本文翻译自 Make Vue’s template refs clean & simple,作者:Roobin S?n, 略有删改。
在Vue项目中有时候我们可能需要直接访问模板中的DOM元素。一个常见的用例是,当我们为组件定义expose(defineExposes
)时,父组件需要访问该组件来调用已暴露的函数或属性。
当我第一次使用Vue的template refs
时,我感觉有些奇怪。这是一个例子:
<template>
<input ref="input" />
</template>
setup 脚本:
<script setup>
import { ref, onMounted } from 'vue'
const input = ref(null)
onMounted(() => {
input.value.focus()
})
</script>
这里有2个问题:
问题1:为什么模板中的input
是const
字符串,而设置脚本中的input
是ref
变量?为什么我们不能像:ref="input"
那样传递ref
变量,而不是总是记住我们需要让脚本中的变量名和模板中的字符串相同?如果你使用Typescript
比较多,你会觉得这很奇怪。
问题2:为什么我们需要调用input.value
来访问组件?在大多数情况下,这个模板ref
通常是不变的,所以调用.value
是不必要的。我们不需要它是一个可变的ref
变量,我们只希望它是一个常量。
在尝试了一些方法,如使用反应,常量,…我终于为这个问题做了一个实用程序,只有10行代码。
import { reactive } from 'vue'
export const useRefs = <T extends object>() => {
const refs = reactive<T>({} as T)
const toRef = (refName: keyof T) => (el: any) => ((refs as T)[refName as keyof T] = el)
return {
refs,
toRef,
}
}
使用方式:
<template>
<input :ref="toRef('input')" />
</template>
<script setup lang="ts">
import { onMounted } from 'vue'
import { useRefs } from '@common/utils/useRefs'
const { refs, toRef } = useRefs<{
input: InstanceType<typeof HTMLInputElement>
}>()
onMounted(() => {
refs.input.focus()
})
</script>
上述方案有几个有点:
input
现在只是一个对象的常量。IDE可以很容易地理解它,所以在IDE中输入的提示就是一个很不错的体验。例如:focus()
输入为focuses()
时:只需要几行代码,Vue的模板引用的问题就变成了零。更少的IDE警告、更少的未知错误和更安全的类型检查。这个解决方案使我在使用模板引用时更加舒适。
希望这对你也有帮助,如果你有更好的解决办法,欢迎留言交流。
看完本文如果觉得有用,记得点个赞支持,收藏起来说不定哪天就用上啦~
专注前端开发,分享前端相关技术干货,公众号:南城大前端(ID: nanchengfe)