之前,我發了一些關於HeyUI元件庫的一些文章,有些人建議我把開發中遇到的問題共享出來,這一篇算是一個嘗試,看大家反饋,會有更多的開發知識共享。
首先,這一篇,說的是vue開發中的“深坑”,並不是有一些文章寫的“vue安裝失敗,模組找不到,或者vue-router如何定義”等等基礎錯誤。
然後,這一篇需要閱讀者對vue有著基本的瞭解,並且使用過,如果你對vue還不懂,建議先收藏,以後再看。
HeyUI
如果對我們元件庫不熟悉的小夥伴可以參見我們官網:
heyui.top
或者圍觀我們的github:
github.com/heyui/heyui
這一篇主要說的是vue使用中遇到的常見並且很難解決的錯誤,有可能系統沒有報錯,但是我們就是找不到原因。
問題一、資料修改了,但是介面仍然沒有更新
<template>
<div id="app">
<p>a:{{value.a}}</p>
<p><button @click="changeValueA">change a value</button></p>
<p><button @click="changeValueToughA">change a value use $set</button></p>
<p>b:{{value.b}}</p>
<p><button @click="changeValueB">change b value</button></p>
<p><button @click="changeValue">change value</button></p>
</div>
</template>
<script>
new Vue({
el: '#app',
data: {
value: {
b: 1
}
},
methods: {
changeValueA() {
this.value.a = new Date().getTime();
},
changeValueToughA() {
this.$set(this.value, "a", new Date().getTime())
},
changeValueB() {
this.value.b = new Date().getTime();
},
changeValue() {
this.value = {
a: 1,
b: 2
};
}
}
})
</script>
複製程式碼
如上圖所示,執行結果是:
- 直接點選
change a value
是無效的。 - 先點選
change a value
無效後,再點選change a value use $set
也會無效。 - 點選
change a value use $set
有效,並且點選過後,點選change a value
又有效了 - 點選
change value
後,點選change a value
又有效了 - 點選
change b value
一直有效
大家應該注意以下事項
-
由於在
data
下直接定義的物件,新增屬性是不會監聽的,比如說value.a
在data中其實未定義,你只有通過$set
的方式通知vue才能夠完成屬性賦值並更新檢視。 -
如果對定義的物件直接進行屬性新增,會導致
$set
也會失效。 -
如果本身data下面的物件的屬性已經定義了,對於物件屬性的變更是能夠被監聽的,比如說
value.b
,你可以直接通過修改b的值來更新檢視。 -
最後一個
changeValue
方法,是對vue data下的直接屬性進行修改,是能夠被整個監聽到,並且更新屬於value
下所有子屬性的檢視。
線上demo: codepen.io/vvpvvp/pen/…
這個主要問題是,我們開發很少用到$set,所以也很少遇到問題,但是新手成員經常幹這種事,還一臉懵逼的問題,是不是vue有問題了?
繼續,關於如何優化自己的程式碼,防止出現這種問題,往下看開發注意事項???
開發注意事項:
1、data在定義的時候,一定要把相關的資料定義全了。 因為data代表著整個模組的處理邏輯,你在下面使用$set,程式碼可讀性非常不好,更不要說,多了很多莫名其妙的bug。
2、業務物件使用資料模型定義
new Vue({
el: '#app',
data: {
page: {
page: 1,
size: 10
},
loading: false,
person: {}
},
})
複製程式碼
如上圖所示,一些常規的屬性,我們可以定義好,但是類似person
這種業務屬性,有可能幾十個欄位,我們不可能全部定義出來吧。
方法: 我們用的是js-model
來定義業務資料模型,需要定義業務物件的時候,類似Person.parse({})
就可以很好的解決問題了。
大家可以讀我寫的這一篇文章: 建立前端資料模型,vue開發必備
Basic.js
import Model from "js-model";
let Person = new Model({
"id": 0,
"description": "",
"tags": [ 0 ],
"companyId": "",
"rate": {
type: Number,
default: 0.8
},
"salary": Number
});
export default Basic;
複製程式碼
import Basic from './Person.js'
let basic = Person.parse({});
複製程式碼
basic:
{
"id": null,
"source": null,
"description": null,
"tags": [],
"companyId": null,
"rate": 0.8, // use default value
"salary": null
}
複製程式碼
實際應用:
new Vue({
el: '#app',
data: {
page: {
page: 1,
size: 10
},
loading: false,
person: Person.parse({})
},
})
複製程式碼
?
這個問題,先點到為止了,我們再繼續往下看。
問題二、v-for迴圈一定要加key
這個問題折磨了我很久,因為我真的不想加key。
但是在系統開發中,不加key是會死的,而且死的很難看,就算這樣,我們公司的程式碼中,還是有大量沒有加key的處理,其實純粹展示沒有太大問題,只是一堆warning很不爽。
我提過一些看起來很不合理的bug,但是尤作者都是以沒有加key反駁,所以我現在只能乖乖的加key了。
尤作者回復我的一些摘錄:
The last
<test-b>
belongs to the same parent with the v-for list, but is un-keyed - this makes the list "partially-keyed" and can lead to unexpected behavior.
You are using the index as the key... which is the same as no key at all. You should give each of your data objects a unique id so that they can be keyed properly.
我們來總結一下尤作者的回答:
1、如果 belongs to the same parent 同一種元件屬於同一個parent,如果不加key,lead to unexpected behavior 將會產生無法預測的行為
<template>
<div>
<ComA></ComA>
<ComA></ComA>
</div>
</template>
複製程式碼
注意:所以,以上情況,也屬於需要加key的範疇,更不要說是v-for了,不過一般情況下是不會出現問題的,如果你遇到未知的一些展示錯誤,一般加個key就可以解決(我們之前就遇到過,在渲染一個特別複雜的資料的時候,就是展示不出來,因為結構複雜,以為是程式碼的問題,調了整整一天,後期發現程式碼沒有問題,加個key就解決了)。
2、You are using the index as the key... which is the same as no key at all
你使用index作為key,其實和沒有使用key是一樣的
<template>
<div>
<ComA v-for="(item, index) of list" :key="index"></ComA>
</div>
</template>
複製程式碼
注意:以上情況,其實和沒有加key是一樣的,key必須是根據你的資料物件相關的唯一值,就是如果你不想出現bug,可以用生成的id來替代,但是,這樣修改資料的時候,整個list都會重新渲染,感人....
當然,還是建議使用資料中的id來定義key值,最方便也最安全。
線上demo: codepen.io/vvpvvp/pen/…
操作步驟:
- 點選新增*3
- 點選第一行click Me!,變成clicked
- 點選第二行click Me!,變成clicked
- 點選刪除第一行
發現clicked保留,最後一行的click Me!被刪除
如果你為v-for使用時間戳加個key,問題就會解決。
問題三、v-for迴圈中,如果有資料編輯,一定要使用物件陣列
其實這個問題是屬於上面一個問題的衍生。
之前我們有一個資料列表,需要編輯,一開始定義的就是[String]
,可是v-for是需要key的吧,你只能使用String的資料作為key。
<template>
<div id="app">
<div v-for="(item,index) of list" :key="item">
<p>{{item}}</p>
<input type="text" v-model="item">
<button @click="remove(index)">delete</button>
</div>
<button @click="add()">add</button>
</div>
</template>
<script>
new Vue({
el: '#app',
data: {
list: []
},
methods: {
add: function() {
this.list.push("string");
},
remove: function(index) {
this.list.splice(index, 1);
}
}
})
</script>
複製程式碼
too young too native
同事問我,為什麼input一編輯就blur了,呵呵呵.......
你能想象嗎?你改動了一個值,然後你自己被重新渲染了。
但是,我剛剛寫了新版本的demo,發現沒有這個問題了。
因為新版本直接error了,這樣也好,告訴了大家怎麼來修改程式碼,不會讓大家一臉懵,input一編輯就blur,你知道是為什麼嗎?
不過,現在也還是有問題的,就是v-model已經不起作用了,希望大家能注意到error中的說明。
後記
本期的總結就到這裡了,後續還有其他的總結
- vue2.0 directive如何使用
- vue v-model 實現機制
最後
希望大家多多支援我們的元件庫
HeyUI,?UI Toolkit for Web, Vue2.0