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

直接来到进阶部分,过渡动画的过了一遍,大概讲述在dom发生变化时可以伴随的动画效果。不看了,后面用到再来看,更关注业务内容如何变化。

  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’。

1.5 VNodes 必须唯一。这句话说的不是很清楚,其实就是同一个VNode只能用在一个地方。 
比如

render: function (createElement) {var myParagraphVNode = createElement('p', 'hi') return createElement('div', [ // Yikes - duplicate VNodes! myParagraphVNode, myParagraphVNode ]) }

这里的myParagraphVNode,被使用于’div’中的两个VNode,这种用法是不行,要想用只能创建两个相同的VNode对象,而不是这样指向同一个VNode对象。

1.6 Render之函数化组件 
大概是这个意思,看看1.5的render的结构, 
render:function(createElement){} 这个结构可以创建VNode对吧,但是无法访问外部数据,如果希望创建的VNode需要依赖外部数据怎么办?这就是这一节的内容。

将其改写为以下方式,就可以访问外部数据了:

Vue.component('my-component', {functional: true,     //1// 为了弥补缺少的实例// 提供第二个参数作为上下文render: function (createElement, context) {   //2// ... }, })

通过1和2两个改写,就可以利用context去访问外部数据了,context相当于一个组件的上下文,可以访问该组件的一些数据: 
props: 提供props 的对象 
children: VNode 子节点的数组 
slots: slots 对象 
data: 传递给组件的 data 对象 
parent: 对父组件的引用

比如:this.$slots.default 更新为 context.children,之后this.level 更新为 context.props.level。 
差不多就是这个意思

1.7 模板编译过程 
这里讲到一些vue模板底层在生命周期的编译阶段Vue.compile的处理方式。 
比如模板:

<div><h1>I'm a template!</h1> <p v-if="message"> {{ message }} </p> <p v-else> No message. </p> </div> 

在编译的时候会类似以下的处理 

可以看出div被创建的时候,类似于createElement,传了VNodes数组给他,_m(0)就是第一个节点VNode<h1>I'm a template!</h1> 后面的参数是个选择运算符a?b:c,如果message为true,则创建一个p节点,如果为false,也创建一个p节点,只不错两个p节点内容不一样

另外可以为createElement取别名,一般用h表示

1.7 JSX 
这个东东作为我这样的前端小白,以前是没有听过的。查了一下,JSX语法,像是在JavaScript代码里直接写XML的语法,每一个XML标签都会被JSX转换工具转换成纯javascript代码。看下面的例子:

//不使用JSX的情况下可能要这么写
render: function (h) {h('div', [ h('span', 'Hello'), ' world!' ] ) } //使用JSX可以像写xml或html这类标签语言一样直接写,是不是直观很多 render (h) { return ( <div> <span>Hello</span> world! </div> ) };

Vue中使用JSX需要这个插件 :Babel plugin 。https://github.com/vuejs/babel-plugin-transform-vue-jsx

转载于:https://www.cnblogs.com/yaowen/p/7111075.html

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

  1. 第三课 k8s源码学习和二次开发-缓存机制Informers和Reflector组件学习

    第三课 k8s源码学习和二次开发-缓存机制Informers和Reflector组件学习 tags: k8s 源码学习 categories: 源码学习 二次开发 文章目录 第三课 k8s源码学习和二 ...

  2. Vue2.0学习笔记二 基础语法

    1. Mustache语法 Mustache语法也叫插值表达式,Mustache语法式通过{{}}渲染到页面,并且数据是响应式的. 数据的响应式:数据的变化导致页面的内容随之变化 效果图: 2. 指令 ...

  3. pandas 学习(二)—— pandas 下的常用函数

    import pandas as pd; 1. 数据处理函数 pd.isnull()/pd.notnull():用于检测缺失数据: 2. 辅助函数 pd.to_datetime() 3. Series ...

  4. 【Unity】Entities 1.0 学习(二):调试工具

    在 Entites 1.0 ,Unity修改了之前的调试面板,以及在场景下构建 Ecs World 的流程,较之前的版本差别还是蛮大的. 之前的学习大多集中在代码和语法,很多是对之前成熟的代码做升级改 ...

  5. Scheduler 学习之二:主调度器_schedule函数

    Summary 1.1 _schedule函数是又被称作为主调度器,负责选择新的task run到当前的cpu当中 1.2 _scheduler将选核的功能交给各调度类完成 1.3 pick_next ...

  6. ASM3.0学习(二)

    2019独角兽企业重金招聘Python工程师标准>>> 2.2.2解析类 解析一个已存在的类仅需要ClassReader这个组件.下面让我们以一个实例来展示如何解析类.假设,我们想要 ...

  7. Hadoop-2.2.0学习之二HDFS联盟

    在学习Hadoop-2.x版本中的HDFS之前先看一下目前普遍使用中的Hadoop-1.x版本的HDFS结构,有助于更好地理解2.x版本中HDFS的变化所带来的好处.先看看2.x版本之前的HDFS结构 ...

  8. mongodb4.0学习总结二(read concern)

    mongodb中的read concern可以用来控制读副本集或分片集时的一致性和隔离性. 通过使用read concern和write concern可以适当的调整一致性和可用性保证级别,比如等待更 ...

  9. Flexe2.0 学习笔记二(利用PopUpManager实现一个组件登录窗体)

    通过对代码的学习实现了一个登录窗体的显示,还未涉及到参数的传递,这次的问题是窗体位置的控制需要如何解决?努力学习ing..... 代码下载 问题已解决 只要在 helpWindow = TitleWi ...

  10. 《OpenSSL3.0学习之二十七 EVP_OpenXXX》

最新文章

  1. AI聚变:寻找2018最佳人工智能应用案例
  2. linux nice线程,linux nice 线程
  3. jQuery应用之(二)使用jQuery管理选择结果(荐)
  4. Vector的简单使用
  5. 编程疑难杂症の设置正确却无效的事件代码
  6. JavaScript数据结构与算法——基本排序算法
  7. 用到f6的快捷键_让你的办公效率成倍翻得快捷键。
  8. 编译原理第三版王生原pdf_CS143:编译原理 | 环境搭建HelloWorld
  9. boot camp驱动下载以及对应机型版本查询
  10. 泰克示波器时频多域信号频谱谐波分析
  11. ntdll.dll 0xc0000005
  12. mount挂载硬盘出错 linux 下分区格式为lvm
  13. 浅谈API开发安全之sign有效时间(三)
  14. linux gic驱动
  15. 把飞书融入日常学习流程:一个人的飞书也挺好
  16. 老式马桶水封不足的唯一解决方案
  17. 3 万字,关系型数据库性能体系,设计和效率提升
  18. java设计模式_UML类图(上)
  19. 快过年了别着急玩耍,学会指针轻松一整年的学习
  20. Python爬虫-某旅游网

热门文章

  1. 修改默认启动操作系统
  2. spring5.0学习笔记3
  3. C语言程序设计 第八章字符串
  4. python resize重置大小
  5. java ee 企业级意味着什么意思_​Java EE是什么意思
  6. Java之数组(下)
  7. Unity Animation和Animator的区别
  8. 【jsp】基础知识总结
  9. 血的教训!千万别在生产使用这些 redis 指令
  10. Kubernetes(K8s) 1.14.3 单机版配置 node 节点 是 taint 时解决方法