你好,我是沐爸,欢迎点赞、收藏、评论和关注。
模板引用在 Vue 中是一个非常重要的特性,它允许我们直接访问 DOM 元素或子组件实例。Vue3.5+ 版本对模板的引用和之前的版本以及选项式API语法有所不同,一起看看吧。
一、访问模板引用
最新语法
要在组合式 API 中获取引用,我们可以使用辅助函数 useTemplateRef()<script setup>
import { useTemplateRef, onMounted } from 'vue'// 第一个参数必须与模板中的 ref 值匹配
const input = useTemplateRef('my-input')onMounted(() => {input.value.focus()
})
</script><template><input ref="my-input" />
</template>
注意,你只可以 在组件挂载后 才能访问模板引用。如果你想在模板中的表达式上访问 input
,在初次渲染时会是 null
。这是因为在初次渲染前这个元素还不存在呢!
如果你需要侦听一个模板引用 ref 的变化,确保考虑到其值为 null
的情况:
watchEffect(() => {if (input.value) {input.value.focus()} else {// 此时还未挂载,或此元素已经被卸载(例如通过 v-if 控制)}
})
3.5前的用法
<script setup>
import { ref, onMounted } from 'vue'// 声明一个 ref 来存放该元素的引用
// 必须和模板里的 ref 同名
const input = ref(null)onMounted(() => {input.value.focus()
})
</script><template><input ref="input" />
</template>
如果不使用 <script setup>
,需确保从 setup()
返回 ref:
export default {setup() {const input = ref(null)// ...return {input}}
}
选项式API语法
选项式 API 访问模板引用语法不变。<script>
export default {mounted() {this.$refs.input.focus()}
}
</script><template><input ref="input" />
</template>
二、`v-for` 中的模板引用
最新语法
当在 v-for
中使用模板引用时,对应的 ref 中包含的值是一个数组,它将在元素被挂载后包含对应整个列表的所有元素:
<script setup>
import { ref, useTemplateRef, onMounted } from 'vue'const list = ref([/* ... */
])const itemRefs = useTemplateRef('items')onMounted(() => console.log(itemRefs.value))
</script><template><ul><li v-for="item in list" ref="items">{{ item }}</li></ul>
</template>
应该注意的是,ref 数组并不保证与源数组相同的顺序。
3.5前的用法
<script setup>
import { ref, onMounted } from 'vue'const list = ref([/* ... */
])const itemRefs = ref([])onMounted(() => console.log(itemRefs.value))
</script><template><ul><li v-for="item in list" ref="itemRefs">{{ item }}</li></ul>
</template>
选项式API语法
选项式 API 访问模板引用语法不变。<script>
export default {data() {return {list: [/* ... */]}},mounted() {console.log(this.$refs.items)}
}
</script><template><ul><li v-for="item in list" ref="items">{{ item }}</li></ul>
</template>
三、组件上的 ref
最新语法
模板引用也可以被用在一个子组件上。这种情况下引用中获得的值是组件实例:
<script setup>
import { useTemplateRef, onMounted } from 'vue'
import Child from './Child.vue'const childRef = useTemplateRef('child')onMounted(() => {// childRef.value 将持有 <Child /> 的实例
})
</script><template><Child ref="child" />
</template>
如果一个子组件使用的是选项式 API 或没有使用 <script setup>
,被引用的组件实例和该子组件的 this
完全一致,这意味着父组件对子组件的每一个属性和方法都有完全的访问权。
注意,使用了 <script setup>
的组件是默认私有的:一个父组件无法访问到一个使用了 <script setup>
的子组件中的任何东西,除非子组件在其中通过 defineExpose
宏显式暴露:
<script setup>
import { ref } from 'vue'const a = 1
const b = ref(2)// 像 defineExpose 这样的编译器宏不需要导入
defineExpose({a,b
})
</script>
当父组件通过模板引用获取到了该组件的实例时,得到的实例类型为 { a: number, b: number }
(ref 都会自动解包,和一般的实例一样)。
3.5前的用法
<script setup>
import { ref, onMounted } from 'vue'
import Child from './Child.vue'const child = ref(null)onMounted(() => {// child.value 是 <Child /> 组件的实例
})
</script><template><Child ref="child" />
</template>
选项式API语法
选项式 API 访问模板引用语法不变。<script>
import Child from './Child.vue'export default {components: {Child},mounted() {// this.$refs.child 是 <Child /> 组件的实例}
}
</script><template><Child ref="child" />
</template>
好了,分享结束,谢谢点赞,下期再见。