VUE将虚拟DOM渲染成真实DOM-----渲染器
我们知道我们的虚拟DOM是通过render函数渲染成真实DOM的,但是render函数又是怎么实现的呢?他的原理是什么呢?接下来我们一起来看看渲染器的实现原理。一、最简单的rander函数function Render(obj, root) {const el = document.createElement(obj.tag)if (typeof obj.children === 'string'
我们知道我们的虚拟DOM是通过render函数渲染成真实DOM的,但是render函数又是怎么实现的呢?他的原理是什么呢?接下来我们一起来看看渲染器的实现原理。
一、最简单的rander函数
function Render(obj, root) {
const el = document.createElement(obj.tag)
if (typeof obj.children === 'string') {
const text = document.createTextNode(obj.children)
el.appendChild(text)
} else if (obj.children) {
// 递归
obj.children.forEach((child) => Render(child, el));
}
root.appendChild(el)
}
const obj = {
tag: 'div',
children: [
{ tag: 'span', children: 'hellow world' },
{ tag: 'div', children: 'hellow world1' }
]
}
Render(obj, document.body)
很明显我们定义的obj对象 就是一组vnode,我们将其传入Render函数中,他就会将对应数据进行挂载。通过document.createElement(obj.tag)将其转为真实DOM,这样看来,render其实是很简单的事,对吧。
二、进阶的rander函数
我们已经实现了一个最简单的render函数,我们不妨在思考下,在vue中是如何将组件渲染成DOM的?
function Render(vnode, container) {
if (typeof vnode.tag === 'string') {
// 标签元素
mountElement(vnode, container)
} else if (typeof vnode.tag === 'function') {
// 组件
mountComponent(vnode, container)
} else if (typeof vnode.tag === 'object') {
// 对象
mountObjComponent(vnode, container)
}
}
我们先不去思考mountElement mountComponent mountObjComponent这三个方法的实现,我们先来看看整体思路。
很明显第一个判断 依然是我们最简单的‘div’等标签
然后我们进行拓展让tag可以是function 如:
const MyConponent = function () {
return {
tag: 'div',
props: {
onClick: () => alert('123')
},
children: '点击'
}
}
const vnode = {
tag: MyConponent,
}
Render(vnode, document.body)
这里传入的就是一个函数,并且我们加入了一个点击事件。所以他将走入我们Rander的二个判断。执行mountComponent函数,执行mountComponent后又将递归的执行Render知道渲染完成。
function mountElement(vnode, container) {
const el = document.createElement(vnode.tag)
// 将属性,事件添加到Dom
for (const key in vnode.props) {
if (/^on/.test(key)) {
el.addEventListener(
key.substr(2).toLowerCase(), // onClick -->click
vnode.props[key]
)
}
}
if (typeof vnode.children === 'string') {
const text = document.createTextNode(vnode.children)
el.appendChild(text)
} else if (Array.isArray(vnode.children)) {
vnode.children.forEach((child) => Render(child, el));
}
container.appendChild(el)
}
function mountComponent(vnode, container) {
// 调用组件函数,获取组件要渲染的内容
const subtree = vnode.tag()
Render(subtree, container)
}
让我们思考下组件一定是函数吗? 当然不一定,比如他是一个对象。这是就会走Render的第三个判断,并执行mountObjComponent函数。
const MyConponent = {
render() {
return {
tag: 'div',
props: {
onClick: () => alert('123')
},
children: '点击'
}
}
}
const vnode = {
tag: MyConponent,
}
function mountObjComponent(vnode, container) {
const subtree = vnode.tag.render()
Render(subtree, container)
}
这就是为对象的处理,是不是与为函数时很相似。
更多推荐
所有评论(0)