了解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 相关文章推荐
可在线编辑网页文字效果代码(单击)
Mar 02 Javascript
二叉树的非递归后序遍历算法实例详解
Feb 07 Javascript
将HTML格式的String转化为HTMLElement的实现方法
Aug 07 Javascript
JavaScript获取图片像素颜色并转换为box-shadow显示
Mar 11 Javascript
js仿支付宝多方框输入支付密码效果
Sep 27 Javascript
完美解决IE不支持Data.parse()的问题
Nov 24 Javascript
在一个页面重复使用一个js函数的方法详解
Dec 26 Javascript
浅谈Vue 初始化性能优化
Aug 31 Javascript
JS实现图片居中悬浮效果
Dec 25 Javascript
vue中父子组件注意事项,传值及slot应用技巧
May 09 Javascript
微信小程序学习笔记之登录API与获取用户信息操作图文详解
Mar 29 Javascript
解决Vue-cli3没有vue.config.js文件夹及配置vue项目域名的问题
Dec 04 Vue.js
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
SONY ICF-SW55的电路分析
2021/03/02 无线电
PHP几个实用自定义函数小结
2016/01/25 PHP
PHP实现的微信公众号扫码模拟登录功能示例
2019/05/30 PHP
javascript 禁止复制网页
2009/06/11 Javascript
JS 遮照层实现代码
2010/03/31 Javascript
分享20多个很棒的jQuery 文件上传插件或教程
2011/09/04 Javascript
使用Jquery来实现可以输入值的下拉选单 雏型
2011/12/06 Javascript
js和css写一个可以自动隐藏的悬浮框
2014/03/05 Javascript
javascript框架设计读书笔记之模块加载系统
2014/12/02 Javascript
AngularJS基础 ng-init 指令简单示例
2016/08/02 Javascript
jQuery+ajax读取并解析XML文件的方法
2016/09/09 Javascript
jQuery.form.js插件不能解决连接超时(timeout)的原因分析及解决方法
2016/10/14 Javascript
easyUI combobox实现联动效果
2017/01/17 Javascript
jQuery EasyUI 页面加载等待及页面等待层
2017/02/06 Javascript
AngularJS的Filter的示例详解
2017/03/07 Javascript
微信小程序 template模板详解及实例代码
2017/03/09 Javascript
详解mpvue开发小程序小总结
2018/07/25 Javascript
微信小程序tabbar底部导航
2018/11/05 Javascript
JS实现将对象转化为数组的方法分析
2019/01/21 Javascript
解决Vue.js应用回退或刷新界面时提示用户保存修改问题
2019/11/24 Javascript
python通过cookie模拟已登录状态的初步研究
2016/11/09 Python
Python整数与Numpy数据溢出问题解决
2019/09/11 Python
jupyter notebook清除输出方式
2020/04/10 Python
将不规则的Python多维数组拉平到一维的方法实现
2021/01/11 Python
python切片作为占位符使用实例讲解
2021/02/17 Python
VICHY薇姿英国官网:全球专业敏感肌护肤领先品牌
2017/07/04 全球购物
Smallable英国家庭概念店:设计师童装及家居装饰
2017/07/05 全球购物
印尼极简主义和实惠的在线家具店:Fabelio
2019/03/27 全球购物
全球最大的生存食品、水和装备专用在线市场:BePrepared.com
2020/01/02 全球购物
.NET面试10题
2014/02/24 面试题
十一酒店活动方案
2014/02/20 职场文书
应届生自荐信
2014/06/30 职场文书
家庭教育的心得体会
2014/09/01 职场文书
公司车辆维修管理制度
2015/08/05 职场文书
大学生村官工作心得体会
2016/01/23 职场文书
Angular CLI发布路径的配置项浅析
2021/03/29 Javascript