如何在 Vue 3 组合中调用渲染函数 api?

How to call render functions in Vue 3 composition api?

在 vue 2 中,我曾经这样调用 render()

export default {
    mounted(){
        ...
    },
    render(){
        ...
    },
    methods(){
        ...
    }
}

我现在正尝试对 Vue 3 和组合 api 做同样的事情。这是我尝试过的:

export default {
    ...
    setup(props, context){
        ...
        const create_canvas = (h, id, props) => {
            _id.value = id
            _attrs.value = props.attrs
            return () => h('div', {
                class: `trading-vue-${id}`,
                style: {
                    left: props.position.x + 'px',
                    top: props.position.y + 'px',
                    position: 'absolute',
                }
            }, [
                h('canvas', Object.assign({
                    id: `${props.tv_id}-${id}-canvas`,
                    onmousemove: e => renderer.mousemove(e),
                    onmouseout: e => renderer.mouseout(e),
                    onmouseup: e => renderer.mouseup(e),
                    onmousedown: e => renderer.mousedown(e),
                    ref: 'canvas',
                    style: props.style,
                }, props.attrs))
            ].concat(props.hs || []))
        };

        function render() {
            const id = props.grid_id
            const layout = props.layout.grids[id]
            return () => create_canvas(h, `grid-${id}`, {
                position: {
                    x: 0,
                    y: layout.offset || 0
                },
                attrs: {
                    width: layout.width,
                    height: layout.height,
                    overflow: 'hidden'
                },
                style: {
                    backgroundColor: props.colors.back
                },
                hs: [
                    h(Crosshair, Object.assign(
                        common_props(),
                        layer_events
                    )),
                    h(KeyboardListener, keyboard_events),
                    h(UxLayer, {
                        id,
                        tv_id: props.tv_id,
                        uxs: uxs.value,
                        colors: props.colors,
                        config: props.config,
                        updater: Math.random(),
                        onCustomEvent: emit_ux_event
                    })
                ].concat(get_overlays(h))
            })
        };

        render()
    }
}

这似乎 return 我的模板中没有任何内容。我认为我没有以正确的方式调用 render 函数。谁能帮助我了解如何使用它?

首先你不是在“调用”渲染函数——你只是在声明它(Vue 在渲染时调用它)

在作文 API 中,您只需 return render function 来自 setup

import { ref, h } from 'vue'

export default {
  props: {
    /* ... */
  },
  setup(props) {
    const count = ref(1)

    // return the render function
    return () => h('div', props.msg + count.value)
  }
}

在将这些知识应用到您自己的代码中后,我会说 setup 的最后一行不应该是 render(),而是 return render()(因为 render() 函数本身 return 实际的“渲染”功能)


在 JS 中,函数被视为数据 - 您可以将它们存储在变量中,并 return 它们来自函数。当函数作为另一个函数的结果被存储或 returned 时,它不会立即执行 - 它只会被创建。调用“工厂”函数的人(在本例中工厂函数是 setup(),调用者是 Vue)可以存储对 returned 函数的引用,并 决定何时调用它

Vue Composition API onMounted hook 的工作方式非常相似。您正在调用 onMounted() 传递一个新创建的函数作为参数。 onMounted 将函数的引用存储在某处,以便 Vue 稍后可以调用它。

重点是,在 setup() 中,onMounted() 第一个执行并且您的渲染函数 return 作为 setup 的最后一条语句并不重要.因为 Vue 决定“有时稍后”调用它们的时间。并且可以合理地期望 Vue 在调用传递给 onMounted() 的函数之前肯定会至少调用您的渲染函数一次(因为在渲染之前无法安装组件)

据我了解,h() 是创建 vnode 并接受 3 个参数的缩写形式。

h(
    tag name,
    props/attributes,
    array of children
)

据我了解,在 create_canvas 中,您正在尝试创建一个 div,其中包含 classinline styles 作为 props/attributes,我们正在创建一个 canvas 作为此 div vnode 的子节点。因此,与其直接从 setup() returning vNode,它应该 return 一个 return 是 vNode.

的渲染函数
export default {
    props: {
      // props will come here
    },
    setup(props) {
        // render() { h(...) } ❌
           return () => {
               h('div', {
                class: `trading-vue-${id}`,
                style: {
                    left: props.position.x + 'px',
                    top: props.position.y + 'px',
                    position: 'absolute',
                }
            }, [
                h('canvas', Object.assign({
                    id: `${props.tv_id}-${id}-canvas`,
                    onmousemove: e => renderer.mousemove(e),
                    onmouseout: e => renderer.mouseout(e),
                    onmouseup: e => renderer.mouseup(e),
                    onmousedown: e => renderer.mousedown(e),
                    ref: 'canvas',
                    style: props.style,
                }, props.attrs))
            ].concat(props.hs || []))
       } ✅
    }
}