Vue render深入开发讲解


Posted in Javascript onApril 13, 2018

简介

在使用Vue进行开发的时候,大多数情况下都是使用template进行开发,使用template简单、方便、快捷,可是有时候需要特殊的场景使用template就不是很适合。因此为了很好使用render函数,我决定深入窥探一下。各位看官如果觉得下面写的有不正确之处还望看官指出,你们与我的互动就是写作的最大动力。

场景

官网描述的场景当我们开始写一个通过 level prop 动态生成 heading 标签的组件,你可能很快想到这样实现:

<script type="text/x-template" id="anchored-heading-template">
 <h1 v-if="level === 1">
  <slot></slot>
 </h1>
 <h2 v-else-if="level === 2">
  <slot></slot>
 </h2>
 <h3 v-else-if="level === 3">
  <slot></slot>
 </h3>
 <h4 v-else-if="level === 4">
  <slot></slot>
 </h4>
 <h5 v-else-if="level === 5">
  <slot></slot>
 </h5>
 <h6 v-else-if="level === 6">
  <slot></slot>
 </h6>
</script>
Vue.component('anchored-heading', {
 template: '#anchored-heading-template',
 props: {
  level: {
   type: Number,
   required: true
  }
 }
})

在这种场景中使用 template 并不是最好的选择:首先代码冗长,为了在不同级别的标题中插入锚点元素,我们需要重复地使用 <slot></slot>。

虽然模板在大多数组件中都非常好用,但是在这里它就不是很简洁的了。那么,我们来尝试使用 render 函数重写上面的例子:

Vue.component('anchored-heading', {
 render: function (createElement) {
  return createElement(
   'h' + this.level,  // tag name 标签名称
   this.$slots.default // 子组件中的阵列
  )
 },
 props: {
  level: {
   type: Number,
   required: true
  }
 }
})

简单清晰很多!简单来说,这样代码精简很多,但是需要非常熟悉 Vue 的实例属性。在这个例子中,你需要知道当你不使用 slot 属性向组件中传递内容时,比如 anchored-heading 中的 Hello world!,这些子元素被存储在组件实例中的 $slots.default中。

createElement参数介绍

接下来你需要熟悉的是如何在 createElement 函数中生成模板。这里是 createElement 接受的参数:

createElement(
 // {String | Object | Function}
 // 一个 HTML 标签字符串,组件选项对象,或者
 // 解析上述任何一种的一个 async 异步函数,必要参数。
 'div',

 // {Object}
 // 一个包含模板相关属性的数据对象
 // 这样,您可以在 template 中使用这些属性。可选参数。
 {
  // (详情见下一节)
 },

 // {String | Array}
 // 子节点 (VNodes),由 `createElement()` 构建而成,
 // 或使用字符串来生成“文本节点”。可选参数。
 [
  '先写一些文字',
  createElement('h1', '一则头条'),
  createElement(MyComponent, {
   props: {
    someProp: 'foobar'
   }
  })
 ]
)

深入 data 对象

有一件事要注意:正如在模板语法中,v-bind:class 和 v-bind:style ,会被特别对待一样,在 VNode 数据对象中,下列属性名是级别最高的字段。该对象也允许你绑定普通的 HTML 特性,就像 DOM 属性一样,比如 innerHTML (这会取代 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: {
  myProp: '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
   }
  }
 ],
 // Scoped slots in the form of
 // { name: props => VNode | Array<VNode> }
 scopedSlots: {
  default: props => createElement('span', props.text)
 },
 // 如果组件是其他组件的子组件,需为插槽指定名称
 slot: 'name-of-slot',
 // 其他特殊顶层属性
 key: 'myKey',
 ref: 'myRef'
}

条件渲染

既然熟读以上api接下来咱们就来点实战。

之前这样写

//HTML
<div id="app">
  <div v-if="isShow">我被你发现啦!!!</div>
</div>
<vv-isshow :show="isShow"></vv-isshow>
//js
//组件形式      
Vue.component('vv-isshow', {
  props:['show'],
  template:'<div v-if="show">我被你发现啦2!!!</div>',
});
var vm = new Vue({
  el: "#app",
  data: {
    isShow:true
  }
});

render这样写

//HTML
<div id="app">
  <vv-isshow :show="isShow"><slot>我被你发现啦3!!!</slot></vv-isshow>
</div>
//js
//组件形式      
Vue.component('vv-isshow', {
  props:{
    show:{
      type: Boolean,
      default: true
    }
  },
  render:function(h){  
    if(this.show ) return h('div',this.$slots.default);
  },
});
var vm = new Vue({
  el: "#app",
  data: {
    isShow:true
  }
});

列表渲染

之前是这样写的,而且v-for 时template内必须被一个标签包裹

//HTML
<div id="app">
  <vv-aside v-bind:list="list"></vv-aside>
</div>
//js
//组件形式      
Vue.component('vv-aside', {
  props:['list'],
  methods:{
    handelClick(item){
      console.log(item);
    }
  },
  template:'<div>\
         <div v-for="item in list" @click="handelClick(item)" :class="{odd:item.odd}">{{item.txt}}</div>\
       </div>',
  //template:'<div v-for="item in list" @click="handelClick(item)" :class="{odd:item.odd}">{{item.txt}}</div>',错误     
});
var vm = new Vue({
  el: "#app",
  data: {
    list: [{
      id: 1,
      txt: 'javaScript',
      odd: true
    }, {
      id: 2,
      txt: 'Vue',
      odd: false
    }, {
      id: 3,
      txt: 'React',
      odd: true
    }]
  }
});

render这样写

//HTML
<div id="app">
  <vv-aside v-bind:list="list"></vv-aside>
</div>
//js
//侧边栏
Vue.component('vv-aside', {
  render: function(h) {
    var _this = this,
      ayy = this.list.map((v) => {
        return h('div', {
          'class': {
            odd: v.odd
          },
          attrs: {
            title: v.txt
          },
          on: {
            click: function() {
              return _this.handelClick(v);
            }
          }
        }, v.txt);
      });
    return h('div', ayy);

  },
  props: {
    list: {
      type: Array,
      default: () => {
        return this.list || [];
      }
    }
  },
  methods: {
    handelClick: function(item) {
      console.log(item, "item");
    }
  }
});
var vm = new Vue({
  el: "#app",
  data: {
    list: [{
      id: 1,
      txt: 'javaScript',
      odd: true
    }, {
      id: 2,
      txt: 'Vue',
      odd: false
    }, {
      id: 3,
      txt: 'React',
      odd: true
    }]
  }
});

v-model

之前的写法

//HTML
<div id="app">
  <vv-models v-model="txt" :txt="txt"></vv-models>
</div>
//js
//input
Vue.component('vv-models', {
  props: ['txt'],
  template: '<div>\
         <p>看官你输入的是:{{txtcout}}</p>\
         <input v-model="txtcout" type="text" />\
       </div>',
  computed: {
    txtcout:{
      get(){
        return this.txt;
      },
      set(val){
        this.$emit('input', val);
      }
      
    }
  }
});
var vm = new Vue({
  el: "#app",
  data: {
    txt: '', 
  }
});

render这样写

//HTML
<div id="app">
  <vv-models v-model="txt" :txt="txt"></vv-models>
</div>
//js
//input
Vue.component('vv-models', {
  props: {
    txt: {
      type: String,
      default: ''
    }
  },
  render: function(h) {
    var self=this;
    return h('div',[h('p','你猜我输入的是啥:'+this.txt),h('input',{
      on:{
        input(event){
          self.$emit('input', event.target.value);
        }
      }
    })] );
  },
});
var vm = new Vue({
  el: "#app",
  data: {
    txt: '', 
  }
});

总结

render函数使用的是JavaScript 的完全编程的能力,在性能上是占用绝对的优势,小编只是对它进行剖析。至于实际项目你选择那种方式进行渲染依旧需要根据你的项目以及实际情况而定。

Javascript 相关文章推荐
JAVASCRIPT  THIS详解 面向对象
Mar 25 Javascript
使用ngView配合AngularJS应用实现动画效果的方法
Jun 19 Javascript
jquery实现不包含当前项的选择器实例
Jun 25 Javascript
基于javascript实现全国省市二级联动下拉选择菜单
Jan 28 Javascript
js+canvas简单绘制圆圈的方法
Jan 28 Javascript
JS实现复选框的全选和批量删除功能
Apr 05 Javascript
Vue 监听列表item渲染事件方法
Sep 06 Javascript
解决angularJS中input标签的ng-change事件无效问题
Sep 13 Javascript
微信小程序实现点赞、取消点赞功能
Nov 02 Javascript
JavaScript实现的弹出遮罩层特效经典示例【基于jQuery】
Jul 10 jQuery
Vue实现点击当前元素以外的地方隐藏当前元素(实现思路)
Dec 04 Javascript
javascript Canvas动态粒子连线
Jan 01 Javascript
用vue2.0实现点击选中active其他选项互斥的效果
Apr 12 #Javascript
vue组件的写法汇总
Apr 12 #Javascript
jQuery实现文件编码成base64并通过AJAX上传的方法
Apr 12 #jQuery
基于vue-simplemde实现图片拖拽、粘贴功能
Apr 12 #Javascript
基于angular6.0实现的一个组件懒加载功能示例
Apr 12 #Javascript
JavaScript实现简单的文本逐字打印效果示例
Apr 12 #Javascript
jQuery实现鼠标点击处心形漂浮的炫酷效果示例
Apr 12 #jQuery
You might like
常用的php ADODB使用方法集锦
2008/03/25 PHP
php实现可用于mysql,mssql,pg数据库操作类
2014/12/13 PHP
Linux下快速搭建php开发环境
2017/03/13 PHP
HTML-CSS群中单选引发的“事件”
2007/03/05 Javascript
JS版网站风格切换实例代码
2008/10/06 Javascript
jQuery(1.6.3) 中css方法对浮动的实现缺陷分析
2011/09/09 Javascript
Java File类的常用方法总结
2015/03/18 Javascript
jQuery获取DOM节点实例分析(2种方式)
2015/12/15 Javascript
Easyui 之 Treegrid 笔记
2016/04/29 Javascript
原生js的数组除重复简单实例
2016/05/24 Javascript
laydate.js日期时间选择插件
2017/01/04 Javascript
vue双向数据绑定原理探究(附demo)
2017/01/17 Javascript
Vue.js实现微信过渡动画左右切换效果
2017/06/13 Javascript
如何利用node.js开发一个生成逐帧动画的小工具
2019/12/01 Javascript
[46:53]Secret vs Liquid 2019国际邀请赛小组赛 BO2 第一场 8.15
2019/08/17 DOTA
Python文件夹与文件的相关操作(推荐)
2016/07/25 Python
Python实现对字典分别按键(key)和值(value)进行排序的方法分析
2018/12/19 Python
Pycharm+Scrapy安装并且初始化项目的方法
2019/01/15 Python
如何使用python操作vmware
2019/07/27 Python
python中如何使用insert函数
2020/01/09 Python
TensorFlow:将ckpt文件固化成pb文件教程
2020/02/11 Python
Python模块相关知识点小结
2020/03/09 Python
Pycharm IDE的安装和使用教程详解
2020/04/30 Python
使用Python将xmind脑图转成excel用例的实现代码(一)
2020/10/12 Python
python实现控制台输出颜色
2021/03/02 Python
前端canvas动画如何转成mp4视频的方法
2019/06/17 HTML / CSS
移动端html5判断是否滚动到底部并且下拉加载
2019/11/19 HTML / CSS
美国顶级水上运动专业店:Marine Products
2018/04/15 全球购物
路由表示做什么用的?在linux环境中怎么来配置一条默认路由?
2013/06/07 面试题
J2EE中常用的名词进行解释
2015/11/09 面试题
护理工作感言
2014/01/16 职场文书
中专生自我鉴定范文
2014/02/02 职场文书
小摄影师教学反思
2014/04/27 职场文书
2015年小学英语教师工作总结
2015/05/12 职场文书
Python爬虫进阶之Beautiful Soup库详解
2021/04/29 Python
《艾尔登法环》发布最新「战技」宣传片
2022/04/03 其他游戏