Vue render 函数

render 函数的初步了解

我们通过下面的 demo 对 render 函数进行初步了解,其需求是传递不同的参数渲染不同的标签

组件实现

<div id="app"> 
  <my-component :level="level">我是 demo</my-component>
</div>

<template id="demo">
  <div>
    <h1 v-if="level == 1">
      <slot></slot>
    </h1>
    <h2 v-if="level == 2">
      <slot></slot>
    </h2>
    <h3 v-if="level == 3">
      <slot></slot>
    </h3>
  </div>
</template>

<script>
Vue.component('my-component', {
  props: ['level'],
  template: '#demo',
  created: function() {
  	console.log(this.level)
  }
})

var app = new Vue({
  el: '#app',
  data: {
  	level: 2
  }
})
</script>

render 函数实现

<div id="app">
  <render-component :level="level">我是 render</render-component>
</div>

<script>
Vue.component('render-component', {
	props: ['level'],
	render: function(createElement) {
  	return createElement('h' + this.level, this.$slots.default)
  }
})

var app = new Vue({
  el: '#app',
  data: {
  	level: 2
  }
})
</script>

显然可以看到组件需要很多代码的事情,render 函数可以简单做到,这对工程量较大的项目来说,着实是一个福利,避免了太多冗余代码的存在。

render 函数的第一个参数

在 render 函数的使用中,render 函数的参数必须是 createElementcreateElement 的类型是 function,第一个参数 (必选) 可以是 String | Object | Function。

Vue.component({
  render: function(createElement) {
    // 当参数为 String,为 html 标签
	// return createElement('h1')

	// 当参数为 Object,为一个含有数据选项的对象
	// return createElement({
	//   template: '<div></div>'
	// })

	// 当参数为 Function,返回一个含有数据选项的对象
	var func = function() {
	  return {
		template: '<p>函数</p>'
	  }
	}
	return createElement(func())
  }
})

render 函数的第二个参数

render 函数的第二个参数是可选的,是数据对象,只能是 Object。

看 demo 和 注释,这里列举 4 个选项

Vue.component('child', {
  render: function(createElement) {
	return createElement({
      template: '<div>我是div</div>'
    }, {
      'class': { 
        div1: true,  // 有 div1 这个 class
        div2: false  // 无
      },
      style: {
        color: 'red',
        fontSize: '20px'
      },
	  // 正常的 html 特性
      attrs: {
        id: 'demo1',   // id="demo1"
        // src: 'https://www.baidu.com'  img 等可以有这个特性
      },
	  // 原生的 DOM 属性
      domProps: {
        innerHTML: '<span style="color: blue; font-size: 14px">我是span</span>'
      }
    })
  }
})

render 函数的第三个参数

render 函数的第三个参数也是可选的,可以是 String | Array(用的多些),作为构建函数的子节点

Vue.component('third', {
	render: function(createElement) {
  	return createElement('div', [
      createElement('h1', '我是 h1'),
      createElement('h4', '我是 h4')
    ])
  }
})

上面的 demo 两次使用到了第三个参数,因为第二个参数只能是 Object 类型,所以传递的不是 Object 则默认没有传递第二个参数。

创建出的 DOM 结构为:

<div>
  <h1>我是 h1</h1>
  <h4>我是 h4</h4>
</div>

this.$slots 在 render 函数中的使用

<div id="app">
  <slot-render>
    <p>我是第一段</p>
    <p>我是第二段</p>
    <h1 slot="header">我是header标题</h1>
    <span slot="footer">我是footer结尾</span>
  </slot-render>
</div>

<script>
  Vue.component('slot-render', {
	render: function(createElement) {
      var header = this.$slots.header
      var main = this.$slots.default
      var footer = this.$slots.footer
    
      return createElement('div', [
        createElement('header', header),
        createElement('main', main),
        createElement('footer', footer)
      ])
   }
})
</script>

其中,this.$slots.header 返回的内容就是含有 VNODE 虚拟节点的数组,而方法 createElement('header', header) 返回的就是 VNODE,所以由此可知 render 函数的第三个参数存的就是 VNODE。

在使用 JS 操作 DOM 树时,会发生重绘;而 VNODE 虚拟节点在与页面双向绑定之后,VueJS 会自动检测哪个 VNODE 发生改变,就更新哪个 VNODE,效率比重绘高很多很多。

在 render 函数中使用 props 传递数据

<div id="app">
  <p>通过 props 在render 函数中传递数据 {{level}}</p>
  <button @click="switchImg">切换图片</button>
  <switchimg :imgno="level"></switchimg>
</div>

<script>
Vue.component('switchimg', {
	props: ['imgno'],
	render: function(createElement) {
  	var imgsrc 
  	if (this.imgno === 1) {
    	imgsrc = 'https://cn.bing.com/th?id=OIP.YAAQjUro7iesK4rOUHYVjgHaEo&pid=Api&rs=1'
    } else {
    	imgsrc = 'https://cn.bing.com/th?id=OIP.3y5dDQmWRxPX1cOLmzZwIAHaEo&pid=Api&rs=1'
    }
    return createElement('img', {
    	attrs: {
      	src: imgsrc
      },
      style: {
      	width: '300px',
        height: '200px'
      }
    })
  }
})

var app = new Vue({
	el: '#app',
  data: {
  	level: 1
  },
  methods: {
  	switchImg: function() {
    	this.level = -this.level
    }
  }
})
</script>

v-model 在 render 函数中的使用

<div id="app">
  <model-component v-model="msg"></model-component>
  {{msg}}
</div>

Vue.component('model-component', {
  props: ['msg'],
  render: function(createElement) {
  	var self = this
    console.log(this)  // vue.component
    return createElement('input', {
      domProps: {
        value: self.msg
      },
      on: {
      	input: function(event) {
		    console.log(this)    // window
      	  self.$emit('input', event.target.value)
        }
      }
    })
  }
})

var app = new Vue({
  el: '#app',
  data: {
    msg: '这是 v-model 在 render 函数中使用的示例'
  }
})

作用域插槽

通过 this.$scopedSlots.default 向父组件插槽传递数据

<slot-component>
    <template slot-scope="props">
      id: {{props.id}}
      {{props.text}}
    </template>
</slot-component>

Vue.component('slot-component',{
	render: function(createElement) {
  	return createElement('p', this.$scopedSlots.default({
        text: '我使来自子组件的数据',
        id: 1
      }))
  } 
})

函数化组件的应用

通过下面代码中两个 console.log(this) 可以表明函数化,拿到的都是 window;

context 代表的是上下文对象,包括子组件和父组件中的所有内容;

Vue.component('func-component', {
  functional: true,  // 函数化,表示当前组件无状态、无实例
  props: ['msg'],
  render: function(createElement, context) {
    console.log(this)  // window
    return createElement('button', {
    	on: {
          click: function() {
        	console.log(this)   // window
            console.log(context)  // 上下文对象
            console.log(context.parent)  // 父组件
            console.log(context.props.msg)  // 父组件给子组件传递的数据 msg
        }
      }
    }, "点击查看 context")
  }
})

使用函数化之后的转变:

this.msg ----- context.props.msg
this.$slots.default ----- context.children  // 默认插槽
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值