动态插入 DOM 元素的最佳方式

假设有一个 DOM 元素,要利用 JavaScript 动态插入到文档中,通常这样写:

document.body.appendChild(elem);

这是最常用的写法,我经常都是这么写的,但同时我也发现有很多不同的写法,比如插入到 <head> 中 ,或插入到第一个 <script> 前面,还有插入到 document.documentElement.firstChild 的。

Paul Irish 提供了一个最佳实践,写法是这样的:

var ref = document.getElementsByTagName('script')[0];
ref.parentNode.insertBefore(yourElem, ref);

可以看出用的是第二种写法。那其他方法有什么缺点呢?

首先说 append 到 <body> 中的方法,大多数情况下,这种方法很有效,但如果是用来写类库,或者组件的话,需要考虑到各种各样的环境。如果代码被放进 <head> 里,那么执行的时候,document.body 的值是 null。于是就出错了。

下一个思路便是插进 <head> 里,问题是有些网页里缺少 <head> 元素,一般来说,浏览器会自动添加一个缺失的 <head>,但在 Opera、Safari 等的一些旧版本里不添加,所以仍会有出错的情况。
阅读全文 »

用 requestAnimationFrame 来实现动画

通常我们实现 JavaScript 动画,用的都是 setTimeoutsetInterval,自己设定一个间隔,利用这两个函数来重复地修改 DOM,产生动画效果。这里面有一个问题,就是间隔究竟设为多少才最合适。太大了动画就不平滑,太小了又会过分消耗计算资源,有时还会丢帧。

理论上说,每一次的 DOM 修改都放在显示器刷新前那一刻进行是最合适的,但是我们利用 JavaScript 还做不到这点,无法准确地知道下一次渲染在什么时刻。一般的显示器刷新频率都设置在 60Hz,刷新间隔便是 1/60 s 约为 17ms。 但也并不是给 setInterval 简单地设置个 17ms 就能解决问题了。requestAnimationFrame 的出现就是为了解决这个的。

语法

 window.requestAnimationFrame( callback ) // 也可省略window 

requestAnimationFrame() 方法接受一个回调函数 callback。调用 requestAnimationFrame() 时,浏览器就会在下一次渲染之前执行 callback,然后渲染。所以对 DOM 的修改就可以放在 callback 里面。另外像 setTimeout 一样,我们要在回调函数中再次调用 requestAnimationFrame(),才能将每一帧动画衔接起来。requestAnimationFrame() 的返回值是一个唯一的 id。

setTimeoutsetInterval 的区别就是,requestAnimationFrame 不能自行设定间隔,一旦调用了,浏览器就会自动在下次渲染前的一刻执行代码,所以这个执行的时机一般是在 17ms 以内。 因为对 DOM 的修改和浏览器渲染的步调做到了一致,所以效率更高,动画会很平滑。用 requestAnimationFrame 的另外一个好处就是,当标签页不活动的时候,动作就会暂停,减少了不必要的内存消耗。

浏览器差异

此方法目前还是草案状态,各浏览器的实现不太一致,IE 从版本 10 开始提供支持,其他浏览器的旧版本需要加对应前缀。Chrome 的方法还支持第二个参数:webkitRequestAnimationFrame( callback, element )element 表示属性发生改变的 DOM 元素,这样渲染会局限在该元素中,提高效率。Firefox 的实现 mozRequestAnimationFrame 会在执行回调时,给 callback 传入一个参数 timestamp,是以毫秒表示的时间,表示下一次渲染的精确时刻。

阅读全文 »

URL 编解码知识

关于 URL 编码知识的笔记:

URL 的结构

一个复杂的 URL 例如 https://bob:bobby@www.lunatech.com:8080/file;p=1?q=2#third,其中的各部分分别为:

名称 数据
协议 https
用户名 bob
密码 bobby
主机地址 www.lunatech.com
端口 8080
路径 /file
路径参数 p=1
查询参数 q=2
片段 third

路径(path)部分以“/”开始,并且用“/”分开各个文件夹。如“/photos/egypt/cairo/first.jpg”包含四个路径片段(path segment):photosegyptcairofirst,jpg。每个路径片段都可以带路径参数(可选,也叫 matrix 参数)。路径参数位于片段末尾,以“;”开头,并用“;”分隔。参数名和数值之间用“=”分开,例如 /file;p=1 表示 file 有一个参数 p=1。这类参数并不常用。

哪些字符需要编码

RFC3986 文档规定,URL 中只允许包含英文字母(a-zA-Z)、数字(0-9)、- _ . ~4个特殊字符以及所有保留字符。

保留字符:URL 可以划分成若干个组件,协议、主机、路径等。有一些字符(: / ? # [ ] @)是用作分隔不同组件的。例如“:”用于分隔协议和主机,“/”用于分隔主机和路径,“?”用于分隔路径和查询参数,等等。还有一些字符(! $ & ( ) * + , ; =)用于在每个组件中起到分隔作用的,如“=”用于表示查询参数中的键值对,“&”符号用于分隔查询多个键值对。当组件中的普通数据包含这些特殊字符时,需要对其进行编码。

RFC3986 中指定了以下字符为保留字符:! * ' ( ) ; : @ & = + $ , / ? # [ ]

阅读全文 »

flight