了解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 相关文章推荐
javascript 遍历验证所有文本框的值
Aug 27 Javascript
JS如何将UTC格式时间转本地格式
Sep 04 Javascript
jquery form表单序列化为对象的示例代码
Mar 05 Javascript
js利用prototype调用Array的slice方法示例
Jun 09 Javascript
JS实现仿google、百度搜索框输入信息智能提示的实现方法
Apr 20 Javascript
用jquery的attr方法实现图片切换效果
Feb 05 Javascript
使用layer弹窗和layui表单实现新增功能
Aug 09 Javascript
利用vue-i18n实现多语言切换效果的方法
Jun 19 Javascript
vue-week-picker实现支持按周切换的日历
Jun 26 Javascript
Smartour 让网页导览变得更简单(推荐)
Jul 19 Javascript
如何利用node.js开发一个生成逐帧动画的小工具
Dec 01 Javascript
js中script的上下放置区别,Dom的增删改创建操作实例分析
Dec 16 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
杏林同学录(八)
2006/10/09 PHP
php输入流php://input使用浅析
2014/09/02 PHP
jquery ajax执行后台方法
2010/03/18 Javascript
jQuery EasyUI NumberBox(数字框)的用法
2010/07/08 Javascript
jQuery下的几个你可能没用过的功能
2010/08/29 Javascript
JQuery扩展插件Validate—6 radio、checkbox、select的验证
2011/09/05 Javascript
ASP.NET jQuery 实例11 通过使用jQuery validation插件简单实现用户登录页面验证功能
2012/02/03 Javascript
jquery简单的拖动效果实现原理及示例
2013/07/26 Javascript
如何正确使用javascript 来进行我们的程序开发
2014/06/23 Javascript
jquery操作checkbox示例分享
2014/07/21 Javascript
JQuery $.each遍历JavaScript数组对象实例
2014/09/01 Javascript
实现js保留小数点后N位的代码
2014/11/13 Javascript
JavaScript正则表达式中的ignoreCase属性使用详解
2015/06/16 Javascript
js实现新浪微博首页效果
2015/10/16 Javascript
JavaScript实现页面跳转的几种常用方式
2015/11/28 Javascript
Ext JS框架程序中阻止键盘触发回退或者刷新页面的代码分享
2016/06/07 Javascript
jQuery AJAX timeout 超时问题详解
2016/06/21 Javascript
使用 jQuery.ajax 上传带文件的表单遇到的问题
2016/10/31 Javascript
Javascript中数组去重与拍平的方法示例
2017/02/03 Javascript
Vue 全家桶实现移动端酷狗音乐功能
2018/11/16 Javascript
electron制作仿制qq聊天界面的示例代码
2018/11/26 Javascript
[01:44]《为梦想出发》—联想杯DOTA2完美世界全国高校联赛
2015/09/30 DOTA
[06:45]2018DOTA2亚洲邀请赛 4.5 SOLO赛 Sccc vs Maybe
2018/04/06 DOTA
浅析python实现scrapy定时执行爬虫
2018/03/04 Python
python创建文件时去掉非法字符的方法
2018/10/31 Python
Pandas 缺失数据处理的实现
2019/11/04 Python
python中lower函数实现方法及用法讲解
2020/12/23 Python
幼儿园毕业寄语
2014/04/03 职场文书
网吧消防安全责任书
2014/07/29 职场文书
2014年综合治理工作总结
2014/11/20 职场文书
大学生思想道德自我评价
2015/03/09 职场文书
2015年党建工作目标责任书
2015/05/08 职场文书
2016高中社会实践心得体会范文
2016/01/14 职场文书
2016年度继续教育学习心得体会
2016/01/19 职场文书
MySQL Threads_running飙升与慢查询的相关问题解决
2021/05/08 MySQL