直接来到进阶部分,

  1. Render函数 
    直接来到Render,本来也想跳过,发现后面的路由貌似跟它还有点关联。先来看看Render 
    1.1 官网一开始就看的挺懵的,不知道讲的是啥,动手试了一下,一开头讲的是Render的用法,官网的栗子永远都是一个特点,tm的不贴完整,我这里是个相对完整版的:(为了看的清楚点,替换了下名字)
  <div id="div1">
    <child :level="2">Hello world!</child>
  </div>   <script type="text/x-template" id="template">
   <div>
   <h1 v-if="level === 1">
   <slot></slot>
   </h1>
   <h2 v-if="level === 2">
   <slot></slot>
   </h2>
   <h3 v-if="level === 3">
   <slot></slot>
   </h3>
   <h4 v-if="level === 4">
   <slot></slot>
   </h4>
   <h5 v-if="level === 5">
   <slot></slot>
   </h5>
   <h6 v-if="level === 6">
   <slot></slot>
   </h6>
   </div>
  </script>   <script type="text/javascript">
  Vue.component('child', {
   template: '#template',
   props: {
   level: {
   type: Number,
   required: true
   }
   }
  }) new Vue({
   el:"#div1"
  })
  </script>

回顾一下前面所学,这里注册了一个名叫child的全局组件,其模板是id=template的模板,往上一看发现,这个写法跟以前不一样啊,以前用的是<template>标签,小伙伴们还有印象不?为此查了下api,也就是说这是新版写法。模板里有做了判断,根据level的值来选择head的尺寸h1-h6,同时使用slot分发内容(不记得的童鞋可以看看我前面的文章)。level在哪里?回头看组件里的props,这东东还有印象不,父组件传递参数给子组件可以用它,同时还做了props验证,level必须是Number类型,这个前面我们也聊过的。

最后实例化Vue,在id=div1的块中使用Vue,这样div1就可以使用child模板:

<div id="div1">
<child :level="2">Hello world!</child>
</div>

此时,父组件div1可以使用子模板child,同时父模板可以使用level属性,采用bind的方式可以传递数值2,不用:去bind的后果就是传递字符串”2”,这个也聊过了。hello world作为slot分发的内容。所以最后整个内容会显而易见的被渲染为:。。。不写了,自己研究。

突然发现我们的案例越来越复杂了,还好前面有做准备。但是这一切跟Render好像没有半毛钱关系啊,确实没有关系- -!官方举了这个栗子就是说明这种写法是繁杂浪费的,浪费的原因是,虽然最后只剩下h2,但是其他的h1,h3-h5其实都被渲染了,只不过没有显示而已。为了优化,所以才引用了Render。

1.2 将上面代码改写为Render方式

//html
<div id="div1">
<child :level="3">Hello world!</child>
</div> //script
<script type="text/javascript">
Vue.component('child', {
render: function (createElement) {
return createElement(
'h' + this.level, // tag name 标签名称
this.$slots.default // 子组件中的阵列
)
},
props: {
level: {
type: Number,
required: true
}
}
})
new Vue({
el:"#div1"
})
</script>

没了?是的,没了。不信你试一下,效果是一样的,绑定1的话渲染出h1,绑定2渲染h2。我去,很6啊,模板都不要就搞定了。怎么做到的?看createElement是个啥东东先,所以就开始createElement。所以,大家们发现了没,这官网的逻辑就是非主流啊,无意中被我发现了要理解他的逻辑必须向我这样边试边看才行,哇咔咔。不过我们顾名思义一下,createElement看名字像动态创建dom节点(节点vue里面也叫VNode)的过程,在看内容,’h’+this.level根据level创建标签h1-h6,所以它只会渲染一个标签,而不是所有都渲染,所以优化了,而且代码也省了不少呢。

1.3 createElement有点印象,js添加dom节点可以用它,document.createElement(tag)。这里的createElement(tag,{},[])或者createElement(tag,{},String)类似,不过接收的参数不一样,后面两个参数都是可选的

// @returns {VNode}
createElement(
// {String | Object | Function}
// 一个 HTML 标签,组件设置,或一个函数
// 必须 Return 上述其中一个
'div',
// {Object}
// 一个对应属性的数据对象
// 您可以在 template 中使用.可选项.
{
// (下一章,将详细说明相关细节)
},
// {String | Array}
// 子节点(VNodes). 可选项.
[
createElement('h1', 'hello world'),
createElement(MyComponent, {
props: {
someProp: 'foo'
}
}),
'bar'
]
)

其中tag参数类似,第二个参数{}其实就一个数据对象,代表用在该节点的属性,比如常见的class,style,props,on等,完整的数据对象如下:

{
// 和`v-bind:class`一样的 API
'class': {
foo: true,
bar: false
},
// 和`v-bind:style`一样的 API
style: {
color: 'red',
fontSize: '14px'
},
// 正常的 HTML 特性
attrs: {
id: 'foo'
},
// 组件 props
props: {
myProp: 'bar'
},
// DOM 属性
domProps: {
innerHTML: 'baz'
},
// 事件监听器基于 "on"
// 所以不再支持如 v-on:keyup.enter 修饰器
// 需要手动匹配 keyCode。
on: {
click: this.clickHandler
},
// 仅对于组件,用于监听原生事件,而不是组件使用 vm.$emit 触发的事件。
nativeOn: {
click: this.nativeClickHandler
},
// 自定义指令. 注意事项:不能对绑定的旧值设值
// Vue 会为您持续追踨
directives: [
{
name: 'my-custom-directive',
value: '2'
expression: '1 + 1',
arg: 'foo',
modifiers: {
bar: true
}
}
],
// 如果子组件有定义 slot 的名称
slot: 'name-of-slot'
// 其他特殊顶层属性
key: 'myKey',
ref: 'myRef'
}

第三个参数[]可以看出来是表示该节点下面还有其他的节点,就放在此处[createElement(tag1),createElement(tag2)]。ok,回头看1.2中改写的render方法,相当于用了createElement(tag,[])的形式,其中tag=’h’+this.level, []= this.$slots.default。第一个参数好理解,第二个参数this.$slots.default是什么鬼,不知道的时候就去查api,slots很显然就是用于分发的那些slot们,找到api中的slot。官方是这么描述的:

用来访问被 slot 分发的内容。每个具名 slot 有其相应的属性(例如:slot="foo" 中的内容将会在
vm.$slots.foo 中被找到)。default 属性包括了所有没有被包含在一个具名 slot 中的节点。
在使用 render 函数书写一个组件时,访问 vm.$slots 最有帮助。

所以这货其实代表的是不具名的slot内容,也就是[VNode1,VNode2…]数组,这里的只有一个VNode就是那句被child包裹的Hello world!所以1.2中的render最后渲染的结果其实就是一个<h1>Hello world!</h1>这样的节点。

1.4 原文后面给了个完整例子不描述了,不一样的地方在于创建a标签的时候使用了(tag,{},[])结构

createElement('a', {
attrs: {
name: headingId,
href: '#' + headingId
}
}, this.$slots.default)

var getChildrenTextContent = function (children) {
return children.map(function (node) {
return node.children
? getChildrenTextContent(node.children)
: node.text
}).join('')
} var headingId = getChildrenTextContent(this.$slots.default)
.toLowerCase()
.replace(/\W+/g, '-')
.replace(/(^\-|\-$)/g, '')

getChildrenTextContent 这个函数,因为this.$slots.default是个数组[VNode1,VNode2…],所以可以做map处理(印象中是SE6方法),对数组中的每个元素做统一处理:递归,一层层去查看VNode是否有子节点,有子节点就调用自身,直到无子节点后取出他的文本内容。最后用数组的join方法把每一层的文本用空格符连接 
比如

<div id="div1">
<child :level="1">
Hello world!
<h2>
woqu
<h3>what</h3>
</h2>
</child>
</div>

this.$slots.default的值是[VNode1,VNode2,VNode3],其中

VNode1 = Hello world!
VNode2 = <h2>woqu</h2>
VNode3 = <h3>what</h3>

VNode1没child,直接返回了Hello world!,VNode2有child是h2,所以递归了一次h2里面没child,返回了woqu,VNode3情况类似,最终返回了what。所以map的结果就是得到了一个数组[‘Hello world!’,’woqu’,’what’],然后调用join方法串起来,得到’Hello world! woqu what’; 
后面再进行.toLowerCase()转小写,变为’hello world! woqu what’;

replace(/\W+/g, '-')进行正则替换,正则对于搞it的来说应该不陌生,js中的正则格式是这样的,/正则表达式/匹配模式,匹配模式当然是可选的,\W表示非单词字符(0-9,a-z,A-Z,_),+表示一个或多个,/g表示使用全局匹配模式,全局的特点是每次匹配完,下次匹配的下标就是下一位,所以这次替换会把连续的非单词字符替换为-,变为’hello-world-woqu-what’;

再使用replace(/(^\-|\-$)/g, '')做一次正则替换,^\-表示匹配开头的-字符,\-$表示匹配结尾的-字符,|表示或者,这句的意思是如果字符串开头或结尾有-,就把他们替换成”,也就是直接删除,于是这里没有变化’hello-world-woqu-what’。

综上所述,var headingId = ‘hello-world-woqu-what’。

Vuejs2.0学习(Render函数,createElement,vm.$slots)的更多相关文章

  1. 【转】【Html】Vuejs2.0学习之二(Render函数,createElement,vm.$slots,函数化组件,模板编译,JSX)

    1.Render函数 所以直接来到Render,本来也想跳过,发现后面的路由貌似跟它还有点关联.先来看看Render 1.1 官网一开始就看的挺懵的,不知道讲的是啥,动手试了一下,一开头讲的是Rend ...

  2. Vuejs2.0学习之二(Render函数,createElement,vm.$slots,函数化组件,模板编译,JSX)

    时隔一周多,因为一些别的事情绊住了,下面接着写.中间这段时间也有看官方文档,发现正如他所说90%的基础内容都一样,所以这里直接跳到我比较关注的东东上,要是想看看哪些不一样,可以参考这个http://v ...

  3. vue2.0之render函数

    虽然vue推荐用template来创建你的html,但是在某些时候你也会用到render函数. 虚拟DOM Vue 通过建立一个虚拟 DOM 对真实 DOM 发生的变化保持追踪.请近距离看一下这行代码 ...

  4. render函数

    vue2.0之render函数   虽然vue推荐用template来创建你的html,但是在某些时候你也会用到render函数. 虚拟DOM Vue 通过建立一个虚拟 DOM 对真实 DOM 发生的 ...

  5. Render函数详解

    一.虚拟dom DOM是文档对象模型(Document Object Model)的简写,在浏览器中通过js来操作DOM的操作性能很差,于是虚拟Dom应运而生.虚拟Dom就是在js中模拟DOM对象树来 ...

  6. render函数、createElement函数与vm.$slots

    1.render函数.createElement函数 Vue.component('es-header', { render: function (createElement) { return cr ...

  7. Vue学习笔记进阶篇——Render函数

    基础 Vue 推荐在绝大多数情况下使用 template 来创建你的 HTML.然而在一些场景中,你真的需要 JavaScript 的完全编程的能力,这就是 render 函数,它比 template ...

  8. Python3.0科学计算学习之函数

    函数 函数允许程序的控制在不同的代码片段之间切换,函数的重要意义在于可以在程序中清晰地分离不同的任务,将复杂的问题分解为几个相对简单的子问题,并逐个解决.即"分而治之". Pyth ...

  9. 关于render函数的总结

    一般情况下封装一个导航组件的写法 <!DOCTYPE html> <html lang="en"> <head> <meta charse ...

随机推荐

  1. 如何使用Web3.js API 在页面中进行转账

    本文介绍如何使用Web3.js API 在页面中进行转账,是我翻译的文档Web3.js 0.2x 中文版 及 区块链全栈-以太坊DAPP开发实战 中Demo的文章说明. 写在前面 阅读本文前,你应该对 ...

  2. Mysql中从一张表中的数据添加到另一张表

    A为原表 B为要加入的表$sql="insert into B select * from A where id=$id";

  3. MySql之行记录的详细操作,创建用户以及库表的授权

    一 介绍 MySQL数据操作: DML ======================================================== 在MySQL管理软件中,可以通过SQL语句中的 ...

  4. JUnit 4.0学习笔记

    JUnit命令整理 @Test(timeout=  ) : 测试时间超过范围即失败 @Test(expected=) : 申明出会发生的异常 @Before :  在每一个测试方法前执行 @After ...

  5. 求[1,n]中与m互素的个数

    void dfs(int d, ll num, int z) { if (d>cnt) { if (num!=1) ans+=z*n/num; } else { dfs(d+1,num*p[d] ...

  6. Pudding Monsters CodeForces - 526F (分治, 双指针)

    大意: n*n棋盘, n个点有怪兽, 求有多少边长为k的正方形内恰好有k只怪兽, 输出k=1,...,n时的答案和. 等价于给定n排列, 对于任意一个长为$k$的区间, 若最大值最小值的差恰好为k, ...

  7. 根据id获取某一类的最大最小值

    ->selectRaw('max(marking_price) as maxPrice, min(marking_price) as minPrice, product_id') ->gr ...

  8. 先天性肾上腺增生症(ACH)

    先天性肾上腺增生症 类型 症状 并发症 治疗 情感支持 产前筛查 预防 什么是先天性肾上腺皮质增生症? 先天性肾上腺增生症(CAH)是一组影响肾上腺的遗传性疾病.肾上腺产生激素皮质醇和醛固酮.CAH是 ...

  9. Leetcode 5016. 删除最外层的括号

    5016. 删除最外层的括号  显示英文描述 我的提交返回竞赛   用户通过次数446 用户尝试次数469 通过次数456 提交次数577 题目难度Easy 有效括号字符串为空 ("&quo ...

  10. ReactiveCocoa入门教程--第二部分

    翻译自:http://www.raywenderlich.com/62796/reactivecocoa-tutorial-pt2 ReactiveCocoa 是一个框架,它允许你在你的iOS程序中使 ...