vue中的渲染函数
虚拟DOM浏览器在解析HTML文档的时候,会将文档中的元素、注释和文本等标记按照它们的层级关系组织成一课数,这就是我们所熟知的DOM树。那么虚拟DOM是什么呢?虚拟DOM是使用普通的JavaScript 对象来描述的 ==DOM ==元素,在Vue 中,每一个虚拟节点都是一 VNode 的实例。而Vue.js 之所以执行性能高,就是因为采用了 虚拟 DOM机制。虚拟DOM对象就是普通的JavaSc
虚拟DOM
浏览器在解析HTML文档的时候,会将文档中的元素、注释和文本等标记按照它们的层级关系组织成一课数,这就是我们所熟知的DOM树
。
那么虚拟DOM是什么呢?虚拟DOM是使用普通的JavaScript 对象来描述的 ==DOM ==元素,在Vue 中,每一个虚拟节点都是一 VNode 的实例。而Vue.js 之所以执行性能高,就是因为采用了 虚拟 DOM机制。
虚拟DOM对象就是普通的JavaScript对象,访问JavaScript对象要比访问真实的DOM 要快的多,Vue 在更新真实的 DOM 前,会比较更新前后 虚拟DOM 结构中有差异的部分,然后采用异步更新队列的方式将差异部分更新到真实的 DOM。
真实的 DOM 结构
<div id="app">
<h1>hello,vue</h1>
</div>
Vue.js的虚拟 DOM 创建的JavaScript对象:
var vNode = {
tag:'div',
data:{
attrs:{
id:'app'
}
},
children:{
//h1节点
}
}
render函数
在 Vue 实例中,我们大多数使用模板来构建HTML,但是有些使用我们需要使用JavaScript进行编程,那么我们可以使用render()
函数。render()
函数的返回值一定是createElement()
方法,8就而 createElement()
方法用于创建一个虚拟节点 (virtual node)
createElement
有三个参数,第一个参数是必须的,其参数类型可以是字符串(HTML标签名),对象(数组选项对象)和函数对象(解析前两者之一的 async 函数)。详情使用方法,和参数详解如下:
render(createElement) {
return createElement("h1", {
// 与 `v-bind:class` 的 API 相同,
// 接受一个字符串、对象或字符串和对象组成的数组
'class': {
foo: true,
bar: false
},
// 与 `v-bind:style` 的 API 相同,
// 接受一个字符串、对象,或对象组成的数组
style: {
color: 'red',
fontSize: '14px'
},
// 普通的 HTML attribute
attrs: {
id: 'foo'
},
// 组件 prop
props: {
myProp: 'bar'
},
// DOM property
domProps: {
innerHTML: 'baz'
},
// 事件监听器在 `on` 内,
// 但不再支持如 `v-on:keyup.enter` 这样的修饰器。
// 需要在处理函数中手动检查 keyCode。
on: {
click: this.clickHandler
},
// 仅用于组件,用于监听原生事件,而不是组件内部使用
// `vm.$emit` 触发的事件。
nativeOn: {
click: this.nativeClickHandler
},
// 自定义指令。注意,你无法对 `binding` 中的 `oldValue`
// 赋值,因为 Vue 已经自动为你进行了同步。
directives: [{
name: 'my-custom-directive',
value: '2',
expression: '1 + 1',
arg: 'foo',
modifiers: {
bar: true
}
}],
// 作用域插槽的格式为
// { name: props => VNode | Array<VNode> }
scopedSlots: {
default: props => createElement('span', props.text)
},
// 如果组件是其它组件的子组件,需为插槽指定名称
slot: 'name-of-slot',
// 其它特殊顶层 property
key: 'myKey',
ref: 'myRef',
// 如果你在渲染函数中给多个元素都应用了相同的 ref 名,
// 那么 `$refs.myRef` 会变成一个数组。
refInFor: true
},{//子节点对象});
}
简单来说 ,createElement函数的第一个参数是要创建的元素节点的名字或者组件选项;第二个参数是元素的属性集合(包括普通属性、porp、事件属性、自定义指令等);第三个参数是子节点的信息,以数组形式输出,如果该元素只有文本子节点,那么直接以字符串形式给出,如果还有其他子元素,则继续调用 createElement 函数。
createElement
函数并不是 DOM API 中的document.createElement()
方法,该函数是 Vue.js 中的函数,用来返回描述节点信息及其子节点信息的一个对象,即虚拟节点。
组件树中的所有 VNode 必须是唯一的,如下所示案例,这种就是不合法的
render: function (createElement) {
var myParagraphVNode = createElement('p', 'hi')
return createElement('div', [
// 错误 - 重复的 VNode
myParagraphVNode, myParagraphVNode
])
}
如果想要重复很多次的元素/组件,可以使用工厂函数来实现
render: function (createElement) {
return createElement('div',
Array.apply(null, { length: 20 }).map(function () {
return createElement('p', 'hi')
})
)
}
JavaScript 代替模板功能
在之前使用模板构建 HTML 的时候,我们可以使用指令。而通过 render 函数创建模板时,就无法提供这些指令,所以我们只能自己编写JavaScript 来实现。
v-if 和 v-for
<ul v-if="items.length">
<li v-for="item in items">{{ item.name }}</li>
</ul>
想要通过 render 函数完成上述 HTML页面的构建,过程如下所示:
props: ['items'],
render: function (createElement) {
if (this.items.length) {
return createElement('ul', this.items.map(function (item) {
return createElement('li', item.name)
}))
} else {
return createElement('p', 'No items found.')
}
}
判断参数 item 的长度,如果长度为 0 ,则返回一个 p 标签,如果长度不为 0 ,则返回一个 ul 标签,并且循环创建 li 子节点
v-model
props: ['value'],
render: function (createElement) {
var self = this
return createElement('input', {
domProps: {
value: self.value
},
on: {
input: function (event) {
self.$emit('input', event.target.value)
}
}
})
}
v-model 的本质是把 value的值作为prop,同时监听 input 事件,而上述代码就是按照 v-model的逻辑实现的。
更多推荐
所有评论(0)