<<往期回顾>>
本期来实现, vue3的自定义渲染器,增加runtime-test子包,所有的源码请查看
createRenderer
的作用是: 实现vue3的runtime-core的核心,不只是仅仅的渲染到dom上,还可以渲染到canvas,webview等指定的平台
请思考🤔🤔🤔,createRenderer是怎么做到的呢?
createRenderer顾名思义就是创造一个render
(可以直接导出一个render函数),现在咱们的是直接在render.ts
中对外导render函数
出提供给createApp中使用
对于createApp而言,需要render函数,那么咱们可以通过函数的参数穿进来,那就变成这个样子的形式
// 通过上面的分析,先把createApp给改造一下,需要一个新的函数来包裹,并且传入render函数
export function createAppApi(render){
return function createApp(rootComponent){
// ……原有的逻辑不变
}
}
// 在createAppApi里面需要render,那就在createRenderer里面调用并且给他,
// 返回一个新的createApp
export function createRenderer(){
function render(vnode, container) {
// 调用patch
patch(vnode, container, null)
}
// ……省略其他所有的函数
return {
// 这样设计是不是对外导出了一个新的createAPP哇
createApp: createAppApi(render)
}
}
既然是自定义渲染平台,那肯定是需要修改元素的挂载逻辑,并且把需要挂载的平台给传入进来
目前代码里面默认是渲染到dom,在mountElement里面使用了document.createElement
, dom.setAttribute
, dom.innerHtml
等逻辑都是用来处理dom操作,其他的平台挂载元素的方式是不一样的,那么怎么解决这个问题呢?
需要解决这个问题,也是非常简单的,既然咱们不知道是挂载到哪里,那直接通过createRenderer
里面传入进来就ok啦😄😄😄 目前用到的主要是四个地方涉及到dom操作,把这四个地方统统封装成函数,然后通过createRenderer
里面作为options里面传入即可
在createRenderer里面加入参数options,并且结构出四个函数
export function createRenderer(options) {
const {
// 创建元素
createElement,
// 绑定key
patchProps,
// 插入操作
insert,
// 设置文本
setElementText
} = options
function mountElement(vnode: any, container: any, parentComponent) {
const el = createElement(vnode.type)
// 设置vnode的el
vnode.el = el
// 设置属性
const { props } = vnode
for (let key in props) {
patchProps(el, key, props[key])
}
// 处理子元素
const children = vnode.children
if (vnode.shapeflag & ShapeFlags.ARRAY_CHILDREN) {
// 数组
mountChildren(children, el, parentComponent)
} else if (vnode.shapeflag & ShapeFlags.TEXT_CHILDREN) {
// 自定义插入文本
setElementText(el, String(children))
}
// 挂载元素
insert(el, container)
}
}
这么改造,目前
createRenderer
的功能实现了,但是会发现所有用的createApp
的测试用例都不行了,由于咱们没目前没有对外导出createApp。
从目前来说,本块的内容可以说是 runtime-dom
,因为runtime-test
对外提供的确实是dom环境的测试,方便用于runtime-core
的测试
新建子包的过程不在这里描述哈,有兴趣的可以查看
runtime-test
需要的依赖是:
"dependencies": {
"shared":"workspace:shared@*",
"runtime-core":"workspace:runtime-core@*"
}
runtime-test
的作用是对外提供一个createApp
函数,那就需要调用createRender来创建一个customRender,customRender里面有createApp函数。 调用createRender又需要传入一个options,options是我们当前对应平台的4个函数,分别是:
function createElement(type) {
return document.createElement(type);
}
function patchProps(el, key, value) {
if (isOn(key)) {
// 注册事件
el.addEventListener(key.slice(2).toLowerCase(), value)
}
el.setAttribute(key, value)
}
function insert(el, container) {
container.append(el)
}
function setElementText(el, text) {
el.textContent = text;
}
const render: any = createRenderer({
createElement,
patchProps,
insert,
setElementText
});
// 对外导出createApp
export function createApp(...args) {
return render.createApp(...args);
}
// 需要使用runtime-core里面的所有内容,因为里面有的变量是在闭包中进行使用的
export * from 'runtime-core'
思考🤔🤗🤔: 处理完
runtime-test
就需要在runtime-core
中进行引用,直接在runtime-core中引用么?
那肯定是不行的,runtime-test
里面引用runtime-core
,如果runtime-core
在引用runtime-test
的话,那就是循环引用了,𝒮ℴ, 𝒽ℴ𝓌 𝓉ℴ 𝓇ℯ𝓈ℴ𝓁𝓋ℯ 𝒾𝓉 ?
解决方式: **在上一级的package.json上加入runtime-test这个包,那么在runtime-core中就能引用啦!**😝😝😝
本期主要实现了createRenderer函数
,改造createApp
等函数,通过这些函数,可以看到vu3在设计方面的用心良苦,尽量让vue3满足更多的人。增加了runtime-test
,方便用于测试dom环境下面的情况!