在 vue3 中,为了更好的实现多平台应用,将渲染器的创建函数 createRenderer 方法单独分离出来,不用像 weex 一样,需要 fork 一下,然后去改源码。

下面以 canvas 为例:

1、首先我们引用 vue3

<script src="../dist/vue.global.js"></script>

2、然后将 createRenderer 方法解构出来

const { createRenderer } = Vue

3、用 createRenderer 方法编写自己平台的渲染方法

const renderer = createRenderer({
  // 创建元素
  createElement(tag, isSVG, is) {
    return {tag}
  },
  // 插入元素
  insert(child, parent, anchor) {
    child.parent = parent
    if (!parent.childs) {
      parent.childs = []
    } else {
      parent.childs.push(child)
    }
    // 如果当前节点是画布,执行绘画逻辑
    if (parent.nodeType === 1) {
      draw(child)
    }
  },
  // 元素属性比较
  patchProp(el, key, prevValue, nextValue) {
    el[key] = nextValue
  }
  // 自己平台其它更多的操作方法
  // ...
})

创建 canvas 的绘制方法

const draw = (el, noClear) => {
  if (!noClear) {
    ctx.clearRect(0, 0, canvas.width, canvas.height)
  }
  if (el.tag === 'bar-chart') {
    const { data } = el
    const barWidth = canvas.width / 10,
      gap = 20,
      paddingLeft = (data.length * barWidth + (data.length - 1) * gap) / 3,
      paddingBootom = 10;
    
      data.forEach(({ title, count, color }, index) => {
        const x = paddingLeft + index * (barWidth + gap)
        const y = canvas.height - paddingBootom - count
        ctx.fillStyle = color
        ctx.fillRect(x, y, barWidth, count)
      })
  }

  // 递归
  el.childs && el.childs.forEach(child => draw(child, true))
}

4、创建自己平台 App 方法 createCanvasApp

let canvas, ctx;

function createCanvasApp(App) {
  const app = renderer.createApp(App)
  app.config.isCustomElement = tag => tag === 'bar-chart'

  const mount = app.mount
  // 重写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)
  }
  // 返回app,以供链式调用及摇数优化
  return app
}

5、执行 createCanvasApp 方法

createCanvasApp({
  template: '#chart',
  data() {
    return {
      chartData: [
        { title: '青铜', count: 200, color: 'red' },
        { title: '白银', count: 150, color: 'yellow' },
        { title: '黄金', count: 100, color: 'gray' },
        { title: '钻石', count: 80, color: 'green' },
        { title: '王者', count: 50, color: 'gold' }
      ]
    }
  }
}).mount('#app')

模板及 dom 元素

<div id="app"></div>

<script type="text/x-template" id="chart">
  <bar-chart :data="chartData"></bar-chart>
</script>

这里就简单实现了跨平台运用 vue3。

vue3 的跨平台自定义渲染器-风君雪科技博客