vue $refs ref 属性
通过 ref 属性获取原生 DOM
步骤
在 mounted 生命周期–2种方式获取原生DOM标签: id 或 ref
- 目标标签–添加 id / ref
- 通过 id / ref 属性获取目标标签
// More.vue
<template>
<div>
<p>1.获取原生DOM元素</p>
<h1 id="h" ref="myH">我是h1标签 - 获取原生DOM元素</h1>
</div>
</template>
<script>
export default {
mounted () {
console.log(document.getElementById("h"))
console.log(this.$refs.myH)
}
}
</script>
// App.vue
<template>
<div>
<h1>$refs的使用</h1>
<More></More>
</div>
</template>
<script>
import More from './components/More.vue'
export default {
data () {
return {
}
},
components: {
More
}
}
</script>
效果
通过 ref 属性获取组件对象
步骤
- 创建 Demo 组件,写一个方法
- App.vue 使用 Demo 组件,给 ref 属性 - 名字随意(目标组件添加ref属性)
- 通过 ref 属性获取组件对象,可调用组件对象里属性 / 方法等(this.$refs.名字获取组件对象)
// Demo.vue
<template>
<div>
<p>我是Demo组件</p>
</div>
</template>
<script>
export default {
methods: {
fn () {
console.log("Demo 组件内的方法 - 被调用了")
}
}
}
</script>
// More.vue
<template>
<div>
<p>1.获取原生DOM元素</p>
<h1 id="h" ref="myH">我是h1标签 - 获取原生DOM元素</h1>
<p>2.获取组件对象 - 可调用组件内的一切</p>
<!-- 起别名:ref="de" -->
<Demo ref="de"></Demo>
</div>
</template>
<script>
import Demo from './child/Demo.vue'
export default {
mounted () {
console.log(document.getElementById("h"))
console.log(this.$refs.myH)
let demoObj = this.$refs.de
demoObj.fn()
},
components: {
Demo
}
}
</script>
效果
通过 ref 属性获取更新的 DOM
BUG效果
原因: Vue更新DOM是异步的
正确效果
步骤
- 点击修改 data,获取原生 DOM 内容
创建标签显示数据
点击+1,马上获取原生DOM内容 - 等 DOM 更新后,触发此方法里函数体执行
- 123456
语法
this.$nextTick(函数体)
<template>
<div>
<p>vue 更新 DOM 是异步的</p>
<p ref="myP">{{ count }}</p>
<button @click="btn">点击count+1,马上提前p标签内容</button>
</div>
</template>
<script>
export default {
data () {
return {
count: 0
}
},
methods: {
btn () {
this.count++ // vue检测数据更新,开启一个DOM更新队列(异步任务)
// console.log(this.$refs.myP.innerHTML) // 0
// 原因:Vue更新DOM异步
// 解决: this.$nextTick()
// 过程: DOM更新完会挨个触发 $nextTick 里的函数体
this.$nextTick(() => {
console.log(this.$refs.myP.innerHTML)
})
},
}
}
</script>
面试问点
- 可以在哪里访问到更新后的 DOM ?
this.$nextTick 里的函数体
updated 生命周期钩子函数
$nextTick 使用 - 扩展
代码
$nextTick()返回Promise配合await使用
<template>
<div>
<input ref="myInp" type="text" placeholder="这是一个输入框" v-if="isShow">
<button v-else @click="btn">点击我进行搜索</button>
</div>
</template>
<script>
// 目标: 点按钮(小时) - 输入框出现并聚焦
// 1.获取到输入框
// 2.输入框调用事件方法focus()达到聚焦行为
export default {
data() {
return {
isShow: false
}
},
methods: {
async btn() {
this.isShow = true;
// this.$refs.myInp.focus()
// 原因: data变化更新DOM是异步的
// 输入框还没有挂载到真实DOM上
// 解决:
// this.$nextTick(() => {
// this.$refs.myInp.focus()
// })
// 扩展: await取代回调函数
// $nextTick()原地返回Promise对象
await this.$nextTick()
this.$refs.myInp.focus()
}
}
}
</script>