ref 属性
在Vue的模板中可以通过为元素或子组件添加ref
属性(如ref="elementRefValue"
)来告诉Vue实例(或组件实例)要获取该元素。例如:
<h1 v-text="msg" ref="title"></h1> <!-- 获取Html内置标签元素 -->
<MySite ref="site"/> <!-- 获取Vue组件 -->
在Vue中,ref
属性被用来给元素或子组件注册引用信息。
然后在Vue实例或组件实例中,通过this.$refs.elementRefValue
来获取该元素或子组件的对象。例如:
this.$refs.title // 获取真实DOM元素
this.$refs.site // 获取组件实例对象
- 如果
ref
在Html内置标签上使用,那么this.$refs.elementRefValue
获取到的是该元素的真实DOM元素。 - 如果
ref
在Vue组件标签上使用,那么this.$refs.elementRefValue
获取到的是该组件的VueComponent
对象。
例如:
<template>
<div>
<h1 v-text="msg" ref="title"></h1>
<button @click="showDom">输出上方DOM</button>
<hr>
<MySite ref="site"/>
</div>
</template>
<script>
// 引入组件
import MySite from "./components/MySite.vue";
export default {
name: 'app',
components: {
MySite,
},
data() {
return {
msg: 'Hello Vue.js!',
}
},
methods: {
showDom() {
console.log(this.$refs); // 获取模板中所有使用了 ref 属性的元素或组件
console.log(this.$refs.title); // 获取真实DOM元素
console.log(this.$refs.site); // 获取组件实例对象
},
},
}
</script>
nextTick 延迟执行
假设有如下组件,需要在点击编辑按钮时显示输入框并且自动获取焦点:
<template>
<div>
<span v-show="!isEdit">{{name}}</span>
<input
v-show="isEdit"
type="text"
v-model.lazy="name"
ref="input"
@keyup.enter="handleBlur"
@blur="handleBlur"
/>
<br><br>
<button v-show="!isEdit" @click="isEdit = true">
编辑
</button>
</div>
</template>
<script>
export default {
name: 'app',
data() {
return {
name: "张三",
isEdit: false,
}
},
methods: {
handleBlur() {
this.isEdit = false
this.$ref.input.focus()
}
},
}
</script>
但是运行后发现,<input>
并不能自动获取焦点。
产生这个问题的原因是,this.$ref.input.focus()
执行的时机在组件DOM更新完成之前。即,点击编辑按钮之后,组件调用this.handleBlur()
,等到this.handleBlur()
执行完成时,组件才开始重新解析页面。
想要让this.$ref.input.focus()
在下次DOM更新完成之后才执行,可以使用Vue提供的this.$nextTick(callback)
(this
指Vue或组件实例)。
this.$nextTick(callback)
需要传入一个回调。当执行到this.$nextTick(callback)
时,Vue并不会立即执行回调,而是等到数据更新完毕,且DOM更新完成之后才执行callback
。
当
callback
使用function
定义时,callback
中的this
指向的是当前Vue或组件实例。
也就是说,this.$nextTick(callback)
可以让callback
在下一次DOM更新结束之后执行。
例如,修改上方案例中的handleBlur()
:
handleBlur() {
this.isEdit = false
// 模板重新解析完成后才自动获取焦点
// $nextTick() 指定的回调,会在下次DOM更新完成之后才执行
this.$nextTick(() => {
this.$refs.input.focus()
})
}
nextTick
的使用场景:当改变数据后,要基于更新之后的新DOM进行某些操作时。其实还有一种解决方法,就是使用一个不带时间、立即执行的定时器:
handleBlur() { this.isEdit = false setTimeout(() => { this.$refs.input.focus() }) }
这是因为
setTimeout()
即使不带时间,它也会将回调推向一个队列去执行,所以本质上来说并不算立即执行。
评论