Template Refs
-
定义和使用
使用 Composition API 时, reactive refs 和 template refs 的概念是统一的。为了获得对模板中元素或组件实例的引用,我们可以像往常一样声明 ref 并从 setup() 返回它:<template> <div ref="root">This is a root element</div> </template> <script> import { ref, onMounted } from 'vue' export default { setup() { const root = ref(null) onMounted(() => { // DOM元素将在初始渲染后分配给ref console.log(root.value) // <div>This is a root element</div> }) return { root } } } </script>
在这里,我们 root 在 render 上下文中进行公开,并将其绑定到 div 作为其 ref="root"。在虚拟 DOM 修补算法中,如果 VNode 的 ref 键对应于渲染上下文上的 ref,则将 VNode 的对应元素或组件实例分配给该 ref 的值。这是在虚拟 DOM 挂载/修补过程中执行的,因此模板引用将仅在初始渲染后获得分配的值。用作模板 ref 的 ref 的行为与其他任何 ref 一样:它们是 reactive 响应式的,可以传递到组合函数中(或从中返回)。
-
JSX的用法
export default { setup() { const root = ref(null) return () => h('div', { ref: root }) // with JSX return () => <div ref={root} /> } }
-
v-for 内部用法
在内部使用时,Composition API 模板引用没有特殊处理 v-for。而是使用函数 ref 来执行自定义处理:<template> <div v-for="(item, i) in list" :ref="el => { if (el) divs[i] = el }"> {{ item }} </div> </template> <script> import { ref, reactive, onBeforeUpdate } from 'vue' export default { setup() { const list = reactive([1, 2, 3]) const divs = ref([]) // make sure to reset the refs before each update onBeforeUpdate(() => { divs.value = [] }) return { list, divs } } } </script>
-
watch 模板 ref
watch 模板 ref 是否发生更改可以替代使用前面的示例中演示的生命周期挂钩。但是生命周期挂钩的主要区别在于 watch(),watchEffect() 效果是在安装或更新 DOM 之前运行的,因此当观察者运行效果时,模板 ref 尚未更新:<template> <div ref="root"> This is a root element </div> </template> <script> import { ref, watchEffect } from 'vue' export default { setup() { const root = ref(null) watchEffect(() => { //此效果会在DOM更新之前运行,因此, //模板ref尚不包含对该元素的引用。 console.log(root.value) // => null }) return { root } } } </script>
因此,应该使用 flush:'post' 选项定义使用模板引用的观察者;这将在DOM更新后运行效果,并确保 模板ref 与 DOM 保持同步并引用正确的元素。
<template> <div ref="root"> This is a root element </div> </template> <script> import { ref, watchEffect } from 'vue' export default { setup() { const root = ref(null) watchEffect(() => { console.log(root.value) // => <div></div> }, { flush: 'post' }) return { root } } } </script>