了解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 function代码
May 23 Javascript
一个小型js框架myJSFrame附API使用帮助
Jun 28 Javascript
firefox下对ajax的onreadystatechange的支持情况分析
Dec 14 Javascript
海量经典的jQuery插件集合
Jan 12 Javascript
CodeMirror2 IE7/IE8 下面未知运行时错误的解决方法
Mar 29 Javascript
深入Javascript函数、递归与闭包(执行环境、变量对象与作用域链)使用详解
May 08 Javascript
javascript定义变量时有var和没有var的区别探讨
Jul 21 Javascript
跟我学习javascript的this关键字
May 28 Javascript
使用Three.js实现太阳系八大行星的自转公转示例代码
Apr 09 Javascript
Vue将页面导出为图片或者PDF
Aug 17 Javascript
jQuery事件委托代码实践详解
Jun 21 jQuery
javascript实现文字跑马灯效果
Jun 18 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
用PHP读取flv文件的播放时间长度
2009/09/03 PHP
析构函数与php的垃圾回收机制详解
2013/10/28 PHP
一个图片地址分解程序(用于PHP小偷程序)
2014/08/23 PHP
php目录遍历函数opendir用法实例
2014/11/20 PHP
ThinkPHP的常用配置选项汇总
2016/03/24 PHP
高性能Javascript笔记 数据的存储与访问性能优化
2012/08/02 Javascript
THREE.JS入门教程(4)创建粒子系统
2013/01/24 Javascript
JQuery 操作/获取table具体代码
2013/06/13 Javascript
js网页实时倒计时精确到秒级
2014/02/10 Javascript
JS实现模拟风力的雪花飘落效果
2015/05/13 Javascript
angular 动态组件类型详解(四种组件类型)
2017/02/22 Javascript
Vue.Draggable实现拖拽效果
2020/07/29 Javascript
angular学习之从零搭建一个angular4.0项目
2017/07/10 Javascript
详解webpack + vue + node 打造单页面(入门篇)
2017/09/23 Javascript
Angular 4根据组件名称动态创建出组件的方法教程
2017/11/01 Javascript
我要点爆”微信小程序云开发之项目建立与我的页面功能实现
2019/05/26 Javascript
p5.js实现故宫橘猫赏秋图动画
2019/10/23 Javascript
js实现网页随机验证码
2020/10/19 Javascript
python列表与元组详解实例
2013/11/01 Python
Python中os和shutil模块实用方法集锦
2014/05/13 Python
在Django中创建动态视图的教程
2015/07/15 Python
win7上python2.7连接mysql数据库的方法
2017/01/14 Python
pandas.DataFrame选取/排除特定行的方法
2018/07/03 Python
基于wxPython的GUI实现输入对话框(1)
2019/02/27 Python
pytorch sampler对数据进行采样的实现
2019/12/31 Python
英国领先的男士服装和时尚零售商:Burton
2017/01/09 全球购物
ZWILLING双立人法国网上商店:德国刀具锅具厨具品牌
2019/08/28 全球购物
北京银河万佳Java面试题
2012/03/21 面试题
宣传口号大全
2014/06/16 职场文书
公安学专业求职信
2014/07/27 职场文书
银行领导班子四风对照检查材料
2014/09/27 职场文书
安全生产感想
2015/08/07 职场文书
婚礼长辈答谢词
2015/09/29 职场文书
新手开公司创业注意事项有哪些?
2019/07/29 职场文书
python基于tkinter制作m3u8视频下载工具
2021/04/24 Python
spring项目中切面及AOP的使用方法
2021/06/26 Java/Android