这是我参与「掘金日新计划 · 8 月更文挑战」的第3天,点击查看活动详情
$ref入门
什么是$ref?
请问大家:我们在Vue中是如何获取真实Dom元素的呢?
我们知道,js最初是为了表单校验而设计的语言,而在不停的更新过程中,js能够做的事情也越来越多,现在js已经是一款非常强大的语言了,再各类程序中都能看到js的身影,我们现在不仅可以用js写校验,还可以用来操作Dom,做动画效果,还可以写算法,js中操作Dom,只需要获取到对应的Dom元素即可,如document.getElementById('app'),js中获取Dom元素的方法有很多种,而在Vue,要获取Dom元素我们使用$ref可以更便携的获取到Dom元素,也是vue为我们提供的语法糖之一
$ref的使用
两种获取Dom标签方式对比
- 为目标标签添加上
ref/id
<p ref="myP" id="name">我叫张三</p>
- 通过
ref/id属性,获取目标标签的Dom,在生命周期中打印出来(注意:这里ref获取直接通过this.$refs.自定义ref名称获取
mounted () {
console.log(document.getElementById('name'));
console.log(this.$refs.myP);
}
完整代码为: refDemo.vue在App.vue中引用查看
<template>
<div>
<p ref="myP" id="name">我叫张三</p>
</div>
</template>
<script>
export default {
mounted () {
console.log(document.getElementById('name'));
console.log(this.$refs.myP);
}
}
</script>
<style>
</style>
这里教大家一个快捷引入的方法,以后对于组件引入这块我就不再赘述了
我们通过案例可以看到,$ref获取Dom比原生获取方式更简洁,并且效果完全一样.
通过ref获取组件对象
假如我们给vue组件给上ref\id,分别获取组件对象,会不会出现什么区别呢?
话不多说直接开干看看
App.vue中
<template>
<div>
<!-- <LifeCycle v-if="isShow"></LifeCycle>
<button @click="isShow = !isShow">显隐组件</button>-->
<ref-demo ref="refDemo" id="myRef"></ref-demo>
</div>
</template>
<script>
import LifeCycle from "./components/lifeCycle.vue";
import RefDemo from './components/refDemo.vue';
export default {
components: { LifeCycle, RefDemo },
data () {
return {
isShow: true
}
},
mounted () {
console.log(this.$refs.refDemo);
console.log(document.getElementById('myRef'));
}
}
</script>
<style>
</style>
运行可以看到效果
此时就有了差距,用ref获取到的Dom节点更清晰,有点类似我们的虚拟Dom,这还没玩,接下来我们为子组件添加上方法与属性,然后尝试使用父组件获取到的组件对象,来使用组件内的方法
refDemo.vue组件
<template>
<div>
<p ref="myP" id="name">我叫{{name}}</p>
<button @click="changeName">改名</button>
</div>
</template>
<script>
export default {
data () {
return {
name: '张三'
}
},
mounted () {
console.log(document.getElementById('name'));
console.log(this.$refs.myP);
},
methods: {
changeName () {
this.name = '李四'
}
}
}
</script>
<style>
</style>
- 吧名称抽成了一个name属性
- 添加了一个修改名称的方法,将张三修改为李四
此时我们在父组件中调用方法,App.vue
mounted () {
this.$refs.refDemo.changeName()
}
可以看到我们没有改名,名称直接发生了修改,可以证明的是我们可以直接使用ref获取到的组件对象直接调用组件内的方法
当我们使用document.getElementById获取的对象调用组件内的方法
mounted () {
document.getElementById('myRef').changeName
}
需要注意的是我们提供js获取到的Dom对象内的changeName是其中一个属性,如果我们在后面加上()就会报错,需要类似于属性的方式调用组件内的方法,所以ref不仅仅可以用来获取Dom,同时在获取组件对象使用组件内方法也有额外的处理所以推荐在Vue中关于获取元素尽量的使用ref
ref有如下优势
- 获取更便携简洁
- 调用组件内方法更语义化
- 获取到的节点信息更清晰
$nextTick入门
为什么要学习$nextTick?
还是上面的案例,当我在changeName方法中立即获取当前名称,获取到的会是修改后的名称吗?
refDemo.vue组件
changeName () {
this.name = '李四' //数据更新
console.log(this.$refs.myP.innerHTML);
}
可以发现,我们打印出来的名称依旧是张三,而非是李四,这到底是为什么呢?
因为,vue更新Dom是异步的
我们知道,js是单线程的,同步任务会在主线程从上往下执行,而异步任务会放在异步任务队列中,当主线程执行栈中的同步任务执行完毕,线程空闲了就会去执行任务队列中的异步任务
所以,更新操作并不会阻塞后面的获取值的操作,所以取到了更新前的值
我们要怎么获取到更新后的值呢? -> $nextTick
$nextTick的使用
- 语法
this.$nextTick(函数体)
this.$nextTick(() => {
console.log(this.$refs.myP.innerHTML);
})
使用箭头函数更简洁,可以看到结果就是修改后的值了
大白话的解释nextTick就是,你放在nextTick内的函数不会立即执行,Vue会尝试$nextTick内的回调函数使用原生的Promise.then、MutationObserver和setImmediate等将回调函数挂载在异步任务队列中,如果执行环境不支持,那么将会采用setTimeout(fn, 0)来替代,即:nextTick内的函数会在修改完Dom后进行操作
$nextTick的实践
我们来实现一个案例,让我们对于nextTick掌握的更深
需求:
- 提供一个按钮点击按钮变为输入框,同时输入框聚焦
这个案例我们需要用到nextTick,那么控制显影就需要用到v-if不然不会重新创建Dom那么nextTick在案例中也没有必要使用\
创建一个vue组件tickDemo.vue
<template>
<div @click="hide">
<h1>tick实例</h1>
<input ref="input" type="text" placeholder="请输入搜索关键字" v-if="isShow" />
<button v-else @click.stop="show">搜索</button>
</div>
</template>
<script>
// 点按钮 消失输入框出现并聚焦
export default {
data () {
return {
isShow: false
}
},
methods: {
show () {
this.isShow = true
this.$nextTick(() => {
this.$refs.input.focus()
})
},
hide () {
this.isShow = false
}
}
}
</script>
<style>
</style>
注意 :
- 按钮与input控制显影字段相反,实现了两者只显示一个的效果
- 按钮事件添加了
.stop修饰符防止事件冒泡 - 最大的div上添加了hide事件,这样可以让搜索框变回按钮
- 聚焦事件需要等待
Dom创建后再进行,如果此处不用nextTick获取到的Dom会是空也就没有focus方法
看看效果
来看看我的其他章节吧,正在长更中
从0到Vue3企业项目实战【01.Vue的基本概念与学习指南】 - 掘金 (juejin.cn)
从0到Vue3企业项目实战【02.了解并理解Vue指令以及虚拟Dom】 - 掘金 (juejin.cn)
从0到Vue3企业项目实战【03.vue基本api入门】 - 掘金 (juejin.cn)
从0到Vue3企业项目实战【04.从vue组件通讯到eventBus以及vuex(附mock接口与axios简单实践)】 - 掘金 (juejin.cn)
从0到Vue3企业项目实战【05.vue生命周期】 - 掘金 (juejin.cn)
从0到Vue3企业项目实战【06.nextTick使用】 - 掘金 (juejin.cn)
从0到Vue3企业项目实战【07.vue动态组件,组件缓存,组件插槽,子组件直接修改props,自定义指令看这一篇就够了】 - 掘金 (juejin.cn)