博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
说说 Vue.js 中的 Render 函数
阅读量:7022 次
发布时间:2019-06-28

本文共 5712 字,大约阅读时间需要 19 分钟。

1 引子

锚点是网页中超级链接的一种,又叫命名锚记。命名锚记像一个迅速定位器一样是一种页面内的超级链接,运用相当普遍。它的英文名是 anchor。

使用命名锚记可以在文档中设置标记,这些标记通常放在文档的特定主题处或顶部。然后可以创建到这些命名锚记的链接,这些链接可快速将访问者带到指定位置。

如果把这个功能封装为组件,它一般是这样写的:

html:

6光年远“超级地球”或存在生命
研究人员发现,距离我们6光年远的一颗巨大的“超级地球”行星可能存在简单生命。Barnard b(或GJ 699 b)是最近发现的一颗围绕巴纳德星(是距离地球第二近的恒星)运行的“超级地球”行星。Barnard b被认为极度寒冷,温度与木卫二相似,约为摄氏零下150度。复制代码

js:

Vue.component('anchor', {	template: '#anchor',	props: {		level: {			type: Number,			required: true		},		title: {			type: String,			default: ''		}	}});var app = new Vue({	el: '#app',	data: {}});复制代码

当点击锚点 “6光年远“超级地球”或存在生命” 时,会跳到当前页所指定的内容。锚点粗细根据 level 值来决定。

这样写的缺点是:组件的 template 代码冗长,只有少部分不同,其它大部分都是相同的。

我们可以使用 Render 函数,通过拼接字符串的形式来构造 <h> 元素。

html:

6光年远“超级地球”或存在生命
复制代码

js:

Vue.component('anchor2', {	props: {		level: {			type: Number,			required: true		},		title: {			type: String,			default: ''		}	},	render: function (createElement) {		return createElement(			'h' + this.level,			[				createElement(					'a',					{						domProps: {							href: '#' + this.title						}					},					this.$slots.default				)			]		)	}});var app2 = new Vue({	el: '#app2',	data: {}});复制代码

效果相同,但这里的场景,使用 Render 函数明显简化了代码。

以上示例

2 createElement

我们使用 createElement 来构建 Vue.js 的 Virtual Dom 模板。

2.1 参数

createElement 有三个参数:

参数 是否必选 说明
HTML 标签、组件选项或函数 必选 -
数据对象 可选 在 template 中使用。
子节点 可选 可为 String 或 Array。

上述示例中,加上注释,我们就会更清楚一些:

return createElement(	// HTML 标签、组件选项或函数(String|Object|Function)	'h' + this.level,	//对应属性的数据对象(可选)	{},	//子节点,可为 String 或 Array	[		createElement(			'a',			{				domProps: {					href: '#' + this.title				}			},			this.$slots.default		)	])复制代码

其中的数据对象是这样的结构:

//对应属性的数据对象(可选){	//对应 v-bind:class	'class': {},	//对应 v-bind:style	style: {},	//HTML 属性	attrs: {},	//组件 props	props: {},	//DOM 属性	domProps: {},	//自定义 on 事件监听器,不支持修饰器	on: {},	//仅适用于组件,用于监听原生事件	nativeOn: {},	//自定义指令	directives: [],	//作用域 slot	// {name:props => VNode | Array
} scopedSlots: {}, //子组件中的 slot 名称(如果组件中有定义) slot: 'xxx', //其它自定义属性 xxx: 'xxx'}复制代码

在此之前,我们在 template 中都是在组件标签中使用 v-bind:class 等指令,而在 Render 函数中,这些都定义在数据对象中咯。

虽然 Render 函数灵活,但在某些场景下却显得臃肿。让我们来看一个例子,假设我们需要定义一个绑定了 class 以及 click 的简单 div 组件,如果用 template 方式,是这样编码的:

html:

复制代码

js:

Vue.component('e', {	template: '\	
后挡风玻璃上的细线竟有如此妙用
\ ', data: function () { return { isShow: true } }, methods: { click: function () { console.log('点击'); } }})var app = new Vue({ el: '#app', data: {}});复制代码

css:

.show {	cursor: pointer}复制代码

如果使用 Render 函数,那么编码方式是这样的:

Vue.component('e2',{	render:function (createElement) {		return createElement(			'div',			{				class:{					'show':this.isShow				},				attrs:{					id:'e2'				},				on:{					click:this.click				}			},			'后挡风玻璃上的细线竟有如此妙用'		)	},	...});复制代码

所以,在这个场景中,使用 template 的编码方式更简洁。

2.2 限制

组件树中,如果 VNode 是组件或者是含有组件的 slot,那么 VNode 必须唯一。

假设我们希望在子节点内渲染出两个子组件。

2.2.1 错误示例 1 —— 重复使用组件

html:

复制代码

js:

var Child3 = {	render: function (createElement) {		return createElement('p', '《怪物猎人》系列世界观设定科普');	}};Vue.component('e3',{	render: function (createElement) {		//使用组件 Child3 来创建子节点		var ChildNode= createElement(Child3);		return createElement('div',[			ChildNode,ChildNode		])	}});var app3 = new Vue({	el: '#app3',	data: {}});复制代码

渲染结果:

《怪物猎人》系列世界观设定科普

复制代码

因为受到限制,所以实际只渲染出一个子组件!

2.2.2 错误示例 2 —— 重复使用组件的 slot

html:

复制代码

js:

//全局注册组件Vue.component('Child4', {	render: function (createElement) {		return createElement('p', '高端商务本存在必要性解读:解决用户痛点更专业');	}});Vue.component('e4', {	render: function (createElement) {		return createElement('div', [			this.$slots.default,			this.$slots.default		])	}});var app4 = new Vue({	el: '#app4',	data: {}});复制代码

渲染结果:

高端商务本存在必要性解读:解决用户痛点更专业

复制代码

也是因为受到限制,所以实际只渲染出一个子组件!

有以下方法可以渲染出多个组件——

2.2.3 循环与工厂函数

html:

复制代码

js:

var Child5 = {	render: function (createElement) {		return createElement('p', '智能科技如何助力实体经济和大众创业?');	}};Vue.component('e5', {	render: function (createElement) {		return createElement('div', [			Array.apply(null, {				length: 3			}).map(function () {				return createElement(Child5);			})		])	}});var app5 = new Vue({	el: '#app5',	data: {}});复制代码

这里通过 apply 工厂函数设定了一个长度为 3 的数组,并通过 map 函数,对数组的每一项创建出子组件。

相关知识点:

  • 每个函数都包含两个非继承来的的方法:apply() 和 call(),它们都用于在特定的作用域下调用函数,实际上等于设置函数体内 this 对象的值。apply() 接收两个参数(运行函数的作用域、参数数组),其中的参数数组可以是 Array 实例,也可以是 arguments 对象。
  • map() 是迭代方法,它对数组的每一项运行给定函数,返回每次函数调用的结果组成的数组。

效果:

2.2.4 深度拷贝 slot

html:

复制代码

js:

Vue.component('Child6', {	render: function (createElement) {		return createElement('p', '线上教育发展将呈现四大趋势');	}});Vue.component('e6', {	render: function (createElement) {		//拷贝 slot 节点		function copy(vnode) {			//递归遍历所有子节点,并拷贝			const children = vnode.children && vnode.children.map(function (vnode) {				return copy(vnode);			});			const element = createElement(				vnode.tag,				vnode.data,				children			);			element.text = vnode.text;			element.isComment = vnode.isComment;			element.componentOptions = vnode.componentOptions;			element.elm = vnode.elm;			element.context = vnode.context;			element.ns = vnode.ns;			element.isStatic = vnode.isStatic;			element.key = vnode.key;			return element;		}		const vNodes = this.$slots.default;		const copyVNodes1 = vNodes.map(function (vnode) {			return copy(vnode);		});		const copyVNodes2 = vNodes.map(function (vnode) {			return copy(vnode);		});		return createElement('div', [			vNodes, copyVNodes1, copyVNodes2		])	}});var app6 = new Vue({	el: '#app6',	data: {}});复制代码

在 Render 函数中,我们创建了一个拷贝 slot 节点的工厂函数,通过递归将 slot 中的所有子节点都做了拷贝,同时还复制了 vnode 中的关键属性。这种手法主要运用于独立组件的开发。

效果:

转载地址:http://pndxl.baihongyu.com/

你可能感兴趣的文章
我的友情链接
查看>>
squid简单配置
查看>>
项目中的几个SQL程序
查看>>
2012-08-18
查看>>
shell学习笔记 (3)
查看>>
安装VirtualBox Extension Pack,让Virtualbox更好的支持USB 2.0、以及一些扩展增强功
查看>>
dpkg工具之dpkg-checkbuilddeps
查看>>
我的友情链接
查看>>
Python - 每次处理一个字符
查看>>
浅谈自动化运维
查看>>
LVS结合keepalived配置
查看>>
网站性能测试PV到TPS的转换以及TPS的波动
查看>>
umount 提示 device is busy
查看>>
支付宝和微信支付
查看>>
iptables详解与举例
查看>>
ls -l命令详解
查看>>
学习Xfire的一些体会
查看>>
redis 对list操作命令
查看>>
[转]layui数据表格(一:基础篇,数据展示、分页组件、表格内嵌表单和图片)...
查看>>
kvm创建快照与还原
查看>>