文章目录
一.ref和$refs
利用ref和$refs可以用于DOM元素或者组件实例的获取
其特点是查找的范围仅限于当前组件中,具有更精确和稳定的优点
步骤
- step1:给目标标签或组件添加ref属性
- step2:在合适的时候(DOM渲染完毕的时候)通过
this.$refs.xxx
获取目标标签或目标组件(以调用目标组件的方法)
1.使用ref和$refs获取DOM元素
示例
//html
<div ref="wineTag">把酒问青天</div>
<button ref="btn">提交</button>
//js
mounted(){
console.log(this.$refs.wineTag.innerHTML);//把酒问青天
this.$refs.btn.disabled=true;//禁用此按钮
}
2.使用ref和$refs获取组件
子组件:BaseRef.vue
//html
<div>
<h3>我是计数器--{{count}}</h3>
<button @click=increment>点击增加</button>
</div>
//js
data(){
return{
count:0,
config:{
min:0,
max:10
}
}
},
methods:{
increment(){
if(this.count<this.config.max) this.count++;
},
resetCounter(){
this.count=this.config.min;
},
changeMax(){
this.config.max=15;
}
}
父组件:App.vue
//html
//step1:通过ref标记目标组件
<base-ref ref="baseRef"></base-ref>
<button @click="getChildData">获取子组件数据</button>
<button @click="getChildResetMethod">重置计数器</button>
<button @click="getChildChangeMethod">修改最大值</button>
//js
methods:{
//step2:通过$refs调用目标组件上的方法
getChildData(){
console.log(this.$refs.baseRef.count);//当前计数
console.log(this.$refs.baseRef.config.min);//配置参数--最小值
console.log(this.$refs.baseRef.config.max);//配置参数--最大值
},
getChildResetMethod(){
this.$refs.baseRef.resetCounter();//重置计数器
},
getChildChangeMethod(){
this.$refs.baseRef.changeMax();;//修改计数器上限
}
}
二.$nextTick的介绍和使用场景
1.通过常见示例引出概念
- 需求
v-if==>标题文字和"编辑"按钮,点击后它们会消失,同时渲染v-else
v-else==>input文本框,要求让input出现的同时自动获得焦点 - 初步逻辑
//显示输入框:
this.isShowEdit=true;
//获取焦点
this.$refs.inp.focus();//在input上绑定ref="inp"
- 出现问题
input成功被渲染,但无法自动获得焦点
此时获取不到inp,打印出来是undefined - 原因分析
Vue出于提升性能的考量,是异步更新DOM的,此时input标签的DOM并未被渲染出来
(验证:在浏览器控制台的Element中,元素还是标题文字和编辑按钮这两个元素,没有input元素) - 解决方法
使用$nextTick
2.$nextTick介绍
- 作用:等DOM更新后,才会执行其函数体
- 语法:
this.$nextTick(函数体)
- 示例
this.$nextTick(()=>{
this.$refs.inp.focus();
});
- 解释
$nextTick会等DOM更新完毕,然后马上执行其函数体 - 上例完整代码
//html
<!-- 因为ref要绑定在v-if控制的元素下 -->
<div id="one" v-if="isShowEdit">
<input type="text" ref="inp">
</div>
<!-- 所以把默认状态写在v-else中 -->
<div id="two" v-else>
<span>我是标题</span>
<button @click="handleEdit">编辑</button>
</div>
//js
data:
isShowEdit:false
methods:
handleEdit(){
this.isShowEdit=true;
this.$nextTick(()=>{
this.$refs.inp.focus();
});
}
踩坑:ref必须直接绑定在v-if控制的元素上
- 总结
.- vue是异步DOM更新的
- 想在DOM更新完成后做某件事,就使用$nextTick
三.拓展
在上例中,使用$nextTick
是为了等DOM更新完毕,
在此逻辑下,可以预料到,使用延时器或者在updated()钩子函数也能解决该问题
1.使用setTimeout处理异步更新
setTimeout(()=>{
this.$refs.inp.focus();
},1000);//时间也可以改成0,但缺点仍存在
//结果:1s后input获得焦点
缺点:等待时长是不确定的(延迟时间不可控)
2.使用updated()钩子函数处理异步更新
methods:{
handleEdit(){
this.isShowEdit=true;
// this.$nextTick(()=>{
// // console.log(this.$refs.inp);
// this.$refs.inp.focus();
// });
}
},
updated(){
this.$refs.inp.focus();//成功获取焦点
}
缺点:
- 每次数据变化都会触发,需要额外状态判断
- 无法保证子组件已完成更新
3.总结三种方案的优缺点
方法 | 执行阶段 | 可靠性 | 代码耦合度 | 性能影响 |
---|---|---|---|---|
this.$nextTick | 微任务队列 | 高 | 低 | 最优 |
updated钩子 | 更新周期内 | 中 | 中 | 中等 |
setTimeout(fn,0) | 宏任务队列 | 中 | 高 | 较差 |