本笔记重点:
- 如何通过vue的refs属性获取DOM节点
- 如何在vue的示例中获取到节点元素
- 在created函数中不可使用的问题
一、refs的使用
1.1 官方介绍
被用来给元素或子组件注册引用信息。引用信息将会注册在父组件的 $refs 对象上。如果在普通的 DOM 元素上使用,引用指向的就是 DOM 元素; 如果用在子组件上,引用就指向组件实例:
<!-- vm.$refs.p will be the DOM node -->
<p ref="p">hello</p>
<!-- vm.$refs.child will be the child comp instance -->
<child-comp ref="child"></child-comp>
1.2 使用方式
通俗的解释:为想要获取的DOM节点元素添加ref属性,值为你命名的该节点名,此节点名就是你要获取的节点对象。这里有一个模仿饿了么的案例:
html代码如下:
<template>
<div class="goods">
<div ref='menuWrapper'>
....此处省略一行行行行的代码...
</div>
<div class='goodsLists' ref='foodsWrapper'>
....此处省略一行行行行的代码...
</div>
</div>
</template>
在vue1.版本中是使用的指令v-el,到了vue2.以后直接在元素上使用属性命名的方式就可以注册引用信息。在js代码中是如何获取此节点的呢?
js代码如下:
import BScroll from 'better-scroll';
export default {
name: 'goods',
props: {
seller:{
type:Object
}
},
data(){
return{
goods:[],//商品信息
listHeight:[] //每个菜单将要滑动的height
}
},
created(){
//此处为使用DOM节点的测试部分
console.log(this.$refs); //此时返回空对象
this.$nextTick(()=>{
console.log(this.$refs); //返回
})
//数据请求
this.$http.get('/api/goods').then((response)=>{
response = response.body;
if(response.errno){
this.goods =response.data;
this.$nextTick(()=>{
this._initScroll();
})
}
},(response)=>{
console.log(response)
});
},
methods:{
_initScroll() {
this.meunScroll = new BScroll(this.$refs.menuWrapper, {
});
this.foodsScroll = new BScroll(this.$refs.foodsWrapper, {
});
}
}
</script>
在 methods 中编写 _initScroll方法,获取menuWrapper 与 foodsWrapper两个节点对象,并有相关的功能,在created钩子函数中调用该函数
结果图:
在created钩子函数中一开始是获取不到包含了两个DOM节点的 this. refs对象的。当使用this. nextTick函数时,方可获取到对象节点。这是为什么呢?
原因(官方解释):
关于ref注册时间的重要说明:因为ref本身是作为渲染结果被创建的,在初始渲染的时候你不能访问它们 - 它们还不存在!$refs 也不是响应式的,因此你不应该试图用它在模版中做数据绑定。
此时要使用此DOM节点是需要使用方法this.$nextTick()
该部分原理请看下一节
1.3 $nextTick 使用(1)
其实在vuejs官网教程中的这一点已经解释的很清楚了,此处贴上链接 https://cn.vuejs.org/v2/guide/reactivity.html
其实解释起来很简单,当把javascript对象传给vue实例的data 选项,Vue将遍历此对象的所有属性,并对他们追踪依赖,属性变化和更改时都能响应变化。然而,在实例对象data以外更改它的属性,vue是无法响应的。
解决方法:使用方法Vue.set(Object,key,value) ,也可以在组件实例中直接用this代替全局vue:this.set(Object,key,value)
demo:
var vm = new Vue({
data:{
a:1
}
})
// `vm.a` 是响应的
vm.b = 2
// `vm.b` 是非响应的
Vue.set(vm.someObject, 'b', 2)
1.3 $nextTick 使用(2)
注意: Vue异步执行DOM更新
demo:
html:
<div id="example">{{message}}</div>
js:
var vm = new Vue({
el: '#example',
data: {
message: '123'
}
})
vm.message = 'new message' // 更改数据
vm.$el.textContent === 'new message' // false
Vue.nextTick(function () {
vm.$el.textContent === 'new message' // true
})
此处可以在组件实例中用this代替全局vue