vue3源码分析——实现createRenderer,增加runtime-test
Posted twinkle||cll
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了vue3源码分析——实现createRenderer,增加runtime-test相关的知识,希望对你有一定的参考价值。
引言
<<往期回顾>>
- vue3源码分析——rollup打包monorepo
- vue3源码分析——实现组件的挂载流程
- vue3源码分析——实现props,emit,事件处理等
- vue3源码分析——实现slots
- vue3源码分析——实现组件通信provide,inject
本期来实现, vue3的自定义渲染器,增加runtime-test子包,所有的源码请查看
正文
createRenderer
的作用是: 实现vue3的runtime-core的核心,不只是仅仅的渲染到dom上,还可以渲染到canvas,webview等指定的平台
请思考🤔🤔🤔,createRenderer是怎么做到的呢?
设计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-test
从目前来说,本块的内容可以说是 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个函数,分别是:
- createElement: 创建dom
- patchProps: 处理属性
- insert: 将某个元素插入到哪里
- setElementText: 设置文本
编码
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环境下面的情况!
以上是关于vue3源码分析——实现createRenderer,增加runtime-test的主要内容,如果未能解决你的问题,请参考以下文章