大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。
Jetbrains全家桶1年46,售后保障稳定
1.render简介
前面我们的组件的模板都是在模板里写的(template),模板最后都会被vue编译成virtual dom(虚拟dom),在某些情况下模板可能不好用,例如需要实现一个动态的文章标题,根据父组件的level属性,动态的渲染成h1~hx标签,用模板写部分代码如下。
<article-header :level="1">Hello world</article-header>
<script type="text/x-template" id="article-header-template"> <h1 v-if="level === 1"> <slot></slot> </h1> <h2 v-else-if="level === 2"> <slot></slot> </h2> <h3 v-else-if="level === 3"> <slot></slot> </h3> <h4 v-else-if="level === 4"> <slot></slot> </h4> <h5 v-else-if="level === 5"> <slot></slot> </h5> <h6 v-else-if="level === 6"> <slot></slot> </h6> </script>
<script> Vue.component('article-header', {
template: '#article-header-template', props: {
level: {
type: Number, required: true } } }) </script>
代码写的很死板,不灵活。这时候使用render函数会变得非常的方便。改写如下
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title></title>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
<article-title :level="level">
hello world
</title>
</div>
<script> Vue.component("article-title", {
render:function(createElement){
return createElement( 'h'+this.level, {
style:{
color:'red' } }, this.$slots.default) }, props:{
level:{
type:Number, required:true } }, data:function(){
return {
} } }); var app11 = new Vue({
el:'#app', data:{
level:1 } }) </script>
</body>
</html>
2. createElement
其实render函数返回的createElement就是一个虚拟dom,来看下广告对createElement参数描述
// @returns {VNode}
createElement(
// {String | Object | Function}
// 一个 HTML 标签名、组件选项对象,或者
// resolve 了上述任何一种的一个 async 函数。必填项。
'div',
// {Object}
// 一个与模板中属性对应的数据对象。可选。
{
// 与 `v-bind:class` 的 API 相同,
// 接受一个字符串、对象或字符串和对象组成的数组
'class': {
foo: true,
bar: false
},
// 与 `v-bind:style` 的 API 相同,
// 接受一个字符串、对象,或对象组成的数组
style: {
color: 'red',
fontSize: '14px'
},
// 普通的 HTML 特性
attrs: {
id: 'foo'
},
// 组件 prop
props: {
myProp: 'bar'
},
// DOM 属性
domProps: {
innerHTML: 'baz'
},
// 事件监听器在 `on` 属性内,
// 但不再支持如 `v-on:keyup.enter` 这样的修饰器。
// 需要在处理函数中手动检查 keyCode。
on: {
click: this.clickHandler
},
// 仅用于组件,用于监听原生事件,而不是组件内部使用
// `vm.$emit` 触发的事件。
nativeOn: {
click: this.nativeClickHandler
},
// 自定义指令。注意,你无法对 `binding` 中的 `oldValue`
// 赋值,因为 Vue 已经自动为你进行了同步。
directives: [
{
name: 'my-custom-directive',
value: '2',
expression: '1 + 1',
arg: 'foo',
modifiers: {
bar: true
}
}
],
// 作用域插槽的格式为
// { name: props => VNode | Array<VNode> }
scopedSlots: {
default: props => createElement('span', props.text)
},
// 如果组件是其它组件的子组件,需为插槽指定名称
slot: 'name-of-slot',
// 其它特殊顶层属性
key: 'myKey',
ref: 'myRef',
// 如果你在渲染函数中给多个元素都应用了相同的 ref 名,
// 那么 `$refs.myRef` 会变成一个数组。
refInFor: true
},
// {String | Array}
// 子级虚拟节点 (VNodes),由 `createElement()` 构建而成,
// 也可以使用字符串来生成“文本虚拟节点”。可选。
[
'先写一些文字',
createElement('h1', '一则头条'),
createElement(MyComponent, {
props: {
someProp: 'foobar'
}
})
]
)
render函数内返回的createElement函数的第一个参数必填,一般是标签名,第二个参数,数据对象可选参数,第三个为子级虚拟节点。
3.约束
所有组件树中,如果VNode是组件或含有组件的slot,那么Vnode必须唯一,例如。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title></title>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id='app'>
<ele></ele>
<div>
<script> var Child = {
render: function (createElement) {
return createElement("p", "text"); } }; Vue.component("ele", {
render: function (createElement) {
var ChildNode = createElement(Child); return createElement("div", [ ChildNode , ChildNode ]); } }) var app11 = new Vue({
el:'#app', data:{
} }) </script>
</body>
</html>
简单的渲染看上去没问题,但是如果使用中涉及到其他复杂的特性,就可能会出问题,
正确的渲染多个重复的组件
Vue.component("ele", {
render: function(createElement) {
return createElement("div",
Array.apply(null, {
length: 20
}).map(function() {
return createElement(child);
})
)
}
});
使用javascript代替某些模板指令,向v-if,v-for,v-model等指令在render函数中都无法使用,都需要自己用js实现相同的逻辑,这就是深入底层的代价。
例如
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title></title>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id='app'>
<ele :type="type" :len="len"></ele>
</div>
<script> var child = {
render: function(createElement) {
return createElement("p", "text"); } }; Vue.component("ele", {
render: function(createElement) {
if(this.type == 1){
return createElement("div", Array.apply(null, {
length: this.len }).map(function() {
return createElement("p","one type"); }) ); }else{
return createElement("div", Array.apply(null, {
length: this.len }).map(function() {
return createElement("p","two type"); }) ) } }, props:{
type:{
type:Number, required:true, default:1 }, len:{
type:Number, required:true, default:5 } } }); var app11 = new Vue({
el: '#app', data: {
type:2, len:6 } }) </script>
</body>
</html>
4. 在render函数中使用插槽
在render函数内,在父组件定义的插槽也是一个vnode,在render中可以通过this.$slots.插槽名去访问。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title></title>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
<article-title>
<template v-slot:default>
hello world
</template>
<template v-slot:nameslot="nameslot">
hello {
{nameslot.name}}
</template>
</title>
</div>
<script> var child = {
render: function(createElement) {
return createElement('p', 'hello'); } } Vue.component("article-title", {
render: function(createElement) {
var node = createElement(child); return createElement( 'div', [node, this.$slots.default, //向作用域插槽传值 createElement('div', [ this.$scopedSlots.nameslot({
name: 'ly' }) ]) ]) }, props: {
}, data: function() {
return {
} } }); var app11 = new Vue({
el: '#app', data: {
} }) </script>
</body>
</html>
如果要用渲染函数向子组件中传递作用域插槽,可以利用 VNode 数据对象中的 scopedSlots 字段。
5.函数式组件
函数式组件是无状态的,无实例(没有this),入参是渲染上下文context,一切的参数都通过,context传递
属性名 | 作用 |
---|---|
props | 提供所有 prop 的对象 |
children | VNode 子节点的数组 |
slots | 一个函数,返回了包含所有插槽的对象 |
scopedSlots | (2.6.0+) 一个暴露传入的作用域插槽的对象。也以函数形式暴露普通 |
data | 传递给组件的整个数据对象,作为 createElement 的第二个参数传入组件 |
parent | 对父组件的引用 |
listeners | (2.3.0+) 一个包含了所有父组件为当前组件注册的事件监听器的对象。这是 data.on 的一个别名。 |
injections | (2.3.0+) 如果使用了 inject 选项,则该对象包含了应当被注入的属性 |
组件定义时,有个functional属性设置为true就表示当前组件是一个函数式组件,render函数新增context上下文,属性如上表,返回的对象。获取默认插槽由this.$slots.default改为了context.children,context.children会返回所有子元素。
也可以用slots().default获取默认插槽,
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title></title>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
<article-title :level="level">
hello world
</title>
</div>
<script> Vue.component("article-title", {
functional:true, render:function(createElement,context){
var props = context.props; return createElement( 'h'+props.level, context.data, context.children) }, props:{
level:{
type:Number, required:true } }, data:function(){
return {
} } }); var app11 = new Vue({
el:'#app', data:{
level:1 } }) </script>
</body>
</html>
参考
https://cn.vuejs.org/v2/guide/render-function.html#slots-和-children-对比
发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/230939.html原文链接:https://javaforall.cn
【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛
【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...