vue 如何生成一个dom元素_vue:虚拟dom的实现

Vitual DOM是一种虚拟dom技术,本质上是基于javascript实现的,相对于dom对象,javascript对象更简单,处理速度更快,dom树的结构,属性信息都可以很容易的用javascript对象来表示:

let element={

tagName:'ul',//节点标签名

props:{//dom的属性,用一个对象存储键值对

id:'list'

},

children:[//该节点的子节点

{tagName:'li',props:{class:'item'},children:['aa']},

{tagName:'li',props:{class:'item'},children:['bb']},

{tagName:'li',props:{class:'item'},children:['cc']}

]

}

对应的html写法是:

  • aa
  • aa
  • aa

Virtual DOM并没有完全实现DOM,Virtual DOM最主要的还是保留了Element之间的层次关系和一些基本属性. 你给我一个数据,我根据这个数据生成一个全新的Virtual DOM,然后跟我上一次生成的Virtual DOM去 diff,得到一个Patch,然后把这个Patch打到浏览器的DOM上去。

我们可以通过javascript对象表示的树结构来构建一棵真正的dom树,当数据状态发生变化时,可以直接修改这个javascript对象,接着对比修改后的javascript对象,记录下需要对页面做的dom操作,然后将其应用到真正的dom树,实现视图的更新,这个过程就是Virtual DOM的核心思想。

VNode的数据结构图:

vue 如何生成一个dom元素_vue:虚拟dom的实现_第1张图片

vue 如何生成一个dom元素_vue:虚拟dom的实现_第2张图片

VNode生成最关键的点是通过render有2种生成方式,第一种是直接在vue对象的option中添加render字段。第二种是写一个模板或指定一个el根元素,它会首先转换成模板,经过html语法解析器生成一个ast抽象语法树,对语法树做优化,然后把语法树转换成代码片段,最后通过代码片段生成function添加到option的render字段中。

ast语法优的过程,主要做了2件事:

会检测出静态的class名和attributes,这样它们在初始化渲染后就永远不会再被比对了。

会检测出最大的静态子树(不需要动态性的子树)并且从渲染函数中萃取出来。这样在每次重渲染时,它就会直接重用完全相同的vnode,同时跳过比对。

src/core/vdom/create-element.js

const SIMPLE_NORMALIZE = 1

const ALWAYS_NORMALIZE = 2

function createElement (context, tag, data, children, normalizationType, alwaysNormalize) {

// 兼容不传data的情况

if (Array.isArray(data) || isPrimitive(data)) {

normalizationType = children

children = data

data = undefined

}

// 如果alwaysNormalize是true

// 那么normalizationType应该设置为常量ALWAYS_NORMALIZE的值

if (alwaysNormalize) normalizationType = ALWAYS_NORMALIZE

// 调用_createElement创建虚拟节点

return _createElement(context, tag, data, children, normalizationType)

}

function _createElement (context, tag, data, children, normalizationType) {

/**

* 如果存在data.__ob__,说明data是被Observer观察的数据

* 不能用作虚拟节点的data

* 需要抛出警告,并返回一个空节点

* 被监控的data不能被用作vnode渲染的数据的原因是:

* data在vnode渲染过程中可能会被改变,这样会触发监控,导致不符合预期的操作

*/

if (data && data.__ob__) {

process.env.NODE_ENV !== 'production' && warn(

`Avoid using observed data object as vnode data: ${JSON.stringify(data)}\n` +

'Always create fresh

你可能感兴趣的:(vue,如何生成一个dom元素)