Vue推荐在绝大多数情况下使用template来创建你的HTML。然而在一些场景中,你真的需要JavaScript的完全编程能力,这时你可以使用render函数,它比template跟接近编译器.

虚拟DOM

在深入渲染函数之前,了解一些浏览器的工作原理很重要。以下面这段HTML为例:


<div>
<h1>My title</h1>
Some text content
<!--TODO:添加标签行-->
</div>

当浏览器读到这些代码时,它会建立一个‘DOM节点树’来保持追踪,如同你会画一张家谱树来追踪家庭成员的发展一样。
HTML的DOM节点树如下图所示:

每个元素都是一个节点。每片文字也是一个节点。甚至注释也都是节点。一个节点就是页面的一个部分。就像家谱树一样,每个节点都可以有孩子节点(也就是说每个部分可以包含其它一些部分)。
高效的更新所有这些节点会是比较困难的,不过所幸你不必再手动完成这个工作了。你只需要告诉Vue你希望页面上的HTML是什么,这可以是在一个模板里:


<h1>{{blogTitle}}</h1>

或则一个渲染函数里:


render:function(createElement){
return createElement('h1',this.blogTitle);
}

在这两种情况下,Vue都会自动保持页面的更新,即便blogTitle发生了改变。

Vue通过建立一个虚拟DOM对真实的DOM发生的变化保持追踪。请仔细看这行代码:


return createElement('h1',this.blogTitle)

createElement到底返回什么呢?其实不是一个实际的Dom元素。它更准确的名字可能是createNodeDescription,因为它所包含的信息会告诉Vue页面上需要渲染什么样的节点,及其子节点。我们把这样的节点描述为虚拟节点,也常简写为VNode。虚拟DOM是我们对Vue组件树建立起来的整个VNode树的称呼。

createElement参数


createElement(
//{String|Object|Function}
//一个HTML标签字符串,组件选项对象,或则解析上述任何一种的一个async异步函数。必须参数。
'div', //{Object}一个包含模板相关属性的数据对象,你可以在template中使用这些特性。可选参数。
{}, //{String|Array}子虚拟节点,由createElement()构建而成,也可以使用也可以使用字符串来生成文本虚拟节点。可选参数。
[
'先写一些文字',
createElement('h1','一则头条'),
createElement(Mycomponent,{
props:{
someProp:'foobar'
}
})
] )

深入data对象

有一点要注意:正如在模板语法中,v-bind:class和v-bind:style,会被特别对待一样,在VNode数据对象中,下列属性名是级别最高的字段。该对象也允许你绑定普通的HTML特性,就像DOM属性一样,比如innnerHTML(这会取代v-html指令)。


{
//和v-bind:class一样的API,接收一个字符串、对象或字符串和对象组成的数组。
'class':{
foo:true,
bar:false
},
//和v-bind:style一样的API,接收一个字符串、对象或对象数组组成的数组
style:{
color:'red',
fontSize:'14px'
},
//普通的HTML特性
attrs:{
id:'foo'
},
//组件props
props:{
myPro:'bar'
},
//DOM属性
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=>createElement('span',props.text)}
scopedSlots:{
default:props=>createElement('span',props.text)
},
//如果组件是其它组件的子组件,需要为插槽指定名称。
slot:'name-of-slot',
//其它特殊顶层属性
key:'myKey',
ref:'myRef',
//如果你在渲染函数中向多个元素都应用了相同的ref名,那么$refs.myRef会变成一个数组。
refInFor:true
}

完整示例

有了这些知识,我们现在可以完成我们最开始想实现的组件:


var getChildrenTextContent = function(children){
return children.map(function(node){
return node.children
?getChildrenTextContent(node.children)
:node.text
}).join('')
}
Vue.component('anchord-heading',{
render:function(createElement){
//创建kebab-case风格的ID
var headingId = getChildrenTextContent(this.$slots.default)
.toLowerCase()
.replace(/\W+/g,'-')
.replace(/(^\-|\-$)/g,'')
return createElement(
'h'+this.level,
[
createElement('a',{
attrs:{
name:headingId,
href:'#'+headingId
}
},this.$slots.default)
]
)
},
props:{
level:{
type:Number,
required:true
}
}
})

原文地址:https://segmentfault.com/a/1190000017354905

最新文章

  1. struts2 数据校验
  2. c++截取英文和汉字(单双字节)混合字符串
  3. 打开Windows10网络发现或是文件打印共享
  4. 微信支付开发h5发起支付再次签名,返回给h5前端
  5. 【Android】Activity遮罩效果的实现
  6. 小米MIUI 360wifi掉线解决方案 落雨
  7. js 数组详解(javascript array)
  8. 使用solrj进行DIH操作
  9. java 类处理工具
  10. Android应用切换皮肤功能实现
  11. iScroll 4.2.5 中文API
  12. Markdown转pdf
  13. 封装Echarts
  14. VMware系统克隆
  15. ROS(indigo)国外开源示例包括多机器人控制等基于V-Rep和Gazebo的仿真
  16. 编译安装LAMP
  17. java内存配置举例
  18. Oracle客户端的安装与远程连接配置
  19. UVa 1103 Ancient Messages(二重深搜)
  20. JAVA 类和对象基础知识详解

热门文章

  1. JS高级学习历程-14
  2. 字典排序permutation
  3. Uva10755
  4. JAVA---spring-boot入门(图文教程)
  5. AtCoderBeginnerContest109题解
  6. TCP/IP协议分析含义与功能
  7. github上fork原项目,如何将本地仓库代码更新到最新版本?
  8. C#调用SAP S4/HANA Gateway Service
  9. (四)SpringMVC之使用cookie实现记住密码的功能
  10. 在浏览器里使用SAPGUI