了解VUE的render函数的使用


Posted in Javascript onJune 08, 2017

Vue 推荐在绝大多数情况下使用 template 来创建你的 HTML。然而在一些场景中,你真的需要 JavaScript 的完全编程的能力,这就是 render 函数,它比 template 更接近编译器。 在 HTML 层, 我们决定这样定义组件接口:通过传入不同的level 1-6 生成h1-h6标签,和使用slot生成内容

<div id="div1">
  <child :level="1">Hello world!</child>
</div>
<script type="text/x-template" id="child-template">
 <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>
 </script>

<script type="text/javascript">
  /**
   * 全局注册child组件,注意template如果值以 # 开始,则它用作选项符,将使用匹配元素的 innerHTML 作为模板。常用的技巧是用 <script type="x-template"> 包含模板,这样的好处是html不会渲染里面的内容
   * 这里使用template不是最好的选择,
   * 一、代码冗长 
   * 二、在不同的标题插入内容需要重复使用slot 
   * 三、由于组件必须有根元素,所以标题和内容被包裹在一个无用的div中,比如<div><h1>hello world</h1></div>
   */

  Vue.component('child', {
   template: '#child-template',
   props: {
    level: {
     type: Number,
     required: true
    }
   },
   data: function() {
    return {
     a: 1
    }
   }
  })

  new Vue({
    el:"#div1"
  })
 </script>

我们尝试使用render函数实现上面的例子,注意使用render函数,template 选项将被忽略。 createElement接收3个参数:

第一个参数可以是HTML标签名,组件或者函数都可以;此参数是必须的;

第二个为数据对象{Object}(可选);

第三个为子节点{String | Array}(可选),多个子节点[createElement(tag1),createElement(tag2)]。

<div id="div1">
  <child :level="1">
   Hello world!
  </child>
  <child :level="2">
   <!-- 将不会被显示 -->
   <span slot="footer">span</span>
   <p slot="header">header slot<span>span</span></p>
  </child>
 </div>

Vue.component('child', {
   render: function(createElement) {
    console.log(this.$slots);
    return createElement(
     'h'+ this.level, // tagName标签名称
     {
      // 为每个h标签设置class
      'class': {
       foo: true,
       bar: false
      },
      // 最终被渲染为内联样式
      style: {
       color: 'red',
       fontSize: '14px'
      },
      // 其他的html属性
      attrs: {
       id: 'foo',
       'data-id': 'bar'
      },
      // DOM属性
      domProps: {
       // innerHTML: 'from domProps',
      },
      // 事件监听器基于 "on"
      // 所以不再支持如 v-on:keyup.enter 修饰器
      on: {
       click: this.clickHandler
      },
      // ...
     },
     // 你可以从this.$slots获取VNodes列表中的静态内容
     // $slots.default用来访问组件的不具名slot
     // 当你可能需要具名slot的时候需要指定slot的name, this.$slots.header
     [this.$slots.default]
    )
   },
   template: '<div v-if="level===1"><slot></slot></div>', // 将被忽略
   props: {
    level: {
     type: Number,
     required: true
    }
   },
   methods: {
    clickHandler: function() {
     console.log('clickHandler')
    }
   }
  })

  new Vue({
    el:"#div1"
  })

我们现在可以完成这样的组件

<h1>
   <a name="hello-world" href="#hello-world" rel="external nofollow" >
    Hello world!
   </a>
</h1>

// 递归函数获得helloworld文本
  function getChildrenTextContent(child) {
    return child.map(function(node) {
      return node.children? getChildrenTextContent(node.children) : node.text
    }).join('')
  }
  Vue.component('child',{
    render: function(createElement) {
      var hello_world = getChildrenTextContent(this.$slots.default)
               .toLowerCase()
               .replace(/\W+/g,'-')
               .replace(/^\-|\-$/g,'');
      return createElement(
        'h'+ this.level,
        {},
        [ // 创建一个a标签,设置属性,并设置a标签的子节点
          createElement('a',{
            attrs: {
              name: hello_world,
              href: '#' + hello_world
            }
          },this.$slots.default)
        ]
      )
    },
    props: {
      level: {
        type: Number,
        required: true
      }
    }
  })
  new Vue({
    el:"#div1"
  })

注意VNode的唯一性,这里两个VNode指向同一引用是错误的,如果要重复创建多个相同元素/组件,可以使用工厂函数实现

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

Vue.component('child',{
  // render: function(createElement) {
  // var myParagraphVNode = createElement('p','hello')
  // return createElement('div',
  //   [myParagraphVNode, myParagraphVNode]
  // )
  // },
  render: function(createElement) {
    return createElement('div',
      Array.apply(null, {length:20}).map(function() {
        return createElement('p','hello')
      })
    )
  },
  props: {
    level: {
      type: Number,
      required: true
    }
  }
})
new Vue({
  el:"#div1"
})

使用javascript代替模板功能,某些api要自己实现

①使用if/else代替v-if

②使用map代替v-for

Vue.component('child',{
  render: function(createElement) {
    if (this.lists.length) {
      return createElement('ul',this.lists.map(function() {
        return createElement('li','hi')
      }))
    } else {
      return createElement('p','no lists')
    }
  },
  props: {
    level: {
      type: Number,
      required: true
    }
  },
  data: function() {
    return {
      lists: [1,2,3]
    }
  }
})

// render函数中没有与v-model相应的api - 你必须自己来实现相应的逻辑:
Vue.component('child-msg',{
  render: function(createElement) {
    var self = this;
    return createElement('div', [
        createElement('input',{
          'on': {
            input: function(event) {
              self.value = event.target.value;
            }
          }
        }),createElement('p',self.value)
      ])
  },
  props: {
    level: {
      type: Number,
      required: true
    }
  },
  data: function() {
    return {
      value: ''
    }
  }
})
new Vue({
  el:"#div1"
})

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
js兼容的placeholder属性详解
Aug 18 Javascript
在页面加载完成后通过jquery给多个span赋值
May 21 Javascript
如何在MVC应用程序中使用Jquery
Nov 17 Javascript
干货分享:让你分分钟学会javascript闭包
Dec 25 Javascript
javascript 广告移动特效的实现代码
Jun 25 Javascript
jQuery+CSS3实现点赞功能
Mar 13 Javascript
详解Vue2.0里过滤器容易踩到的坑
Jun 01 Javascript
JS计算两个时间相差分钟数的方法示例
Jan 10 Javascript
vue生成token并保存到本地存储中
Jul 17 Javascript
微信小程序解除10个请求并发限制
Dec 18 Javascript
Vue项目安装插件并保存
Jan 28 Javascript
微信小程序开发实现的IP地址查询功能示例
Mar 28 Javascript
Node.js 使用命令行工具检查更新
Jun 08 #Javascript
在vue.js中抽出公共代码的方法示例
Jun 08 #Javascript
Ionic3 UI组件之autocomplete详解
Jun 08 #Javascript
jQuery+ajax实现局部刷新的两种方法
Jun 08 #jQuery
gulp解决跨域的配置文件问题
Jun 08 #Javascript
angular 用拦截器统一处理http请求和响应的方法
Jun 08 #Javascript
jQuery 添加样式属性的优先级别方法(推荐)
Jun 08 #jQuery
You might like
escape unescape的php下的实现方法
2007/04/27 PHP
SESSION存放在数据库用法实例
2015/08/08 PHP
Zend Framework教程之Application用法实例详解
2016/03/14 PHP
Thinkphp5.0框架视图view的模板布局用法分析
2019/10/12 PHP
PHP实现笛卡尔积算法的实例讲解
2019/12/22 PHP
PHP pthreads v3下同步处理synchronized用法示例
2020/02/21 PHP
javascript学习笔记(三)显示当时时间的代码
2011/04/08 Javascript
jquery 选择器引擎sizzle浅析
2013/02/06 Javascript
js四舍五入数学函数round使用实例
2014/05/09 Javascript
js实现进度条的方法
2015/02/13 Javascript
详解JavaScript中setSeconds()方法的使用
2015/06/11 Javascript
使用Node.js处理前端代码文件的编码问题
2016/02/16 Javascript
AngularJS上拉加载问题解决方法
2016/05/23 Javascript
浅谈String.valueOf()方法的使用
2016/06/06 Javascript
JS+HTML实现的圆形可点击区域示例【3种方法】
2018/08/01 Javascript
Vue前后端不同端口的实现方法
2018/09/19 Javascript
Vue封装Axios请求和拦截器的步骤
2020/09/16 Javascript
[57:29]Alliance vs KG 2019国际邀请赛小组赛 BO2 第二场 8.16
2019/08/17 DOTA
python实现mysql的单引号字符串过滤方法
2015/11/14 Python
Django REST framework视图的用法
2019/01/16 Python
Python-opencv 双线性插值实例
2020/01/17 Python
Python3 socket即时通讯脚本实现代码实例(threading多线程)
2020/06/01 Python
使用pyplot.matshow()函数添加绘图标题
2020/06/16 Python
css3实现超炫风车特效
2014/11/12 HTML / CSS
使用CSS3配合IE滤镜实现渐变和投影的效果
2015/09/06 HTML / CSS
HTML5 直播疯狂点赞动画实现代码 附源码
2020/04/14 HTML / CSS
TripAdvisor瑞典:全球领先的旅游网站
2017/12/11 全球购物
一些Unix笔试题和面试题
2013/01/22 面试题
汽车维修专业个人求职信范文
2014/01/01 职场文书
京剧自荐信
2014/01/26 职场文书
思想品德自我评价
2014/02/04 职场文书
自荐信的格式
2014/03/10 职场文书
孝敬父母的活动方案
2014/08/28 职场文书
小学运动会宣传稿
2015/07/23 职场文书
2016年3月份红领巾广播稿
2015/12/21 职场文书
电工实训心得体会
2016/01/14 职场文书