Vue3之ref取render形式组件jsx元素节点

发布时间 2023-07-28 23:06:14作者: 邪妖怪

[2023 年 7 月 28 日 22:16:06]

ref 取 render 方式组件节点

一开始注意到组件 setup 和 render 一起使用的情况,好奇怎么通过 ref 取到 render 中 jsx 里的节点,一开始试了以下的尝试,结果是 undefined 的:

import { defineComponent, ref, onMounted } from "vue";

export default defineComponent({
  setup() {
    let chartRef = ref()

    onMounted(() => {
      console.log(chartRef.value); // undefined
    })

    return {
      chartRef
    }
  },
  render() {
    return <div ref={this.chartRef} style="{{ width: 200px, height: 100px }}"></div>
  },
});

后来经过大佬指点,改成以下形式:

import { defineComponent, ref, onMounted } from 'vue'

export default defineComponent({
  setup() {
    let chartRef = ref<HTMLDivElement | null>()

    onMounted(() => {
      console.log(chartRef.value) // Element div...
    })

    return {
      chartRef
    }
  },
  render() {
    return <div ref={el => this.chartRef = el} style="{{width: 200px, height: 100px}}"></div>
  }
})

render 这一步就很像 react 里 jsx 的写法了,react 里也有回调 ref,都是一样写法。回调函数参数el引用了 div 元素节点,通过赋值到chartRef。这种方式在 react 里是保持引用响应的,vue3 也是。

这种方式在 vue3 官方文档的模板引用目录里是有注明的,这里容易漏,做下记录。

渲染函数 h 引申

在以往的 vue2 中我们会看到如下的代码:

new App({
  el: "app",
  render: (h) => h(App)
});

是不是熟悉起来了? h 到底是什么意思,h => h(App)箭头函数,如果我把无语义的h参数替换成 createElement 呢?没错,就是这个意思,它是个函数,创建虚拟 dom 的函数,该函数传的参数也是有区分的:

  • 如果是组件,App就是一个组件,参数直接传组件就好;
  • 如果是标签,第一个参数是渲染的 dom 标签,第二个是渲染该标签内的内容,createElement('h1', 'Hello World!')

所以在 vue3 中,以上面的例子改写成如下:

import { defineComponent, ref, onMounted, h } from 'vue'

export default defineComponent({
  setup() {
    let chartRef = ref<HTMLDivElement | null>()

    onMounted(() => {
      console.log(chartRef.value) // Element div...
    })

    return {
      chartRef
    }
  },
  render() {
    // return <div ref={(el) => this.chartRef = el} style="{{width: 200px, height: 100px}}"></div>
    return h('div', {style : {width: '200px', height: '100px'}, ref: el => this.chartRef = el}, 'setup&render方式h函数渲染')
  }
})

setup&return 组件写法也是类似:

import { defineComponent, ref, onMounted, h } from 'vue'

export default defineComponent({
  setup() {
    let chartRef = ref<HTMLDivElement | null>()

    onMounted(() => {
      console.log(chartRef.value) // Element div...
    })

    return() => {
      return h('div', {style : {width: '200px', height: '100px'}, ref: chartRef}, 'setup&return方式h函数渲染')
    }
  }
})

相比下就是把setup外部的render配置项拿到了 setup 里用return匿名函数代替了,而且拿到setup里可以直接绑定 ref 属性。

待更正补充...