Vue中fragment.js使用方法详解

大部分内容源自 jQuery,当然,同时也参考了 component/domify ,如果有兴趣去这翻阅原始的代码,可以到 jQuery 中查找 wrapMap;至于 domify,直接到 github 搜索即可,相关项目类容很少,直接看 index.js 就行了。

createDocumentFragment

如果要在一个节点上一次性插入多个元素怎么办,比如说一次插入 10000 个节点?

最简单粗暴的方式就是:

var parent = document.getElementById('parent');
for(var i = 0; i < 10000; i++) {
 var child = document.createElement('div');
 var text = document.createTextNode('' + i);
 child.appendChild(text);
 parent.appendChild(child);
}

不过众所周知的原因,对 DOM 反复操作会导致页面重绘、回流,效率非常低,而且页面可能会被卡死,这段代码基本是没人用的。

如果分段来进行 DOM 操作呢,这样就能避免卡死页面了,js 忍者秘籍里面提到过可以用 setTimeout 来改进:

var i = 0, max = 10000;
setTimeout(function addNodes() {
 for(var step = i + 500; i < step; i++) {
  var child = document.createElement('div');
  child.appendChild(document.createTextNode('' + i));
  div.appendChild(child);
 }
 if(i < max) {
  setTimeout(addNodes, 0);
 }
}, 0);

当然,更多能想到的方式应该是,在内存中直接操作节点,所有节点都凑在一起之后再跟 DOM 树进行交互,把所有节点都串在一个 div 上,然后再把 div 挂到 DOM 树上:

var parent = document.getElementById('parent');
var div = document.createElement('div');
for(var i = 0; i < 10000; i++) {
 var child = document.createElement('div');
 var text = document.createTextNode('' + i);
 child.appendChild(text);
 div.appendChild(child);
}
parent.appendChild(div);

如上,只跟 DOM 树交互一次,性能方面肯定是大有改善的,不过额外插入了一个 div,如果说不是跟div之类的节点进行交互呢,比如在 table 中插入 th、td?

这时候,createDocumentFragment 就该出马了,翻译过来叫“文档片段”,按MDN的描述:

DocumentFragments 是一些 DOM 节点。它们不是 DOM 树的一部分。通常的使用场景是创建一个文档片段,然后将创建的 DOM 元素插入到文档片段中,最后把文档片段插入到 DOM 树中。在 DOM 树中,文档片段会被替换为它所有的子元素。

因为文档片段存在与内存中,并不在 DOM 树中,所以将子元素插入到文档片段时不会引起页面回流(对元素位置和几何上的计算)。因此,使用文档片段 document fragments 通常会起到优化性能的作用。

简单来说,就是上面一个例子的不需要 div 中转版本,插入的时候,直接用其子元素替换其本身,非常完美。

虽然说,“好用的都不通用”(特别是针对某公司浏览器),不过这个好用的东西,甚至连 IE6 都支持。

具体代码大概就长这样:

var parent = document.getElementById('parent');
var frag = document.createDocumentFragment();
for(var i = 0; i < 10000; i++) {
 var child = document.createElement('div');
 var text = document.createTextNode('' + i);
 child.appendChild(text);
 frag.appendChild(child);
}
parent.appendChild(frag);

具体性能方面的测试,有兴趣的可以把所有代码都跑一遍。

innerHTML

把一长串字符串转换为对应的 DOM 节点,正常而言,首先想到的肯定是 innerHTML。大概流程就是,先创建一个 div 节点,然后 div.innerHTML = str,根据需要把 div 的 children 取出来放到该放的地方去,div 本身给扔了。

如果想单独生成一个 th 节点呢?

试试上面的流程:

var div = document.createElement('div');
div.innerHTML = '<th>xxx</th>';
console.log(div);

实际输出是(chrome 下):

<div>xxx</div>

并没有得到想要的:

<div><th>xxx</th></div>

对于这样的结果是可以理解的,毕竟一个 th 放到 div 里面,怎么看都不对,直接把外围的标签去掉,内容扔到 div 里面也是相当智能的。

不过架不住,有时候就是要获取一个 th 节点。

其实也好办,写全了不就得了:

var node = document.createElement('div');
node.innerHTML = '<table><tbody><tr><th>xxx</th></tr></tbody></table>';
// 把外面的几层皮扒掉就是想要的 th 了
var depth = 3;
while(depth--) {
 node = node.lastChild;
 }
console.log(node.firstChild);

可以看出,结果正是所想要的。

fragment.js

// 需要单独处理的一些特殊节点
var map = {
 legend : [1, '<fieldset>', '</fieldset>'],
 tr : [2, '<table><tbody>', '</tbody></table>'],
 col : [2, '<table><tbody></tbody><colgroup>', '</colgroup></table>'],

 _default : [0, '', '']
};
map.td = map.th = [3, '<table><tbody><tr>', '</tr></tbody></table>'];
map.option = map.optgroup = [1, '<select multiple="multiple">', '</select>'];
map.thead = map.tbody = map.colgroup = map.caption = map.tfoot = [1, '<table>', '</table>']
map.text = map.circle = map.ellipse = map.line = map.path = map.polygon = map.polyline = map.rect = [1, '<svg xmlns="http://www.w3.org/2000/svg" version="1.1">','</svg>'];

var TAG_RE = /<([\w:]+)/;

module.exports = function(templateString) {
 var frag = document.createDocumentFragment(),
  m = TAG_RE.exec(templateString);
 // 单纯字符串的情况
 if(!m) {
  frag.appendChild(document.createTextNode(templateString);
  return frag;
 }

 var tag = m[1],
  wrap = map[tag] || map._default,
  depth = wrap[0],
  prefix = wrap[1],
  suffix = wrap[2],
  node = document.createElement('div');
 // 拼接节点字符串
 node.innerHTML = prefix + templateString.trim() + suffix;
 // 去除外包裹层,只留字符串转化的节点
 while(depth--) node = node.lastChild;
 // 只有一个节点的情况
 if(node.firstChild === node.lastChild) {
  frag.appendChild(node.firstChild);
  return frag;
 }
 // 多个节点,依序添加到 frag
 var child;
 while(child = node.firstChild) {
  frag.appendChild(child);
 }
 return frag;
}

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

赞 (0)

相关推荐

  • 浅析document.createDocumentFragment()与js效率

    document.createDocumentFragment()说白了就是为了节约使用DOM.每次JavaScript对DOM的操作都会改变页面的变现,并重新刷新整个页面,从而消耗了大量的时间.为解决这个问题,可以创建一个文档碎片,把所有的新节点附加其上,然后把文档碎片的内容一次性添加到document中.这是我写的一个简单的测试页面: 复制代码 代码如下: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN&quo

  • 关于javascript document.createDocumentFragment()

    他支持以下DOM2方法: appendChild, cloneNode, hasAttributes, hasChildNodes, insertBefore, normalize, removeChild, replaceChild. 也支持以下DOM2屬性: attributes, childNodes, firstChild, lastChild, localName, namespaceURI, nextSibling, nodeName, nodeType, nodeValue, ow

  • 监控 url fragment变化的js代码

    当然,页面最好不要刷新,但是,拷贝一下浏览器的链接,又希望是下次能定位到你播发的那个视频.方法很简单,改变一下 url 的 fragment 就可以了. 监听fragment 的变化是这类编程的核心.在主流的浏览器(IE firefox)里面 都有一个 onhashchange 的事件监听 fragment 的变化. 但是,他们的行为有些差异.在IE8 以前的 IE版本里面,当 window.location 对象迅速变化的情况下,onhashchange 不会触发,非常奇怪的bug. 下面我写

  • JavaScript Tips 使用DocumentFragment加快DOM渲染速度

    大家在使用JavaScript的时候,DOM操作是最平常不过的了, 随着Web前端技术的发展,我们越来越多的使用JS来操作DOM元素,比如通过ajax请求获取到数据,然后更新页面上的元素,一般情况下,这种操作我们会用类似node.appendChild()这中方式来完成.这个方法是无缓冲的,也就是说我们每次调用appendChild方法的时候,浏览器都会重新渲染页面.当然,使用这种方法也没有什么不行,因为我们在一般情况下都是对少量的DOM节点进行更新,也并不会带来太大的性能问题,但是如果大量的更

  • JavaScript性能优化 创建文档碎片(document.createDocumentFragment)

    在浏览器中,我们一旦把节点添加到document.body(或者其他节点)中,页面就会更新并反映出这个变化,对于少量的更新,一条条循环插入也会运行很好,也是我们常用的方法.代码如下: 复制代码 代码如下: for(var i=0;i<5;i++){ var op = document.createElement("span"); var oText = document.createTextNode(i); op.appendChild(oText); document.body

  • Vue中fragment.js使用方法详解

    大部分内容源自 jQuery,当然,同时也参考了 component/domify ,如果有兴趣去这翻阅原始的代码,可以到 jQuery 中查找 wrapMap:至于 domify,直接到 github 搜索即可,相关项目类容很少,直接看 index.js 就行了. createDocumentFragment 如果要在一个节点上一次性插入多个元素怎么办,比如说一次插入 10000 个节点? 最简单粗暴的方式就是: var parent = document.getElementById('pa

  • Vue 中使用 typescript的方法详解

    什么是typescript typescript 为 javaScript的超集,这意味着它支持所有都JavaScript都语法.它很像JavaScript都强类型版本,除此之外,它还有一些扩展的语法,如interface/module等. typescript 在编译期会去掉类型和特有语法,生成纯粹的JavaScript. Typescript 5年内的热度随时间变化的趋势,整体呈现一个上升的趋势.也说明ts越来越️受大家的关注了. 安装typescript npm install -g ty

  • vue中使用vue-pdf的方法详解

    需求:简单说~~有两个pdf文件需在h5上展示,通过点击按钮切换不同文件的显示 注: 1.vue-pdf默认展示首页,我这里的需求是通过滑动展示所有页面,这里使用的v-for遍历.有多少页就加载了多少个pdf组件. 2.pdf文件存在跨域问题,这个需要后端同学支持. 3.demo上的pdf文件只有一页,测试多页展示,自己改用多页pdf文件即可 <template> <div class="pdf_wrap"> <div class="pdf_li

  • vue项目中main.js使用方法详解

    目录 第一部分:main.js文件解析 第二部分:Vue.use的作用以及什么时候使用 Vue.use是什么?(官方文档) Vue.use()什么时候使用? 补充:关于main.js方便小技巧 总结 第一部分:main.js文件解析 src/main.js是入口文件,主要作用是初始化vue实例并使用需要的插件 在main.js文件中定义了一个vue对象,其中el为实例提供挂载元素 //基础配置 import Vue from 'vue' import App from './App.vue' /

  • Vue中fragment.js使用方法小结

    createDocumentFragment 如果要在一个节点上一次性插入多个元素怎么办,比如说一次插入 10000 个节点? 最简单粗暴的方式就是: var parent = document.getElementById(`'parent'`); for`(`var i = 0; i < 10000; i++) { var child = document.createElement(`'div'`); var text = document.createTextNode(`'' + i);

  • Vue 项目中Echarts 5使用方法详解

    目录 前言 创建项目 基本使用 安装 使用方法 柱状图 动态排序柱状图 前言 Echarts 是一个纯JavaScript的图表库,兼容绝大部分的浏览器,底层依赖轻量级的canvas类库ZRender,提供直观,生动,可交互,可高度个性化定制的数据可视化图表. 创建项目 先使用vue-cli创建一个新的项目,配置按照自己的需要选择,默认的也可 vue create vue_echarts cd vue_echarts npm run serve 基本使用 安装 首先安装echarts npm i

  • vue中使用codemirror的实例详解

    这篇文章在vue里使用codemirror遇到的问题,写的很不错,还有下载的方法,大家可以点击查看. 以下是自己使用过的,做出来的例子: 做出来的效果图: 记住使用之前要npm下载哦 npm install vue-codemirror --save main.js import { codemirror } from 'vue-codemirror' import 'codemirror/lib/codemirror.css' Vue.use(VueCodemirror) 再到组件中使用 im

  • vue中引入mxGraph的步骤详解

    第一步:下载npm包 npm install mxgraph --save 第二步:新建一个index.js文件 文件内容如下 import mx from 'mxgraph'; const mxgraph = mx({ mxImageBasePath: './src/images', mxBasePath: './src' }); // decode bug https://github.com/jgraph/mxgraph/issues/49 window.mxGraph = mxgraph

  • 发布订阅模式在vue中的实际运用实例详解

    订阅发布模式定义了一种一对多的依赖关系,让多个订阅者对象同时监听某一个主题对象.这个主题对象在自身状态变化时,会通知所有订阅者对象,使它们能够自动更新自己的状态. 比如addEventListener 这个api就是个发布订阅模式 如果用过vue的同学,可以把他类比于 watch 下面我们看一个例子 var observe={ fnsObj:{}, // 订阅方法 on:function(key,fn){ if(!observe.fnsObj[key]){ observe.fnsObj[key]

  • 基于Vue中使用节流Lodash throttle详解

    在Vue中使用 Lodash.throttle 来做节流 在Vue中,有时需要对ajax请求提交进行节流操作.这时候,如果页面在请求成功之后会跳转,使用vue指令once或者加载一个loading遮罩禁止点击即可,但如果请求之后不跳转,并且loading不适用时,需要通过其他方式来实现节流,比如通过标识位判断等,这里我们着重说一下如何通过lodash.throttle来实现节流 lodash lodash是一个广受欢迎的js工具库,其中包含了各种各样的工具函数,方便开发时不需要反复造轮子,更关注

随机推荐