Vue: Template Refs
2022-03-21
0. Intro
虽然 Vue 的声明式 rendering model 把很多直接的 DOM operation 都抽象化了,但我们还是可以会遇到一些情况,需要我们直接 access DOM elements。此时我们需要用 ref
attribute 来完成这件事。
<input ref="input">
what is ref
?
ref
是一个 special attribute,类似 v-for
的 key
attribute。它让我们可以获得一个 direct reference to a specific DOM element or child component instance after it’s mounted.
Note
我们只能在 component mounted 之后才能 access ref,假如我们在 template expression 里面 access ref,第一次渲染会 return null,因为只有 render 之后这个 element 才会存在。
Note that you can only access the ref after the component is mounted. If you try to access
$refs.input
in a template expression, it will benull
on the first render. This is because the element doesn’t exist until after the first render!
ref
有什么用?
假如我们想 programmatically focus an input on component mount or initialize a 3rd party library on an element.
1. Accessing the Refs
The resulting ref is exposed on this.$refs
。
<script>
export default {
mounted() {
this.$refs.input.focus()
}
}
</script>
<template>
<input ref="input" />
</template>
2. v-for
里面的 Refs
当 ref
在 v-for
里面使用的时候,resulting ref value 会是一个 array containing the corresponding elements.
而且 ref array 的顺序和 source array 不一定是一样的。
<script>
export default {
data() {
return {
list: [1, 2, 3]
}
},
mounted() {
console.log(this.$refs.items)
}
}
</script>
<template>
<ul>
<li v-for="item in list" ref="items">
{{ item }}
</li>
</ul>
</template>
3. Function Refs
ref
attribute 还可以跟 function 绑定,不一定要跟 string key 绑定。
这个 function 每当 component update 的时候就会被调用,它会给你 full flexibility on where to store the element reference.
这个 function 接收到的第一个 argument 就是 element reference。
下面的例子用的是 dynamic binding,当 element unmounted 时,argument 就会变成 null。
<input :ref="(el) => { /* assign el to a property or ref */ }">
Note we are using a dynamic
:ref
binding so we can pass it a function instead of a ref name string. When the element is unmounted, the argument will benull
. You can, of course, use a method instead of an inline function.
4. Ref on Component
ref
可以在 child component 上使用,reference 就等于是 child component instance,就等于是 child component 的 this
.
这意味着 parent component 可以 access child component 的所有 property 和 method,假如我们要 create tightly coupled implementation details between parent and child,就可以很容易实现了。
当然,component ref 也不能滥用,只有需要的时候才应该用,大多数情况下,我们都应该用 standard props and emit interfaces 来做 parent / child interactions。
<script>
import Child from './Child.vue'
export default {
components: {
Child
},
mounted() {
// this.$refs.child will hold an instance of <Child />
}
}
</script>
<template>
<Child ref="child" />
</template>
expose
option - 白名单
这个 option 可以用来限制 access to a child instance,下面的例子就是 parent 只能 access ['publicData', 'publicMethod']
, 其他都不行。
export default {
expose: ['publicData', 'publicMethod'],
data() {
return {
publicData: 'foo',
privateData: 'bar'
}
},
methods: {
publicMethod() {
/* ... */
},
privateMethod() {
/* ... */
}
}
}