Vuetify v3(2)- useRender
如果你需要使用 setup
+ jsx
+ 暴露组件内部属性
一般来说会在 render
函数里编写 jsx
代码并返回,在 setup
中返回需要用到的属性
下面例子中的 child.tsx
为了满足上面需求,setup
暴露(返回)了所有方法
如果我们需要将 child.tsx
中 reset
,init
方法设为私有呢?
好像行不通,渲染函数只能拿到 setup
中返回的内容,此时会出现一个问题:
- 渲染函数需要的变量均需要在
setup
中返回,导致无法控制组件暴露给外部的变量
你可能会想到 setup
中返回 jsx
渲染函数,并使用 expose
暴露需要暴露的东西
但是这个方法有一个问题,使用 expose
后组件实例中以 $
开头的成员会被隐藏,导致很多高级的组件用法无法使用
例如如下代码:
1 | // test.tsx |
外部通过 <Test ref={testRef}></Test>
拿到组件实例 testRef
,其内容如下
1 | const testRef = { testData: 233 }; // 组件上的 $el, $attrs 等等都拿不到了 |
那么有无两全其美的方法呢?
useRender
会给出答案
思路
调试 vue
源码亿下,找到 setup
的实现,跟踪到 handleSetupResult
方法,发现其逻辑如下:
1 | // handleSetupResult |
然后传递 vm 实例到方法 finishComponentSetup
中进行处理
1 | // finishComponentSetup |
最后会在 renderComponentRoot
方法中调用 instance.render
渲染组件
1 | // renderComponentRoot |
简单来说就是:
vm
实例上有render
就拿来用没有就找组件上的
render
,组件上没有render
就拿组件模板编译成render
都没有那就渲染失败报错呗
到这里思路应该就很清晰了
如果我们在 setup
调用的过程中构建 render
并塞给当前 vm
实例,就可以实现在只暴露部分公开成员的同时,渲染函数能通过闭包拿到所有私有成员
实现
简单暴力,但有效
1 | import { getCurrentInstance } from 'vue'; |
从类型提示可以发现 render
并不是公开的,所以说该方法偏 Hook,说不准往后一次主版本号更新就寄了
不过既然 vuetify
这种知名项目都在使用该方法,就不用太担心了
使用
基于上面提到的 child.tsx
组件,为了方便对比源码我先贴下来
1 | import { defineComponent, ref } from 'vue'; |
我们将其改造成只暴露 title
成员
1 | import { defineComponent, ref } from 'vue'; |
此时父组件拿到的 Child
实例如下
1 | const childRef = { |
完美