餓了麼專案---7、ref屬性註冊節點資訊,並獲取DOM節點(1)
本筆記重點:
- 如何通過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.
原因(官方解釋):
關於ref註冊時間的重要說明:因為ref本身是作為渲染結果被建立的,在初始渲染的時候你不能訪問它們 - 它們還不存在!$refs 也不是響應式的,因此你不應該試圖用它在模版中做資料繫結。
此時要使用此DOM節點是需要使用方法this.$nextTick()
該部分原理請看下一節
1.3 $nextTick 使用(1)
其實解釋起來很簡單,當把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