单页应用现在很流行,特别是移动前端开发方面,用web页面做出来的应用,几乎可以达到java,C++等开发的用程序一样的效果。基于web天生就有跨平台的优势,使得前端开发也越来越受重视了。要想在移动端做出原生应用的效果,单页应用首当其冲,但是呢,单页应用有一个重要的知识点,那就是异步过程太明显,你想,大量的样式操作,事件邦定,都要在dom节点绘制完成之后才能进行。怎样确定我们在操作某个dom节点的时候,它已经在页面上存在了呢。以前呢,我们都是用定时器设一个时间来保证的。例如:
var element = document.createElement(‘svg‘); //大量的文档数据 //..... document.body.appendChild(element); setTimeout(function(){ element.style.background = ‘‘; //其它对于element的操作 },1000);
这样做,通常都不会有问题,特别是在pc上,即便你的延时设的更小一点,也可能看不到问题,但是一旦在手机或平板上,就会发现,如果你设的延时比较小,那可能后面的节点操作会报undefined没有style属性之类的错误。如果设的比较大,就会发现,操作反应变得很迟顿了。有没有一种方式可以在节点绘制好了,就通知我们进行下一步的操作呢?当然是有的,在现代浏览器的一些高级版本上大多都实现了变动事件,再再高级一点的浏览版本,还实现了MutationObserver这个东东。于是呢,我们就可以解决上面的问题了。下面是我写的一个插件:
/** * 当监听的节点内容发生变化时,触发指定的回调 * @param opts { * container:父容器,dom对象或jQuery对象 * content :要加入父容器的内容,字符串或jQuery对象 * position :内容插入父容器的位置,‘first‘ 表示在前加入,默认在末尾 * delay :延时,默认0 * } * @version 1.02 * @author [author] bjtqti * @return {[type]} [description] */ Xut.nextTick = new function() { var DOC = document, MutationObserver = window.MutationObserver||window.WebKitMutationObserver||window.MozMutationObserver; function nextTick(opts,callback) { var container = opts.container, content = opts.content, delay = opts.delay||0, position = opts.position, animatId = ‘T‘+ (Math.random()*10000 << 1), tick = DOC.createElement(‘input‘), observer = null; if (!container || !content) { return; } //检查容器---$(container) 转为dom对象 if(typeof container === ‘object‘ && container.selector !== undefined){ container = container[0]; } if(container.nodeType !== 1){ console.log(‘container must be HTMLLIElement ‘); return; } //标记任务 tick.setAttribute(‘value‘,animatId); //检查内容 if(typeof content ===‘string‘){ var temp = $(content); if(!temp[0]){ //纯文本内容 temp = DOC.createTextNode(content); temp = $(temp); } content = temp; } //组装内容到临时片段 function _createFragment(){ var frag = DOC.createDocumentFragment(), len = content.length; for(var i=0;i<len;i++){ frag.appendChild(content[i]); } return frag; } //将内容加入父容器 function _appendChild(){ //拼接内容 content = _createFragment(); content.appendChild(tick); //判断插入的位置 if(position === ‘first‘){ container.insertBefore(content, container.firstChild); }else{ container.appendChild(content); } //触发变动事件 tick.setAttribute(‘value‘,animatId); } //完成任务后处理&Event function _finishTask(event) { if(event.target.value === animatId){ container.removeEventListener(‘DOMNodeRemoved‘,_finishTask,false); callback(); } } //完成任务后处理&Observer function _completeTask() { container.removeChild(tick); callback(); } if(MutationObserver){ observer = new MutationObserver(function(mutations) { mutations.forEach(function(record) { if(record.oldValue === animatId){ _completeTask(); observer = null; } }); }); //设置要监听的属性 observer.observe(tick, { attributes: true, //childList: true, attributeOldValue :true, attributeFilter:["value"]//只监听value属性,提高性能 }); _appendChild(); }else{ //检测是否支持DOM变动事件 if(DOC.implementation.hasFeature("MutationEvents","2.0")){ container.addEventListener(‘DOMNodeRemoved‘,_finishTask,false); _appendChild(); container.removeChild(tick); }else{ //歉容Android2.xx处理 _appendChild(); setTimeout(function () { _completeTask(); }, delay); } } } return nextTick; }
都是项目中实践过的功能。如果有用就直接拿走吧。关于这些高级事件的解释,在博客园已有前辈写的很详细了,有想法深入了解的,就要靠自己百度或谷歌了。
高级前端开发不可或缺的知识
时间: 2024-11-09 00:57:34