模板引用(ref)新特性
模板引用(ref)新特性
Vue.js 3.x 对模板引用功能进行了重大升级,提供了更灵活、更强大的 ref 使用方式。这些改进让开发者能够更直接地操作 DOM 元素和组件实例,同时保持了 Vue 的响应式特性。
ref 基础用法
在 Vue 3 中,ref 可以通过两种方式创建:
// 选项式 API
export default {
data() {
return {
myRef: null
}
}
}
// 组合式 API
import { ref } from 'vue'
const myRef = ref(null)
在模板中使用时,只需在元素或组件上添加 ref 属性:
<template>
<div ref="myRef">这是一个可引用的元素</div>
<ChildComponent ref="childComponent" />
</template>
函数式 ref
Vue 3 引入了函数式 ref 的新写法,允许在 ref 绑定中使用函数:
<template>
<div :ref="(el) => { divElement = el }">函数式引用</div>
</template>
<script setup>
import { ref } from 'vue'
const divElement = ref(null)
</script>
这种方式特别适合动态生成 ref 的场景,例如在 v-for 循环中:
<template>
<div v-for="item in items" :key="item.id" :ref="setItemRef">
{{ item.text }}
</div>
</template>
<script setup>
import { ref, onBeforeUpdate } from 'vue'
const items = ref([/* ... */])
const itemRefs = ref([])
const setItemRef = el => {
if (el) {
itemRefs.value.push(el)
}
}
// 在更新前清空 refs 数组
onBeforeUpdate(() => {
itemRefs.value = []
})
</script>
ref 在组件上的使用
当 ref 用在组件上时,它指向的是组件实例:
<template>
<ChildComponent ref="child" />
</template>
<script setup>
import { ref, onMounted } from 'vue'
import ChildComponent from './ChildComponent.vue'
const child = ref(null)
onMounted(() => {
// 访问子组件的方法
child.value.someMethod()
// 访问子组件的属性
console.log(child.value.someProperty)
})
</script>
使用 expose 控制组件暴露内容
Vue 3 新增了 expose 选项,可以精确控制组件对外暴露的内容:
<!-- ChildComponent.vue -->
<script setup>
import { ref } from 'vue'
const internalState = ref('私有数据')
const publicMethod = () => {
console.log('这是公开方法')
}
// 只暴露 publicMethod
defineExpose({
publicMethod
})
</script>
ref 与 TypeScript 的类型推断
Vue 3 对 TypeScript 的支持更加完善,可以为 ref 提供精确的类型提示:
import { ref } from 'vue'
import type { HTMLInputElement } from 'vue'
const inputRef = ref<HTMLInputElement | null>(null)
onMounted(() => {
if (inputRef.value) {
inputRef.value.focus() // 有正确的类型提示
}
})
动态组件与 ref
动态组件上的 ref 行为有所不同,需要使用特殊处理:
<template>
<component :is="currentComponent" ref="dynamicComponent" />
</template>
<script setup>
import { ref, shallowRef } from 'vue'
import CompA from './CompA.vue'
import CompB from './CompB.vue'
const currentComponent = shallowRef(CompA)
const dynamicComponent = ref(null)
// 切换组件时 ref 会自动更新
function toggleComponent() {
currentComponent.value = currentComponent.value === CompA ? CompB : CompA
}
</script>
ref 与自定义指令
自定义指令也可以与 ref 配合使用:
<template>
<div ref="target" v-custom-directive>指令目标</div>
</template>
<script setup>
import { ref, onMounted } from 'vue'
const target = ref(null)
const vCustomDirective = {
mounted(el) {
console.log('指令挂载', el === target.value) // true
}
}
</script>
ref 在渲染函数中的使用
在渲染函数中,ref 需要作为第二个参数传递:
import { h, ref } from 'vue'
const myRef = ref(null)
export default {
setup() {
return () => h('div', { ref: myRef }, '渲染函数中的引用')
}
}
ref 与 Teleport 组件
Teleport 组件中的 ref 会指向传送后的 DOM 元素:
<template>
<Teleport to="body">
<div ref="teleported">会被传送到 body 的元素</div>
</Teleport>
</template>
<script setup>
import { ref, onMounted } from 'vue'
const teleported = ref(null)
onMounted(() => {
console.log(teleported.value.parentNode) // body
})
</script>
ref 的性能考虑
对于大型列表,使用 ref 集合可能会影响性能。Vue 提供了 ref 数组的优化方案:
<template>
<div v-for="i in 1000" :key="i" :ref="setRef">Item {{ i }}</div>
</template>
<script setup>
import { ref } from 'vue'
const refs = ref([])
function setRef(el) {
if (el) {
refs.value.push(el)
}
}
</script>
ref 与 SSR 兼容性
在服务端渲染(SSR)环境中,ref 的行为需要注意:
<script setup>
import { ref, onMounted } from 'vue'
const clientOnlyRef = ref(null)
onMounted(() => {
// 只在客户端执行
console.log(clientOnlyRef.value)
})
</script>
ref 与 Suspense 组件
在 Suspense 环境中,ref 需要等待异步组件解析完成:
<template>
<Suspense>
<template #default>
<AsyncComponent ref="asyncComp" />
</template>
</Suspense>
</template>
<script setup>
import { ref } from 'vue'
import AsyncComponent from './AsyncComponent.vue'
const asyncComp = ref(null)
// 需要等待 Suspense 解析完成
</script>
ref 的调试技巧
开发过程中可以方便地调试 ref:
import { ref } from 'vue'
const debugRef = ref(null)
// 添加 watcher 观察 ref 变化
watch(debugRef, (newVal) => {
console.log('ref 值变化:', newVal)
}, { immediate: true })
ref 与第三方库集成
与第三方库集成时,ref 提供了便捷的接入点:
<template>
<div ref="chartContainer"></div>
</template>
<script setup>
import { ref, onMounted } from 'vue'
import * as echarts from 'echarts'
const chartContainer = ref(null)
onMounted(() => {
const chart = echarts.init(chartContainer.value)
chart.setOption({/* ... */})
})
</script>
本站部分内容来自互联网,一切版权均归源网站或源作者所有。
如果侵犯了你的权益请来信告知我们删除。邮箱:cc@cccx.cn
下一篇:自定义指令变化