vue3源码分析——实现createRenderer,增加runtime-test

简介: createRenderer顾名思义就是创造一个render(可以直接导出一个render函数),现在咱们的是直接在render.ts中对外导render函数出提供给createApp中使用

引言


<<往期回顾>>


1.vue3源码分析——rollup打包monorepo

2.vue3源码分析——实现组件的挂载流程

3.vue3源码分析——实现props,emit,事件处理等

4.vue3源码分析——实现slots

5.vue3源码分析——实现组件通信provide,inject


本期来实现, vue3的自定义渲染器,增加runtime-test子包,所有的源码请查看


正文


createRenderer的作用是: 实现vue3的runtime-core的核心,不只是仅仅的渲染到dom上,还可以渲染到canvas,webview等指定的平台


请思考🤔🤔🤔,createRenderer是怎么做到的呢?


设计createRenderer函数


createRenderer顾名思义就是创造一个render(可以直接导出一个render函数),现在咱们的是直接在render.ts中对外导render函数出提供给createApp中使用


418da52c7debd4c6be4223626a9a6ab1.png


对于createApp而言,需要render函数,那么咱们可以通过函数的参数穿进来,那就变成这个样子的形式


974b0dd47a5f9c76e92ce178219bd9e8.png


编码


// 通过上面的分析,先把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中就能引用啦!**😝😝😝


测试效果


623b9858082bbd85237f48fd5ea0ebf7.png


总结


本期主要实现了createRenderer函数,改造createApp等函数,通过这些函数,可以看到vu3在设计方面的用心良苦,尽量让vue3满足更多的人。增加了runtime-test,方便用于测试dom环境下面的情况!

相关文章
|
2月前
|
缓存 JavaScript UED
Vue3中v-model在处理自定义组件双向数据绑定时有哪些注意事项?
在使用`v-model`处理自定义组件双向数据绑定时,要仔细考虑各种因素,确保数据的准确传递和更新,同时提供良好的用户体验和代码可维护性。通过合理的设计和注意事项的遵循,能够更好地发挥`v-model`的优势,实现高效的双向数据绑定效果。
147 64
|
2月前
|
JavaScript 前端开发 API
Vue 3 中 v-model 与 Vue 2 中 v-model 的区别是什么?
总的来说,Vue 3 中的 `v-model` 在灵活性、与组合式 API 的结合、对自定义组件的支持等方面都有了明显的提升和改进,使其更适应现代前端开发的需求和趋势。但需要注意的是,在迁移过程中可能需要对一些代码进行调整和适配。
117 60
|
13天前
|
JavaScript API 数据处理
vue3使用pinia中的actions,需要调用接口的话
通过上述步骤,您可以在Vue 3中使用Pinia和actions来管理状态并调用API接口。Pinia的简洁设计使得状态管理和异步操作更加直观和易于维护。无论是安装配置、创建Store还是在组件中使用Store,都能轻松实现高效的状态管理和数据处理。
45 3
|
2月前
|
前端开发 JavaScript 测试技术
Vue3中v-model在处理自定义组件双向数据绑定时,如何避免循环引用?
Web 组件化是一种有效的开发方法,可以提高项目的质量、效率和可维护性。在实际项目中,要结合项目的具体情况,合理应用 Web 组件化的理念和技术,实现项目的成功实施和交付。通过不断地探索和实践,将 Web 组件化的优势充分发挥出来,为前端开发领域的发展做出贡献。
41 8
|
2月前
|
存储 JavaScript 数据管理
除了provide/inject,Vue3中还有哪些方式可以避免v-model的循环引用?
需要注意的是,在实际开发中,应根据具体的项目需求和组件结构来选择合适的方式来避免`v-model`的循环引用。同时,要综合考虑代码的可读性、可维护性和性能等因素,以确保系统的稳定和高效运行。
34 1
|
2月前
|
JavaScript
Vue3中使用provide/inject来避免v-model的循环引用
`provide`和`inject`是 Vue 3 中非常有用的特性,在处理一些复杂的组件间通信问题时,可以提供一种灵活的解决方案。通过合理使用它们,可以帮助我们更好地避免`v-model`的循环引用问题,提高代码的质量和可维护性。
45 1
|
2月前
|
JavaScript
在 Vue 3 中,如何使用 v-model 来处理自定义组件的双向数据绑定?
需要注意的是,在实际开发中,根据具体的业务需求和组件设计,可能需要对上述步骤进行适当的调整和优化,以确保双向数据绑定的正确性和稳定性。同时,深入理解 Vue 3 的响应式机制和组件通信原理,将有助于更好地运用 `v-model` 实现自定义组件的双向数据绑定。
|
2月前
|
JavaScript 索引
Vue 3.x 版本中双向数据绑定的底层实现有哪些变化
从Vue 2.x的`Object.defineProperty`到Vue 3.x的`Proxy`,实现了更高效的数据劫持与响应式处理。`Proxy`不仅能够代理整个对象,动态响应属性的增删,还优化了嵌套对象的处理和依赖追踪,减少了不必要的视图更新,提升了性能。同时,Vue 3.x对数组的响应式处理也更加灵活,简化了开发流程。
|
2月前
|
JavaScript 前端开发 API
从Vue 2到Vue 3的演进
从Vue 2到Vue 3的演进
48 0
|
2月前
|
JavaScript 前端开发 API
Vue.js响应式原理深度解析:从Vue 2到Vue 3的演进
Vue.js响应式原理深度解析:从Vue 2到Vue 3的演进
67 0

热门文章

最新文章