Rosin 是一个 Fiddler 插件,协助开发者进行移动端页面开发调试。
特性
- 可配置的页面匹配规则
- 拦截 console
- 日志内容的存储,展示,过滤
- 脚本运行错误捕获
原理
- 首先在 fiddler 里面配置了匹配规则
- 访问的页面进过 fiddler 之后,匹配规则会生效,如命中,则在返回的内容中注入脚本。
- 脚本重写了 console 的各种方式(也监听了 onerror 事件)
- 将 console 打出的各种消息 push 到消息队列
- 队列达到阈值或者间隔的时间到,就将消息通过 xhr 发送到
http://__rosin__.qq.com
- rosin 插件在 fiddler 中捕获上面的请求(并且隐藏了,所以看不到这个请求),将请求的 body 部分显示到面板上面
- 将 log 存储到本地
D:Program Files (x86)Fiddler2ScriptsRosinLog
1 2 3 4 5 6 7 8 9 10 11 12 |
add: <span class="keyword">function</span>() { <span class="keyword">Array</span>.prototype.push.apply(<span class="keyword">this</span>._queueArr, arguments); <span class="comment">// 定时发送消息</span> clock.start(); <span class="comment">//队列达到阈值就触发上传</span> <span class="keyword">if</span> (<span class="keyword">this</span>._queueArr.length >= THRESHOLD) { <span class="keyword">this</span>._post(<span class="keyword">this</span>._queueArr.splice(<span class="number">0</span>, <span class="keyword">this</span>._queueArr.length)); <span class="keyword">return</span>; } } |
Log 格式:
JSConsole
JSConsole 是一个 JS 命令行调试工具。
如何使用
- 在
http://jsconsole.com/
中输入:listen
创建一个 session(主要是生成一个 GUID) - 在页面中引入脚本
1 2 |
<script src="http://jsconsole.com/remote.js?FAE031CD-74A0-46D3-AE36-757BAB262BEA"></script> |
原理
- 引入的 remote.js 脚本创建一个隐藏的 iframe,Url 指向了
http://jsconsole.com/remote.html
,并且把上面的 GUID 带上 - 重写 console 中的方法,这里的问题是:
如何把消息 push 到 jsconsole.com
? - 页面调用 console 等方法时,实际通过 postMessage 是向 iframe 发送了一条消息。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
log: <span class="keyword">function</span> () { <span class="keyword">var</span> argsObj = stringify(arguments.length == <span class="number">1</span> ? arguments[<span class="number">0</span>] : [].slice.call(arguments, <span class="number">0</span>)); ar response = []; [].<span class="keyword">forEach</span>.call(arguments, <span class="keyword">function</span> (args) { response.push(stringify(args, <span class="keyword">true</span>)); }); <span class="keyword">var</span> msg = JSON.stringify({ response: response, cmd: <span class="string">'remote console.log'</span>, type: msgType }); <span class="keyword">if</span> (remoteWindow) { remoteWindow.postMessage(msg, origin); } <span class="keyword">else</span> { queue.push(msg); } msgType = <span class="string">''</span>; } |
- iframe 中内嵌的页面收到消息后,通过 EventSource 向 server 发送信息内容(类似于 socket)
- 日志显示在 jsconsole.com 上面
什么是 VM?
VM 模块是 NodeJS 里面的核心模块,支撑了 require 方法和 NodeJS 的运行机制,我们有些时候可能也要用到 VM 模板来做一些特殊的事情。
通过 VM,JS 可以被编译后立即执行或者编译保存下来稍后执行(JavaScript code can be compiled and run immediately or compiled, saved, and run later.)
VM 模块包含了三个常用的方法,用于创建独立运行的沙箱体制,如下三个方法
写在前面
因为用 React 就会需要写jsx。
React 会将 jsx 编译成 js。然后 append 到 head 当中。从 fiddler 的请求和 JSXTransformer 源码来看,当在页面使用下面的 html 时候:
1 |
<script type="text/jsx" src="js/react_test.js"></script> |
会发送两次请求 react_test.js 文件,一次是 JSXTransformer 发送的,一次是浏览器识别 script 标签自动发送的。
上面的 react_test.js 里面全是jsx语法,和 javascript 有点像,如:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
var Timer = React.createClass({ getInitialState: function() { return {secondsElapsed: 0}; }, tick: function() { this.setState({secondsElapsed: this.state.secondsElapsed + 1}); }, componentDidMount: function() { this.interval = setInterval(this.tick, 1000); }, componentWillUnmount: function() { clearInterval(this.interval); }, render: function() { return ( <div>Seconds Elapsed: {this.state.secondsElapsed}</div> ); } }); |
这两个伪元素分别表示元素内容的【前】【后】,利用这两个伪元素可以在元素内容的前后添加内容,其实这没有什么前后的概念,如果应用了 absolute 的特性之后,你可以把这些伪元素放在任何位置,有了这两个伪元素,就代表每个元素都有两个助手可供使用,灵活运用它们的话将会得到很多有趣的实现,简化许多实现。
伪元素特性(目前已经遇到的)
- 它不存在于文档中,所以 js 无法操作它
- 它属于主元素本身,有些伪类仅仅是代表元素内容的一部分,譬如:first-letter 代表第一个字母;因此当伪元素被点击的时候触发的是主元素的 click 事件
- 块级元素才能有:before, :after,譬如 img 就不能设置,亦即某些元素是没有:before, :after 的,只要知道一般的块级元素都可以用就行了
注:css3 中,为了与伪类区分,伪元素前应该使用两个冒号,即:hover 伪类,::before 伪元素。当然为了向下兼容,用一个冒号也是可以的,不过建议尽量使用规范的写法。
各种图标
利用这两个伪类,可以实现需要简单的图标,例如搜索的放大镜,叉叉,箭头等等
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
<span class="comment">//视频播放图标</span> .course[data-type=<span class="string">"2"</span>] { .course__cover { &:before, &:after { content: <span class="string">''</span>; display: block; position: absolute; left: <span class="number">5</span>px; bottom: <span class="number">5</span>px; } &:after { <span class="comment">//实现圈圈</span> width: <span class="number">20</span>px; height: <span class="number">20</span>px; border: <span class="number">2</span>px solid white; background: rgba(<span class="number">0</span>, <span class="number">0</span>, <span class="number">0</span>, .<span class="number">6</span>); border-radius: <span class="number">12</span>px; background-clip: padding-box; } &:before { <span class="comment">//实现三角形</span> height: <span class="number">0</span>; width: <span class="number">0</span>; border-left: <span class="number">8</span>px solid white; border-top: <span class="number">5</span>px solid transparent; border-bottom: <span class="number">5</span>px solid transparent; margin-left: <span class="number">9</span>px; margin-bottom: <span class="number">7</span>px; z-index: <span class="number">5</span>; } } } |
上述图标的效果如下图:
扩大可点区域
在 mobile,特别是小屏手机,可点区域一般需要大一点,这样对用户友好一点。
当主元素实在没办法扩大自身的时候,可以利用:before, :after 来实现可点区域的扩大,还记得伪元素的特性之一,伪元素属于主元素,点伪元素就是点击主元素。
1 2 3 4 5 6 7 8 9 10 11 12 |
<span class="comment">//利用这个样式可以把可点区域扩大为40px宽,高度原理一样</span> &:before { content: <span class="string">""</span>; display: block; position: absolute; width: <span class="number">40</span>px; left: <span class="number">50</span>%; margin-left: -<span class="number">20</span>px; top: <span class="number">0</span>; height: <span class="number">50</span>px; <span class="comment">//随便</span> } |
实现效果如下图:
这个算是个综合例子,应用了多种技巧。这是一个收藏按钮,两种状态:已收藏和未收藏,正好符合 checkbox,因此应用了 checkbox,修改了样式给了一个底图。然后下面的文字是:after,利用了动态 label 的技巧(详见 1.4),然后:before 应用了扩大可点区域技巧,使得 40*50 的区域内点击都有效。
实现 label
对于一些静态的文字,说明性的文字,譬如最常见的上图下字单元,完全可以用:after 实现那个文字。
还记得 form 家族的 label 标签吗?它的特性是 label 和 input 的联动,点击 label 元素就等同于点击 input,这个效果和伪元素的特性是一模一样的,用:before 完全可以替代 label。
唯有一点是 label 独有的,就是 label 元素和 input 元素的位置相距较远,这种联动是伪元素无法实现的,毕竟伪元素还是要围绕主元素存在的,远距离 absolute 将会引发灾难的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
.empty__bg { display: inline-block; width: <span class="number">95</span>px; height: <span class="number">92</span>px; background: url(../../img/bg_empty_center@<span class="number">2</span>x.png) no-repeat; background-size: <span class="number">95</span>px <span class="number">92</span>px; position: relative; margin-bottom: <span class="number">16</span>px; <span class="comment">//注意这里需要留好位置放置after元素(它是absolute进去的)</span> &:after { content: <span class="string">"暂无学习计划"</span>; display: block; font-size: <span class="number">14</span>px; line-height: <span class="number">24</span>px; text-align: center; width: <span class="number">100</span>%; color: <span class="comment">#909090;</span> position: absolute; top: <span class="number">100</span>%; left: <span class="number">0</span>; } } |
实现效果如下图:
实现动态信息
如果你认为伪元素只能实现静态 label,那就把 CSS3 想得简单了。
:before, :after 的 content 属性的值除了是静态字符串之外,还有其他的一些特殊值,其中一个是 attr(…),这个特性的作用是用主元素的某个属性的值作为 content 的值,当这个属性的值改变的时候,伪元素的值也会跟着改变,利用这个特性就可以实现动态信息了。
可以有两种动态方案:
- 用 js 动态修改主元素的属性值,这个很直观
- 修改伪元素 content 关联的属性
下面看一个例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
<span class="comment">//html:</span> <span class="comment">//<a class="datepicker__link z-today" href="javascript:void(0)" data-monthstr="04月" data-weekstr="周三" data-k="2015422"><span>22</span></a></span> <span class="comment">//<li class="datepicker__item"><a class="datepicker__link" href="javascript:void(0)" data-monthstr="04月" data-weekstr="周四" data-k="2015423"><span>23</span></a></li></span> <span class="comment">//<a class="datepicker__link z-active" href="javascript:void(0)" data-monthstr="04月" data-weekstr="周五" data-k="2015424"><span>24</span></a></span> <span class="comment">//core css</span> .datepicker__link { &:before { content: attr(data-monthStr); } &.z-active { &:before { content: attr(data-weekStr); } } } |
实现的效果如下图:
这里用到第二种动态方案,日期列表里面,日期上面默认显示月份信息,但是选中态需要显示星期信息。
预先把每个单元用到的月份信息和星期信息放到主元素的 data 属性上面(缓存的思想),选中的时候一般都是要添加一个选中态样式,这时,除了基本的凸显性样式外,同时切换伪元素关联的 data 属性即可轻松地解决这个问题,而不用通过 js 去找到 label 元素,然后修改 text。
小结
伪元素帮助我们选择那些有特殊意义,但是却无法具体定位的 “东西”,它们对这些 “东西” 不做任何限制,它们只是代表这些特殊意义,譬如:first-letter,不限制首字母是哪一个字母,只是代表了首字母元素。
通过伪元素,可以让 CSS 更好的处理一些有特殊意义的元素,这些元素一般很难定位,甚至有些是代表状态的元素,譬如:target。
结合伪元素的特点,利用它们的灵活性,可以为我们提供更多的特性,下面总结一下目前想到的伪元素的优缺点:
优点/用途
- 减少 dom 节点数
- 让 css 帮助解决一部分 js 问题,让问题变得简单
缺点
- 不利于 SEO
- 代码读起来 “可能” 会有疑惑
写在前面
不读文章,只对代码感兴趣可以直接跳转到这里 https://github.com/AlloyTeam/AlloyGameEngine
然后 star 一下,多谢支持:)。
前几天发了篇向 ES6 靠齐的 Class.js,当初 jr 为什么不把父类的实例暴露给子类,其原因还是为了延续原型继承的习惯,子类重写就会覆盖掉父类的方法,父类的方法就会丢,如下面的代码,就堆栈溢出了:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
var Parent = function () { } Parent.prototype.a = function () { } var Child = function () { } Child.prototype = new Parent(); Child.prototype.a = function () { this.a(); } var child = new Child(); child.a(); |
而 jr 的 Class.js 可以让你通过 this._super 访问父类同类方法,修复了原型继承同名无法访问父类的弱点,当然也可以 hack 一下,先赋给变量或者某个属性。如:
前端可选的视频直播协议大致只有两种:
- RTMP(Real Time Messaging Protocol)
- HLS(HTTP Live Streaming)
其中RTMP
是 Adobe 开发的协议,无法在 iPhone 中兼容,故目前兼容最好的就是 HLS 协议了。
HTTP Live Streaming(HLS)是苹果公司实现的基于 HTTP 的流媒体传输协议,可实现流媒体的直播和点播。原理上是将视频流分片成一系列 HTTP 下载文件。所以,HLS 比 RTMP 有较高的延迟。
前端播放 HLS
- Native 支持
- Android 3.0+
- iOS 3.0+
- flash 支持
- Flowplayer(GPL
×
) - GrindPlayer(MIT)
- video-js-swf(Apache License 2.0)
- MediaElement.js(MIT)
- clappr(BSD IE10+
×
)
- Flowplayer(GPL
最后,由于 MediaElement 已经纳入 WordPress 的核心视音频库,以及其良好的兼容性(见下图),所以最后选择使用 MediaElement.js 来实现。
切片准备
可使用 m3u8downloader 下载一个 HLS 源,或者使用 node-m3u 生成 m3u8 索引和 MPEG-TS 切片,下面是我们准备切片:
注意看切片索引文件:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
<span class="comment">#EXTM3U</span> <span class="comment">#EXT-X-TARGETDURATION:11</span> <span class="comment">#EXT-X-VERSION:3</span> <span class="comment">#EXT-X-MEDIA-SEQUENCE:0</span> <span class="comment">#EXT-X-PLAYLIST-TYPE:VOD</span> <span class="comment">#EXTINF:10.133333,</span> fileSequence0.ts <span class="comment">#EXTINF:10.000666,</span> fileSequence1.ts <span class="comment">#EXTINF:10.667334,</span> fileSequence2.ts <span class="comment">#EXTINF:9.686001,</span> fileSequence3.ts <span class="comment">#EXTINF:9.768665,</span> fileSequence4.ts <span class="comment">#EXTINF:10.000000,</span> fileSequence5.ts <span class="comment">#EXT-X-ENDLIST</span> |
其中 #EXT-X-ENDLIST
为切片终止标记,如果没有该标记,浏览器会在文件读取完后再请求索引文件,如果有更新则继续下载新文件,以此达到直播效果。
前端代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
<!DOCTYPE html> <html> <head> <title>player</title> <link rel=<span class="string">"stylesheet"</span> href=<span class="string">"./player/mediaelementplayer.css"</span> /> <style> <span class="comment">/** 隐藏控制条 **/</span> .mejs-controls { display: none !important; } </style> </head> <body> <video width=<span class="string">"640"</span> height=<span class="string">"360"</span> id=<span class="string">"player1"</span>> <source type=<span class="string">"application/x-mpegURL"</span> src=<span class="string">"/m3u8/index.m3u8"</span>> </video> <script src=<span class="string">"http://7.url.cn/edu/jslib/jquery/1.9.1/jquery.min.js"</span>></script> <script src=<span class="string">"./player/mediaelement-and-player.js"</span>></script> <script> <span class="keyword">var</span> player = <span class="keyword">new</span> MediaElementPlayer(<span class="string">'#player1'</span>, { <span class="comment">// 禁止点击暂停</span> clickToPlayPause: <span class="keyword">false</span>, success: <span class="keyword">function</span> (media, ele, player) { <span class="comment">// 初始化后立刻播放</span> player.play(); } }); </script> </body> </html> |
效果
例子源码
写在前面
不读文章,只对代码感兴趣可以直接跳转到这里 https://github.com/AlloyTeam/AlloyGameEngine
然后 star 一下,多谢支持:)。
游戏或者应用中,不是所有的地方都是贴图,Shape 也有很常见的应用场景,如游戏中显示 HP 的血条。大量的 Shape 可以组成矢量图。矢量图的好处是放大不失真,也就是不会变模糊;而位图放大失真,失真的程度要看其平台插值算法的牛 B 程度,但放大效果越好的算法,速度越慢,所以大部分平台会在速度和效果上取个折中。
绘制 Shape 根绘制位图本质不一样,绘制位图可以充分利用 GPU 渲染(当然也可以不用),绘制 Shape 必须经过 CPU 先进行数学计算和图形学相关算法(比如你可以尝试不使用 api,而使用点去绘制贝塞尔曲线、圆形、线条等,你做的所有数学工作,就是计算机做的工作),然后再进行渲染。所以很显然,绘制大量的 Shape 会造成帧率下降。