vue3的自定义渲染器解析

552 阅读2分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第5天,点击查看活动详情

原理

自定义渲染器(Renderer),可以用来自己重新定义开发渲染逻辑,它能把Vdom渲染成Web的真实Dom,将获取到的vnode对象转换到特定平台的特定操作比如:在web平台下能够将vdom渲染为真实Dom对象。我们通过下面创建canvas画布为大家一 一解析。

解析

我们建一个canvas画布,通过它来进行一些列的操作

  • 我们创建一个渲染器,需要给它提供节点和属性的操作
const { createRenderer } = Vue

给它提供节点的操作,这里创建一个nodeOps对象,方便存储

const nodeOps = {}
const renderer = createRenderer(nodeOps);

创建canvas画图工具

  1. 创建保存画布和上下文,上下文:ctx,画布:canvas
let ctx;
let canvas;
  1. 拓展mount挂载,创建一个画布元素,创建一个创建画布的方法并传入App参数,这个参数最终将通过 renderer.createApp创建并渲染。
function createCanvasApp(App) {
    const app = renderer.createApp(App);
    const mount = app.mount
    app.mount = function(selector) {
        canvas = document.createElement('canvas');
        canvas.width = window.innerWidth;
        canvas.height = window.innerHeight;
        document.querySelector(selector).appendChild(canvas);
        ctx = canvas.getContext('2d');
        mount(canvas);
    }
    return app
}

我们通过设置挂载方法mount给它添加一个属性方法,在内为其创建一个画布并设置画布的大小宽高上下文等,并将它添加到html内,最后返回出去

3.创建app实例,挂载到实例上

createCanvasApp({}).mount('#app')

此时,已经可以看到canvas,但是会报一个错误,因为我们上面的组件是空的,vue想要创建一个comment元素导致的,最后我们把这个这段写好的代码封装成一个组件bar-chart

  • 添加模板 在挂载实例中将bar-chart引入,并给它一个参数chartData这是它的最终成型主要参数,包括颜色color,大小count,还有名称Title
  <script type="text/x-template" id="chart">
    <bar-chart :data="[{ title: "⻘铜", count: 200, color: "brown" }]"></bar-chart>
  </script>
  <div id="app"></div>

节点操作实现

  1. 保存canvas实例和上下文
let ctx, canvas
  1. nodeOps详解
  • 在内定义creteElement方法(创建Dom方法),创建元素时由于没有需要创建的Dom元素,所以只需要返回当前元素的数据对象{tag}
const nodeOps = {
    createElement: (tag, isSVG, is) => {
      return {tag}
    },
}

重写insert逻辑

因为在我们的canvasApp中不存在实际dom插入操作,这里我们只需要将元素只见的父子关系保存一下即可。

const nodeOps = {
    insert: (child, parent, anchor) => {
      child.parent = parent
      if (!parent.childs) {
        parent.childs = [child]
      } else {
        parent.childs.push(child)
      }
      if (parent.nodeType === 1) {
        draw(child)
      }
    }
}

只有canvas有nodeType,所以这里(parent.nodeType === 1)就开始绘制知道内容到canvas

最后

这里是通过一个简单的实例来进行实现和分析,请掘友们多提意见,每一次进步都是成长!