【vue设计与实现】渲染器 2-自定义渲染器

下面来实现的是渲染器的跨平台能力
先从渲染一个普通的<h1>标签开始,可以用如下vnode对象来描述一个<h1>标签

const vnode = {
	type: 'h1',
	children: 'hello'
}

上面的vnode对象,使用type属性来描述vnode类型,当type属性时字符串类型值时,可以认为其描述的是普通标签,并使用该type属性的字符串值作为标签的名称。这样我们可以使用render函数来渲染,如下面代码所示:

const vnode = {
	type: 'h1',
	children: 'hello'
}
// 创建一个渲染器
const renderer = createRenderer()
// 调用render函数渲染该vnode
renderer.render(vnode, document.querySelector('#app'))

为了完成渲染工作,需要补充patch函数

function createRenderer(){
	function patch(n1,n2,container){
		// 如果n1不存在,意味着挂载,则调用mountElement函数完成挂载
		if(!n1){
			mountElement(n2,container)
		}else{
			// n1存在,意味着打补丁,暂时省略
		}
	}
	// 省略其他代码
}

当n1不存在时,意味着没有旧vnode,此时只需要执行挂载即可。这时调用mountElement完成挂载,其实现如下:

function mountElement(vnode,container){
	// 创建DOM元素
	const el = document.createElement(vnode.type)
	// 处理子节点,如果子节点是字符串,代表元素具有文本节点
	if(typeof vnode.children === 'string'){
		// 因此值需要设置元素的textContent属性即可
		el.textContent = vnode.children
	}
	// 将元素添加到容器中
	container.appendChild(el)
	
}

知识扩展
createElement() 方法通过指定名称创建一个元素
document.createElement(nodename)
nodename是创建元素的名称。

textContent 属性设置或者返回指定节点的文本内容
如果设置了 textContent 属性, 任何的子节点会被移除及被指定的字符串的文本节点替换。

上面的代码实现了挂载一个普通标签元素的工作,但是我们的目的是设计一个不依赖于浏览器平台的通用渲染器,而mountElement函数内调用了大量依赖于浏览器的api,所以第一步要做的就是将这些浏览器特有的api抽离。具体可以将这些操作DOM的API作为配置项,该配置项可以作为createRenderer的参数,如下面代码

// 创建renderer时传入配置项
const renderer = createRenderer({
	// 用于创建元素
	createElement(tag){
		return document.createElement(tag)
	},
	// 用于设置元素的文本节点
	setElementText(el,text){
		el.textContent = text
	},
	// 用于在给定的parent下添加指定元素
	insert(el,parent,anchor = null){
		parent.insertBefore(el,anchor)
	}
})

这里直接把用于操作DOM的API封装为一个对象,并将其传递给createRenderer函数。这样在mountElement等函数内就可以通过配置项来取得操作DOM的API了

function createRenderer(options){
	// 通过options得到操作DOM的API
	const{
		createElement,
		insert,
		setElementText
	} = options

	// 在这个作用域内定义的函数都可以访问那些API
	function mountElement(vnode, container){
		// ...
	}

	function patch(n1, n2, container){
		// ...
	}

	function patch(n1, n2, container){
		// ...
	}

	return {
		render
	}	
}

接着从配置项取出得到的API重新实现mountElement函数:

function mountElement(vnode, container){
	// 调用createElement函数创建元素
	const el = createElement(vnode.type)
	// 处理子节点,如果子节点是字符串,代表元素具有文本节点
	if(typeof vnode.children === 'string'){
		// 调用setElementText设置元素的文本节点
		setElement(el,vnode.children)
	}
	// 调用insert函数将元素插入到容器内
	insert(el,container)
}

这样通过传入不同的配置项,就能够完成非浏览器环境下的渲染工作。

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值