前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >DOM操作

DOM操作

作者头像
奋飛
发布2019-08-15 16:19:42
8660
发布2019-08-15 16:19:42
举报
文章被收录于专栏:Super 前端Super 前端

版权声明:本文为博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。

本文链接:https://ligang.blog.csdn.net/article/details/71053133

​ 页面上有个空的无序列表节点,用<ul></ul> 表示,通过JavaScript动态往列表中插入 3 个<li>,每个列表项的文本内容是列表项的插入顺序,取值 1, 2, 3;同时绑定click事件,单击依次输出1,2,3。

代码语言:javascript
复制
<ul class="js-container">
    <!-- 动态添加内容 -->
</ul>

动态添加li

代码语言:javascript
复制
var containerDom = document.querySelector('.js-container'),
    itemDom = null;

for(let i = 1; i <= 3; i++) {
    itemDom = document.createElement("li");
    itemDom.innerText = i;
    containerDom.appendChild(itemDom);
}

绑定事件

代码语言:javascript
复制
var containerDom = document.querySelector('.js-container'),
    itemDom = null;

for(let i = 1; i <= 3; i++) {
    itemDom = document.createElement("li");
    itemDom.innerText = i;
    itemDom[i].addEventListener('click', function() {
        alert(i); // alert(this.innerText);
    });
    containerDom.appendChild(itemDom);
}

需要注意: 上述使用let局部作用域(使用闭包同样可以实现)!绑定事件使用addEventListener,而没有使用内联事件onclick。是因为内联事件是作为元素属性保存起来的,这些属性可以被覆盖,所以如果为同一个事件绑定了多个处理程序,那么最后一个处理程序会覆盖之前的。

增大数据量

​ 如果将li的数量改为500,5000甚至更大呢?页面必然会出现卡顿或者直接卡死。

事件代理,减少事件数量

代码语言:javascript
复制
var containerDom = document.querySelector('.js-container'),
    itemDom = null;

for(let i = 1; i <= 500; i++) {
    itemDom = document.createElement("li");
    itemDom.innerText = i;
    containerDom.appendChild(itemDom);
}

// 事件代理
containerDom.addEventListener('click', function(e){
    const target = e.target;
    if (target.tagName === 'LI') {
        alert(target.innerHTML);
    }
});

DocumentFragement可以减少DOM操作

​ 接口表示的是没有父节点的最小的文档对象。它被当做一个轻量版本的 Document 使用,用于存储已排好版的或尚未打理好格式的XML片段。可以使用document.createDocumentFragment方法或者构造函数来创建一个空的 DocumentFragment.

​ DocumentFragement通常用来创建一个文档片段,然后将创建的DOM元素插入到文档片段中,最后把文档片段插入到DOM树中。在DOM树中,文档片段会被替换为它所有的子元素。因为文档片段存在于内存中,并不在DOM树中,所以将子元素插入到文档片段时不会引起页面重绘(reflow)(对元素位置和几何上的计算)。因此,使用文档片段DocumentFragement通常会起到优化性能的作用。

代码语言:javascript
复制
var containerDom = document.querySelector('.js-container'),
    contentFragment = document.createDocumentFragment(),
    itemDom = null;

// 先将li添加到contentFragment,已减少dom操作
for(let i = 1; i <= 500; i++) {
    itemDom = document.createElement("li");
    itemDom.innerText = i;
    contentFragment.appendChild(itemDom);
}
containerDom.appendChild(contentFragment);

// 事件代理
containerDom.addEventListener('click', function(e){
    const target = e.target;
    if (target.tagName === 'LI') {
        alert(target.innerHTML);
    }
});

分批处理,requestAnimationFrame平滑过渡

创建动画时,大家经常会想到使用setTimeoutsetInterval。使用上述方式有这样几个问题:

  • 动画区域或者页面已被隐藏,setTimeoutsetInterval仍被执行;
  • 大多数计算机显示器以60Hz的速率刷新,这基本上意味着每秒重新绘制60次。为了得到最平滑的动画,需要设置最佳间隔是1000ms / 60或约17ms,但这不能覆盖全部浏览器;
  • 延迟毫秒数并不意味着该毫秒后被执行,仅表示其进行排队。如果UI线程很忙,可能会处理用户操作,那么该代码将不会立即执行;

window.requestAnimationFrame(callback) 方法告诉浏览器您希望执行动画,并请求浏览器调用指定的函数在下一次重绘之前更新动画。该方法将在重绘之前调用的回调作为参数。window.cancelAnimationFrame() 来取消这个回调函数。

代码语言:javascript
复制
const containerDom = document.querySelector('.js-container');

const total = 5000,   // 5000个li
    batchSize = 50,   // 每一个批次执行50个
    batchCount = Math.ceil(total / batchSize); // 批次数
let batchDone = 0;  // 已经完成的批处理个数

/**
 * 批次插入li
 */
function appendItems() {
    let contentFragment = document.createDocumentFragment(),
        itemDom = null;
    for(let i = 1; i <= batchSize; i++) {
        itemDom = document.createElement("li");
        itemDom.innerText = (batchDone * batchSize) + i;
        contentFragment.appendChild(itemDom);
    }
    containerDom.appendChild(contentFragment);
    batchDone++;
    // 调用下一批次
    doBatchAppend();
}

/**
 * 平滑插入各个批次
 */
function doBatchAppend() {
    if (batchDone < batchCount) {
        // 无需设置时间
        window.requestAnimationFrame(appendItems);
    }
}

doBatchAppend();

// 绑定事件
containerDom.addEventListener('click', function(e){
    const target = e.target;
    if (target.tagName === 'LI') {
        alert(target.innerHTML);
    }
});

注意: requestAnimationFrame()存在一定的兼容性问题

兼容性
兼容性
代码语言:javascript
复制
(function() {
    if (window.requestAnimationFrame) {
        return;
    } else {
        var lastTime = 0;
        var vendors = ['ms', 'moz', 'webkit', 'o'];
        for(var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) {
            window.requestAnimationFrame = window[vendors[x]+'RequestAnimationFrame'];
            window.cancelAnimationFrame = window[vendors[x]+'CancelAnimationFrame']
                     || window[vendors[x]+'CancelRequestAnimationFrame'];
        }
        // 使用setTimeout模拟实现
        if (!window.requestAnimationFrame){
            window.requestAnimationFrame = function(callback, element) {
                var currTime = new Date().getTime();
                var timeToCall = Math.max(0, 16 - (currTime - lastTime));
                var id = window.setTimeout(function() { 
                  callback(currTime + timeToCall); 
                }, timeToCall);
                lastTime = currTime + timeToCall;
                return id;
            };
            window.cancelAnimationFrame = function(id) {
                clearTimeout(id);
            };
        }
    }
}());

参考地址: http://creativejs.com/resources/requestanimationframe/ https://www.nczonline.net/blog/2011/05/03/better-javascript-animations-with-requestanimationframe/

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2017年05月01日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 动态添加li
  • 绑定事件
  • 增大数据量
    • 事件代理,减少事件数量
      • DocumentFragement可以减少DOM操作
        • 分批处理,requestAnimationFrame平滑过渡
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档