在我写完《【版权所有】唐霜 www.tangshuang.netVirtual DOM原理浅易详解【本文首发于唐霜的博客】》之后,我打算把Virtual DOM的未经授权,禁止复制转载。【版权所有】唐霜 www.tangshuang.net体系拆解开。其中非常重要的一点,是我打算【未经授权禁止转载】【作者:唐霜】做一个HTML的解析器,在通过fetch转载请注明出处:www.tangshuang.net本文作者:唐霜,转载请注明出处。抓取到某个网页之后,可以通过这个解析器,原创内容,盗版必究。【转载请注明来源】快速得到自己想要的数据。而这一部分,是V原创内容,盗版必究。【访问 www.tangshuang.net 获取更多精彩内容】irtual DOM整个知识体系的一部分【原创内容,转载请注明出处】【关注微信公众号:wwwtangshuangnet】,即“DOM树抽象成一个js对象”这个部著作权归作者所有,禁止商业用途转载。著作权归作者所有,禁止商业用途转载。分。于是,我希望通过本文,详细阐述我是怎未经授权,禁止复制转载。本文版权归作者所有,未经授权不得转载。么创建自己的这个抽象js对象。
本文作者:唐霜,转载请注明出处。本文作者:唐霜,转载请注明出处。【版权所有】唐霜 www.tangshuang.net未经授权,禁止复制转载。Virtual Node的结构本文版权归作者所有,未经授权不得转载。
【版权所有】唐霜 www.tangshuang.net本文版权归作者所有,未经授权不得转载。转载请注明出处:www.tangshuang.net【未经授权禁止转载】Virtual DOM从某种意义上讲,是本文版权归作者所有,未经授权不得转载。本文作者:唐霜,转载请注明出处。一个tree,tree的节点就是我所指的【本文受版权保护】原创内容,盗版必究。Virtual Node。那么一个Vir【原创内容,转载请注明出处】著作权归作者所有,禁止商业用途转载。tual Node作为一个js对象,应该转载请注明出处:www.tangshuang.net著作权归作者所有,禁止商业用途转载。拥有哪些属性呢?
著作权归作者所有,禁止商业用途转载。转载请注明出处:www.tangshuang.net本文版权归作者所有,未经授权不得转载。{
name: 'div', // 标签名称
id: 'header', // 标签id,默认undefined
class: ['float-right', 'font-big'], // 类数组,默认[]
attrs: { // 从html字符串中解析出来的所有标签属性字符串
id: 'header',
class: 'float-right font-big',
...
},
parent: ..., // 父节点的引用,如果没有父节点就是null
children: [...], // 子节点引用列表,如果没有子节点就是[]
text: 'My BLOG', // 文本节点
events: { // 事件绑定
click(e) { ... },
},
}
我本来想用tagName作为标签名属性,【访问 www.tangshuang.net 获取更多精彩内容】转载请注明出处:www.tangshuang.net但是为了简洁,直接用name。paren未经授权,禁止复制转载。【本文受版权保护】t只会有一个,而children会有多个【关注微信公众号:wwwtangshuangnet】【转载请注明来源】。events只会在通过VNode还原为本文作者:唐霜,转载请注明出处。【版权所有,侵权必究】DOM Node的时候使用到,从HTML【本文首发于唐霜的博客】【原创内容,转载请注明出处】字符串解析到VNode的时候,是不会有的【本文首发于唐霜的博客】原创内容,盗版必究。。
原创内容,盗版必究。【本文首发于唐霜的博客】【版权所有】唐霜 www.tangshuang.netHTMLStringParser的实现【原创不易,请尊重版权】
本文版权归作者所有,未经授权不得转载。本文作者:唐霜,转载请注明出处。转载请注明出处:www.tangshuang.net【关注微信公众号:wwwtangshuangnet】正如文章开头的需求,我希望解析抓取到的H未经授权,禁止复制转载。【本文首发于唐霜的博客】TML string,快速找到自己想要的转载请注明出处:www.tangshuang.net【版权所有】唐霜 www.tangshuang.net节点数据。有人说,使用jquery不就好转载请注明出处:www.tangshuang.net【版权所有,侵权必究】了吗?也有人说,就算在node中我们也有【访问 www.tangshuang.net 获取更多精彩内容】本文作者:唐霜,转载请注明出处。cheerio啊。之所以我想自己实现,是【关注微信公众号:wwwtangshuangnet】【本文受版权保护】为了:1.用最少的代码满足快速获取的需求原创内容,盗版必究。本文版权归作者所有,未经授权不得转载。,2.使用我自己定义的VNode结构。
著作权归作者所有,禁止商业用途转载。【本文首发于唐霜的博客】原创内容,盗版必究。【版权所有】唐霜 www.tangshuang.net我们希望这样来使用这个工具:【版权所有,侵权必究】
【未经授权禁止转载】【未经授权禁止转载】未经授权,禁止复制转载。【转载请注明来源】原创内容,盗版必究。let parser = new HTMLStringParser(htmlstring)
let vnode = parser.getElementById('my-test') // 得到一个VNode
let text = vnode.text
let vnodes = vnode.getElementsByClassName('my-class') // 得到一组VNode
这种使用非常爽。比如说,你通过fetch本文作者:唐霜,转载请注明出处。未经授权,禁止复制转载。得到了一个页面的html源码,想找到这个【转载请注明来源】转载请注明出处:www.tangshuang.net页面中的固定位置的title和link,【转载请注明来源】本文作者:唐霜,转载请注明出处。那就非常容易(搞采集的小伙伴请当做什么都【本文受版权保护】著作权归作者所有,禁止商业用途转载。没看到)。
本文版权归作者所有,未经授权不得转载。【本文受版权保护】【原创不易,请尊重版权】著作权归作者所有,禁止商业用途转载。本文作者:唐霜,转载请注明出处。有了需求之后,我们就开始撸代码。著作权归作者所有,禁止商业用途转载。
【原创不易,请尊重版权】原创内容,盗版必究。【转载请注明来源】htmlparser2【版权所有,侵权必究】
【原创不易,请尊重版权】【转载请注明来源】【访问 www.tangshuang.net 获取更多精彩内容】未经授权,禁止复制转载。【版权所有】唐霜 www.tangshuang.net大神Felix开发了htmlparser【版权所有】唐霜 www.tangshuang.net著作权归作者所有,禁止商业用途转载。2,看这名字,显然还有一个htmlpar原创内容,盗版必究。【本文首发于唐霜的博客】ser,htmlparser2是它的pl本文作者:唐霜,转载请注明出处。【版权所有,侵权必究】us版。但是包括cheerio在内的很多原创内容,盗版必究。【版权所有】唐霜 www.tangshuang.net第三方解析器都是采用了htmlparse原创内容,盗版必究。【关注微信公众号:wwwtangshuangnet】r2,因为它确实好用。
本文版权归作者所有,未经授权不得转载。原创内容,盗版必究。著作权归作者所有,禁止商业用途转载。【原创不易,请尊重版权】用htmlpareser2编程的思想,是【本文首发于唐霜的博客】【本文首发于唐霜的博客】注重“过程”。不像我们预期的,输入字符串【转载请注明来源】【本文受版权保护】得到结果,它更重视的是,把字符串输入之后本文作者:唐霜,转载请注明出处。未经授权,禁止复制转载。,解析器去爬,爬的过程中会对字符串进行解【作者:唐霜】原创内容,盗版必究。释,html标签有非常明显的特点,就是有著作权归作者所有,禁止商业用途转载。本文版权归作者所有,未经授权不得转载。闭合标签,因此,htmlparser2的【本文首发于唐霜的博客】【原创不易,请尊重版权】重要特征就是,有onopentag和on【作者:唐霜】【原创内容,转载请注明出处】closetag这两个事件。
【未经授权禁止转载】【关注微信公众号:wwwtangshuangnet】转载请注明出处:www.tangshuang.net但是,对于htmlparser2来说,它【原创内容,转载请注明出处】本文版权归作者所有,未经授权不得转载。并不关心html标签的父子关系,它只关心本文作者:唐霜,转载请注明出处。著作权归作者所有,禁止商业用途转载。标签的开合,因此,对于我而言,要做的,是著作权归作者所有,禁止商业用途转载。【转载请注明来源】在htmlparser2的过程中,去记录【本文受版权保护】【访问 www.tangshuang.net 获取更多精彩内容】标签的父子关系,并最终构建自己的VNod【本文首发于唐霜的博客】原创内容,盗版必究。e。下面就是我的实现代码:
本文版权归作者所有,未经授权不得转载。本文作者:唐霜,转载请注明出处。【转载请注明来源】let elements = []let recordtree = []let parser = new Parser({
onopentag(name, attrs) {
let parent = recordtree.length ? recordtree[recordtree.length - 1] : undefined
let vnode = {
name: name,
id: attrs.id,
class: attrs.class ? attrs.class.split(' ') : [],
attrs: attrs,
parent,
children: [],
text: undefined,
}
if (parent) {
parent.children.push(vnode)
}
recordtree.push(vnode)
elements.push(vnode)
},
ontext(text) {
let vnode = recordtree[recordtree.length - 1]
if (vnode) {
vnode.text = text.trim()
}
},
onclosetag(name) {
recordtree.pop()
}
})
parser.parseChunk(htmlstring)
parser.done()
借助了两个变量,一个是elements,本文作者:唐霜,转载请注明出处。原创内容,盗版必究。存储了所有的VNode,没有父子关系,按未经授权,禁止复制转载。原创内容,盗版必究。标签打开顺序,依次记录。另一个是reco【作者:唐霜】【未经授权禁止转载】rdtree,用来作为保存节点层级关系的【原创不易,请尊重版权】【未经授权禁止转载】临时变量,它的最后一个元素,其实就是当前本文作者:唐霜,转载请注明出处。【转载请注明来源】正在处理的标签对应的vnode,而前一个【版权所有,侵权必究】【本文受版权保护】标签,就是它的父级标签对应的vnode。
本文作者:唐霜,转载请注明出处。【访问 www.tangshuang.net 获取更多精彩内容】【原创不易,请尊重版权】如此简单的一小段代码,就让我们拥有了所有本文版权归作者所有,未经授权不得转载。未经授权,禁止复制转载。html string的所有节点的VNo【本文受版权保护】【版权所有】唐霜 www.tangshuang.netde。我们可以通过elements变量获【关注微信公众号:wwwtangshuangnet】本文版权归作者所有,未经授权不得转载。取任意一个。
【版权所有】唐霜 www.tangshuang.net本文作者:唐霜,转载请注明出处。
因为javascript的object本文作者:唐霜,转载请注明出处。【本文受版权保护】是引用型数据,因此处理parent和ch转载请注明出处:www.tangshuang.net本文作者:唐霜,转载请注明出处。ildren简直不能再方便了。
节点选择器方法未经授权,禁止复制转载。
本文作者:唐霜,转载请注明出处。著作权归作者所有,禁止商业用途转载。【原创内容,转载请注明出处】【本文受版权保护】【原创不易,请尊重版权】DOM获取节点的方法主要是getElem原创内容,盗版必究。【版权所有】唐霜 www.tangshuang.netent(a)By系列,得到一个节点,最坏著作权归作者所有,禁止商业用途转载。【关注微信公众号:wwwtangshuangnet】的打算是要遍历一颗树,这实在太昂贵了。但转载请注明出处:www.tangshuang.net【作者:唐霜】是,我们现在有了elements这个产量本文作者:唐霜,转载请注明出处。转载请注明出处:www.tangshuang.net,它是一个包含了所有节点信息的数组,一个本文版权归作者所有,未经授权不得转载。【版权所有】唐霜 www.tangshuang.nethtml标签节点就是一个元素,要找到一个【本文受版权保护】【未经授权禁止转载】元素实在是太容易了,只要使用js原生的数【原创不易,请尊重版权】未经授权,禁止复制转载。组操作方法就可以了。比如我们要找到所有包【版权所有,侵权必究】转载请注明出处:www.tangshuang.net含mytest样式类的元素,只需要
本文版权归作者所有,未经授权不得转载。未经授权,禁止复制转载。【本文受版权保护】【版权所有】唐霜 www.tangshuang.netelements.filter(item => item.class.contains('mytest'))
多么简单的操作。当然,我们还可以对算法进原创内容,盗版必究。未经授权,禁止复制转载。行优化,我们查找一个元素,无非按id或标【关注微信公众号:wwwtangshuangnet】本文版权归作者所有,未经授权不得转载。签名或class或attribute查找未经授权,禁止复制转载。本文作者:唐霜,转载请注明出处。,我们完全可以事先按照这四个进行分类,引转载请注明出处:www.tangshuang.net本文版权归作者所有,未经授权不得转载。用型数据又可以帮大忙,按其中一类查找时,本文版权归作者所有,未经授权不得转载。转载请注明出处:www.tangshuang.net就只遍历一个子集。
【版权所有,侵权必究】著作权归作者所有,禁止商业用途转载。著作权归作者所有,禁止商业用途转载。【版权所有,侵权必究】【转载请注明来源】基于这样的设计,想怎么挑选就怎么挑选,可著作权归作者所有,禁止商业用途转载。【版权所有,侵权必究】以挑选出同时具备myclass1和myc【版权所有】唐霜 www.tangshuang.net【转载请注明来源】lass2的元素。但是为了保持和DOM操【未经授权禁止转载】著作权归作者所有,禁止商业用途转载。作的相似性,我实现了如下方法:
【版权所有】唐霜 www.tangshuang.net转载请注明出处:www.tangshuang.net【版权所有,侵权必究】function getElementById(id) {
return elements.filter(item => item.id === id)[0]}function getElementsByClassName(className) {
return elements.filter(item => item.class.indexOf(className) > -1)}function getElementsByTagName(tagName) {
return elements.filter(item => item.name === tagName)}function querySelectorAll(selector) {
let type = selector.substring(0, 1)
let formula = selector.substring(1)
switch (type) {
case '#':
return elements.filter(item => item.id === formula)
break
case '.':
return getElementsByClassName(formula)
break
default:
return getElementsByTagName(selector)
}
}
function querySelector(selector) {
return querySelectorAll(selector)[0]
}
另外,我还是实现一个简单的通过属性来获取【版权所有】唐霜 www.tangshuang.net本文版权归作者所有,未经授权不得转载。元素的方法:
未经授权,禁止复制转载。【版权所有,侵权必究】未经授权,禁止复制转载。function getElementsByAttribute(attrName, attrValue) {
return elements.filter(item => item.attrs[attrName] && item.attrs[attrName] === attrValue)
}
因为把所有元素扁平的存在elements【原创不易,请尊重版权】【访问 www.tangshuang.net 获取更多精彩内容】里,这些方法的实现都变得超级简单。
【原创内容,转载请注明出处】【本文受版权保护】【原创不易,请尊重版权】本文作者:唐霜,转载请注明出处。【版权所有】唐霜 www.tangshuang.netVNode原型继承著作权归作者所有,禁止商业用途转载。
本文作者:唐霜,转载请注明出处。著作权归作者所有,禁止商业用途转载。未经授权,禁止复制转载。对于一个VNode而言,除了上述我们给出本文版权归作者所有,未经授权不得转载。原创内容,盗版必究。的那些属性,我们也希望这个VNode拥有【访问 www.tangshuang.net 获取更多精彩内容】【版权所有,侵权必究】上面的这些获取方法,我们可以这样用:
转载请注明出处:www.tangshuang.net【版权所有,侵权必究】著作权归作者所有,禁止商业用途转载。本文作者:唐霜,转载请注明出处。let vnode = parser.getElementById('my-test')
let codes = vnode.getElementsByTagName('code')
也就是说,可以通过被选中的VNode来获本文版权归作者所有,未经授权不得转载。转载请注明出处:www.tangshuang.net取它的子元素里面的对应的元素。这个实现起【访问 www.tangshuang.net 获取更多精彩内容】转载请注明出处:www.tangshuang.net来并不容易,因为你需要对所有的VNode本文版权归作者所有,未经授权不得转载。【未经授权禁止转载】进行方法设置,而且明显,这些方法和par【本文首发于唐霜的博客】著作权归作者所有,禁止商业用途转载。ser本身的方法是一致的,不应该重写。所未经授权,禁止复制转载。未经授权,禁止复制转载。以,我想到了使用原型链,这一js中最突出【本文首发于唐霜的博客】【本文受版权保护】的特质。
未经授权,禁止复制转载。【本文首发于唐霜的博客】
首先,我们创建一个原型:【原创内容,转载请注明出处】
let VNodePrototype = {
parent: null,
children: [],
getElementById(id) {
getElementById.call(this, id)
},
// ...
}
这里之所以要用.call(this..是【原创内容,转载请注明出处】【关注微信公众号:wwwtangshuangnet】因为我们需要在一个单独的VNode中重新【作者:唐霜】【原创内容,转载请注明出处】去考虑使用新的elements,因为当你【原创内容,转载请注明出处】【访问 www.tangshuang.net 获取更多精彩内容】把getElementById作用在一个【原创不易,请尊重版权】转载请注明出处:www.tangshuang.netVNode的时候,你是希望从它内部的元素【原创不易,请尊重版权】著作权归作者所有,禁止商业用途转载。中去获取,而不是从顶层的elements【版权所有】唐霜 www.tangshuang.net原创内容,盗版必究。中获取。我们后文会有完整的源码链接,你应本文版权归作者所有,未经授权不得转载。【未经授权禁止转载】该阅读完整的源码,找到这个位置进行阅读。
【版权所有】唐霜 www.tangshuang.net【关注微信公众号:wwwtangshuangnet】【版权所有】唐霜 www.tangshuang.net本文作者:唐霜,转载请注明出处。那么如何把它的子元素都拿到呢?要知道虽然著作权归作者所有,禁止商业用途转载。【作者:唐霜】它有个children属性,但是这些元素【访问 www.tangshuang.net 获取更多精彩内容】原创内容,盗版必究。仅仅是它的垂直一层的子元素,它还有孙元素【访问 www.tangshuang.net 获取更多精彩内容】未经授权,禁止复制转载。,以及更低层的元素,索性,我们有递归,我【版权所有,侵权必究】本文版权归作者所有,未经授权不得转载。们写一个递归来获取一个VNode所包含的【原创不易,请尊重版权】著作权归作者所有,禁止商业用途转载。所有节点:
本文版权归作者所有,未经授权不得转载。【本文首发于唐霜的博客】【原创不易,请尊重版权】转载请注明出处:www.tangshuang.net本文版权归作者所有,未经授权不得转载。function getVNodeElements(vnode) {
let results = []
vnode.children.forEach(item => {
results.push(item)
if (item.children.length) {
results = results.concat(getVNodeElements(item))
}
})
return results
}
这样就可以获取包含在这个VNode内的所【版权所有,侵权必究】【转载请注明来源】有元素了。
【作者:唐霜】【作者:唐霜】原创内容,盗版必究。有了原型之后,我们就可以通过原型继承的方【转载请注明来源】著作权归作者所有,禁止商业用途转载。式,创建我们的VNode,使我们的每一个【本文受版权保护】未经授权,禁止复制转载。VNode都具备上面这些基础方法:
【本文首发于唐霜的博客】【未经授权禁止转载】【转载请注明来源】本文版权归作者所有,未经授权不得转载。本文版权归作者所有,未经授权不得转载。function createVNode(name, attrs) {
let obj = Object.create(VNodePrototype)
obj.name = name
obj.attrs = attrs
obj.id = attrs.id
obj.class = attrs.class ? attrs.class.split(' ') : []
return obj
}
所以,当我们在构建一个VNode的时候,本文版权归作者所有,未经授权不得转载。【访问 www.tangshuang.net 获取更多精彩内容】其实只需要按照我们设想的结构,把对应的属本文版权归作者所有,未经授权不得转载。未经授权,禁止复制转载。性加上去即可。
转载请注明出处:www.tangshuang.net【未经授权禁止转载】【原创不易,请尊重版权】封装为Class著作权归作者所有,禁止商业用途转载。
【版权所有】唐霜 www.tangshuang.net【版权所有】唐霜 www.tangshuang.net【关注微信公众号:wwwtangshuangnet】转载请注明出处:www.tangshuang.net转载请注明出处:www.tangshuang.netES6的Class非常方便的让我们可以e【版权所有,侵权必究】【未经授权禁止转载】xtends,因此,是封装一个解析器的最【原创不易,请尊重版权】【作者:唐霜】佳选择。我们把上面提到的所有函数或方法都本文版权归作者所有,未经授权不得转载。【本文首发于唐霜的博客】提炼到这个类中,把elements当做它【本文首发于唐霜的博客】【原创不易,请尊重版权】的一个隐私的属性,在不同的方法中可以共享著作权归作者所有,禁止商业用途转载。著作权归作者所有,禁止商业用途转载。,而原型则作为static属性,这样可以【作者:唐霜】原创内容,盗版必究。更省内存。
未经授权,禁止复制转载。本文作者:唐霜,转载请注明出处。原创内容,盗版必究。转载请注明出处:www.tangshuang.net转载请注明出处:www.tangshuang.net你可以在【访问 www.tangshuang.net 获取更多精彩内容】我的GitHub上阅读源码【访问 www.tangshuang.net 获取更多精彩内容】,并且按照README进行使用。【本文受版权保护】
原创内容,盗版必究。未经授权,禁止复制转载。【原创不易,请尊重版权】本文作者:唐霜,转载请注明出处。【转载请注明来源】HTMLStringParser的使用【版权所有,侵权必究】
【原创内容,转载请注明出处】【本文首发于唐霜的博客】【未经授权禁止转载】因为封装为Class,所以使用起来也超级【关注微信公众号:wwwtangshuangnet】【版权所有,侵权必究】方便,你只需要按照我们前面的想法去使用即本文作者:唐霜,转载请注明出处。【访问 www.tangshuang.net 获取更多精彩内容】可。
【未经授权禁止转载】【版权所有】唐霜 www.tangshuang.net原创内容,盗版必究。【原创内容,转载请注明出处】import HTMLStringParser from './HTMLStringParser'
let html = '...'
let parser = new HTMLStringParser(html)
let rootNodes = parser.getRoots()
let header = parser.getElementById('header')
let logo = header.getElementById('logo')
console.log(JSON.stringify(rootNodes[0]))
所有的API都按照我们的设计实现了。转载请注明出处:www.tangshuang.net
【原创不易,请尊重版权】【未经授权禁止转载】【原创不易,请尊重版权】本文版权归作者所有,未经授权不得转载。本文作者:唐霜,转载请注明出处。renderToHTMLString【本文受版权保护】
【本文受版权保护】转载请注明出处:www.tangshuang.net本文版权归作者所有,未经授权不得转载。【本文首发于唐霜的博客】【关注微信公众号:wwwtangshuangnet】既然我们定义了自己的VNode,那么,我【原创内容,转载请注明出处】未经授权,禁止复制转载。们就可以写一个方法,将我们的Virtua【访问 www.tangshuang.net 获取更多精彩内容】未经授权,禁止复制转载。l DOM反转为html字符串。对于反转未经授权,禁止复制转载。【本文受版权保护】字符串而言,其实我们只需要一个VNode【原创内容,转载请注明出处】【关注微信公众号:wwwtangshuangnet】的name, attrs, childr【原创不易,请尊重版权】本文作者:唐霜,转载请注明出处。en属性即可,其他属性都没有用。
未经授权,禁止复制转载。转载请注明出处:www.tangshuang.net【原创不易,请尊重版权】【版权所有,侵权必究】【本文受版权保护】function renderToHTMLString(json) {
let html = ''
// if it is an Array, it means there are several nodes on the top level
if (Array.isArray(json)) {
json.forEach(node => {
html += renderToHTMLString(node)
})
return html
}
// if it is an Object
html += createNode(json)
return html
}
function createNode(node) {
let name = node.name
let html = `<${name}`
let voidElements = ['br', 'hr', 'img', 'input', 'link', 'meta', 'area', 'base', 'col', 'command', 'embed', 'keygen', 'param', 'source', 'track', 'wbr']
let attrs = node.attrs
let keys = Object.keys(attrs)
if (keys && keys.length) {
keys.forEach(key => {
let value = attrs[key]
if (value === '' || value === true) {
html += ` ${key}`
}
else {
html += ` ${key}="${value}"`
}
})
}
if (voidElements.indexOf(name) > -1) {
html += ' />'
return html
}
html += '>'
if (node.text) {
html += node.text + `</${name}>`
return html
}
if (node.children && node.children.length) {
html += renderToHTMLString(node.children)
}
html += `</${name}>`
return html
}
你可以看到,我们的参数是json,这也就【作者:唐霜】【原创内容,转载请注明出处】是说,实际上,我们可以利用这个方法来实现【关注微信公众号:wwwtangshuangnet】未经授权,禁止复制转载。xml的解析和转换。考虑到一些html标【转载请注明来源】【版权所有,侵权必究】签是没有闭合标签的,所以实际上我们最好还【本文首发于唐霜的博客】【原创不易,请尊重版权】是用它来做html的处理。
【版权所有】唐霜 www.tangshuang.net【本文受版权保护】【关注微信公众号:wwwtangshuangnet】【关注微信公众号:wwwtangshuangnet】【作者:唐霜】处理事件绑定【本文受版权保护】
本文版权归作者所有,未经授权不得转载。【访问 www.tangshuang.net 获取更多精彩内容】转载请注明出处:www.tangshuang.net【转载请注明来源】【本文首发于唐霜的博客】最后一件事是,我们在还原Virtual 本文作者:唐霜,转载请注明出处。未经授权,禁止复制转载。DOM为真实DOM的时候,如何处理事件绑【作者:唐霜】本文版权归作者所有,未经授权不得转载。定的问题?在文章第一部分VNode的结构【原创内容,转载请注明出处】著作权归作者所有,禁止商业用途转载。中,我们给出了events属性,那么如何本文作者:唐霜,转载请注明出处。原创内容,盗版必究。实现事件绑定呢?
本文作者:唐霜,转载请注明出处。【未经授权禁止转载】原创内容,盗版必究。实际上,与把Virtual DOM还原为原创内容,盗版必究。【关注微信公众号:wwwtangshuangnet】HTML字符串而言,还原为DOM更加简单【转载请注明来源】【作者:唐霜】:
本文版权归作者所有,未经授权不得转载。【版权所有】唐霜 www.tangshuang.net【本文受版权保护】function createElement(node) {
let name = node.name
let el = document.createElement(name)
let attrs = node.attrs
let events = node.events
let attrKeys = attrs ? Object.keys(attrs) : []
if (attrKeys && attrKeys.length) {
attrKeys.forEach(key => {
let value = attrs[key]
el.setAttribute(key, value)
})
}
let eventKeys = events ? Object.keys(events) : []
if (eventKeys && eventKeys.length) {
eventKeys.forEach(key => {
let callback = events[key]
el.addEventListener(key, callback, false)
})
}
if (node.text) {
el.innerText = node.text
return el
}
if (node.children && node.children.length) {
node.children.forEach(child => {
let childEl = createElement(child)
el.appendChild(childEl)
})
}
return el
}
之所以简单,是因为我们有appendCh未经授权,禁止复制转载。【未经授权禁止转载】ild方法,这个方法避免了我们想尽一切递未经授权,禁止复制转载。【未经授权禁止转载】归办法去构造字符串。看上面的红色字体部分原创内容,盗版必究。著作权归作者所有,禁止商业用途转载。,使用addEventListener绑【作者:唐霜】【作者:唐霜】定事件回调函数,简直易如反掌。
转载请注明出处:www.tangshuang.net本文版权归作者所有,未经授权不得转载。本文作者:唐霜,转载请注明出处。本文作者:唐霜,转载请注明出处。小结【本文首发于唐霜的博客】
原创内容,盗版必究。转载请注明出处:www.tangshuang.net【转载请注明来源】原创内容,盗版必究。【转载请注明来源】这篇文章之所以还有一个副标题指出“Vir原创内容,盗版必究。【原创不易,请尊重版权】tual DOM之前”,是因为我们并没有【关注微信公众号:wwwtangshuangnet】【本文首发于唐霜的博客】完整的去实现一个Virtual DOM机原创内容,盗版必究。【访问 www.tangshuang.net 获取更多精彩内容】制,相反,我们是实现了从DOM到Virt本文版权归作者所有,未经授权不得转载。本文作者:唐霜,转载请注明出处。ual DOM的过程,虽然我们写了cre【转载请注明来源】本文版权归作者所有,未经授权不得转载。ateElement方法,把Virtua著作权归作者所有,禁止商业用途转载。本文版权归作者所有,未经授权不得转载。l DOM还原为真实的DOM,但是这明显【作者:唐霜】【原创内容,转载请注明出处】是不够的。本文的核心,是在利用htmlp【版权所有,侵权必究】未经授权,禁止复制转载。arser2实现一个html到js对象的【原创不易,请尊重版权】【未经授权禁止转载】过程,希望你能从中获得一些自己想要的东西【版权所有】唐霜 www.tangshuang.net【本文受版权保护】。
【原创不易,请尊重版权】本文版权归作者所有,未经授权不得转载。【转载请注明来源】未经授权,禁止复制转载。2017-09-13 7702 Vritual DOM



[…] 写完《HTMLStringParser:自己撸一个Virtual DOM之前》之后,我第一时间整理代码,把文章转载到掘金上,满足作为宅逼程序猿的虚荣感。但写完HTMLStringPareser之后,我并不满足,既然都已经到了吧html转换为对应的js对象解构了,而且连createElement都写了,为何不更进一步,把整个Virtual DOM也给实现了呢?于是开始手撸。这一下,把自己给摔进坑里,在实现diff的时候,几乎陷入了绝境。最后,在无法实现的前提先,做了妥协,最后才终于撸完了整个Virtual DOM,代码在这里,你可以自己慢慢拍砖。 […]