了解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 相关文章推荐
jquery分页插件AmSetPager(自写)
Apr 15 Javascript
防止按钮在短时间内被多次点击的方法
Mar 10 Javascript
基于jQuery的判断iPad、iPhone、Android是横屏还是竖屏的代码
May 11 Javascript
jQuery解析XML与传统JavaScript方法的差别实例分析
Mar 05 Javascript
js实现的页面矩阵图形变换特效
Jan 26 Javascript
jQuery遍历json的方法(推荐)
Jun 12 Javascript
ASP.NET jquery ajax传递参数的实例
Nov 02 Javascript
Javascript之面向对象--方法
Dec 02 Javascript
Bootstrap实现翻页效果
Nov 27 Javascript
Vue实现导出excel表格功能
Mar 30 Javascript
基于JS实现简单滑块拼图游戏
Oct 12 Javascript
axios如何取消重复无用的请求详解
Dec 15 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与ASP
2006/10/09 PHP
解析:通过php socket并借助telnet实现简单的聊天程序
2013/06/18 PHP
Codeigniter实现智能裁剪图片的方法
2014/06/12 PHP
PHP实现非阻塞模式的方法分析
2018/07/26 PHP
详解PHP中curl_multi并发的实现
2020/06/08 PHP
JavaScript中为元素加上name属性的方法
2011/05/09 Javascript
JavaScript单元测试ABC
2012/04/12 Javascript
引入autocomplete组件时JS报未结束字符串常量错误
2014/03/19 Javascript
JS和JQ的event对象区别分析
2014/11/24 Javascript
jQuery中$.click()无效问题分析
2015/01/29 Javascript
javascript中replace( )方法的使用
2015/04/24 Javascript
JavaScript学习笔记之检测客户端类型是(引擎、浏览器、平台、操作系统、移动设备)
2015/12/03 Javascript
从零开始学习Node.js系列教程三:图片上传和显示方法示例
2017/04/13 Javascript
Angular2生命周期钩子函数的详细介绍
2017/07/10 Javascript
Javascript ES6中对象类型Sets的介绍与使用详解
2017/07/17 Javascript
JS禁止浏览器右键查看元素或按F12审查元素自动关闭页面示例代码
2017/09/07 Javascript
Vue+axios实现统一接口管理的方法
2018/07/23 Javascript
JS实现HTML页面中动态显示当前时间完整示例
2018/07/30 Javascript
详解vue-cli3开发Chrome插件实践
2019/05/29 Javascript
微信小程序仿今日头条导航栏滚动解析
2019/08/20 Javascript
vue使用element-ui实现表单验证
2020/12/13 Vue.js
Django 添加静态文件的两种实现方法(必看篇)
2017/07/14 Python
python机器学习理论与实战(一)K近邻法
2021/01/28 Python
Python cookbook(数据结构与算法)从字典中提取子集的方法示例
2018/03/22 Python
PyQt5的安装配置过程,将ui文件转为py文件后显示窗口的实例
2019/06/19 Python
python把一个字符串切开的实例方法
2020/09/27 Python
python collections模块的使用
2020/10/16 Python
在pycharm中使用pipenv创建虚拟环境和安装django的详细教程
2020/11/30 Python
kfc实习自我鉴定
2013/12/14 职场文书
合作意向书范本
2014/03/31 职场文书
2015年学校心理健康教育工作总结
2015/05/11 职场文书
2015年度招聘工作总结
2015/05/28 职场文书
2015年个人实习工作总结
2015/05/28 职场文书
学校少先队工作总结
2015/08/12 职场文书
特别篇动画《总之就是非常可爱 ~制服~》PV公开,2022年夏季播出
2022/04/04 日漫
如何Tomcat中使用ipv6地址
2022/05/06 Servers