本文主要總結了vue實際開發項目當中應該如何解決一些實際的開發問題,可能你認爲很簡單,但短期內也許你並沒解決思路的。css
建議閱讀時間:15-25minhtml
更多精彩內容請關注我掘金主頁或者 達摩兵的空間博客vue
這種書數據的要求比較高,且要求你可以找到比較好的對應關係,須要針對class進行特徵性的組件渲染。當你須要改變時改變數據便可從新渲染達到改變樣式的目的。webpack
<li v-for="item of list" :key="item.id" :class="item.status?'color':''" @click="changeColor(item.id)">{{item.name}}</li>
return {
list:[
{id:1,status:true,name:1111},
{id:2,status:true,name:222}]
}
methods:{
changeColor(id){
this.list.map((item)=>{
if(item.id==id){
item.status=!item.status;
}
return item;
})
}
}
複製代碼
特色更加靈活,也能夠根據須要傳入你須要傳入的item屬性參數進行與class的匹配判斷,不用改變接口返回的數據結構。es6
<li v-for="item of list" :key="item.id" @click="changeColor($event)">{{item.name}}</li>
return {
list:[
{id:1,name:1111},
{id:2,name:222}]
}
changeColor(e){
let el=e.target;
if(el.classList.contains("color")){
el.classList.remove("color")
}else{
el.classList.add("color")
}
}
複製代碼
問題描述:若是你的計算屬性依賴於data的部分,而你的data對應的字段在data裏沒有申明,只是在請求接口時進行申明賦值,那麼當接口請求時,雖然數據發生了變化,可是計算屬性的值不會發生更新。web
解決方案 :須要你在data裏申明你計算屬性依賴的字段,哪怕是空或者nullnpm
問題描述 :定義了輸入框blur,再按鈕點擊事件問題,其中默認click的話,執行順序是先執行blur再執行click.若是你須要場景在點擊的時候不執行blur的事件數組
解決方案:bash
1 常規方案 : 須要吧點擊事件變成@mousedown.prevent ,前者會讓點擊優於blur執行,後者會阻止blur執行babel
2 el-input並不生效,能夠用計時器延遲執行 將失去焦點的事件計時器延遲執行,而後點擊事件裏清除定時器,也是能夠只執行點擊事件邏輯的
問題描述 :路由參數變化,可是組件沒有對應的更新,主要是由於通常獲取參數寫在了created路由鉤子函數中,路由參數變化的時候,這個生命週期不會從新執行。
解決方案:watch監聽router
watch: {
// 方法1
'$route' (to, from) { //監聽路由是否變化
if(this.$route.params.articleId){// 判斷條件1 判斷傳遞值的變化
//獲取文章數據
}
}
//方法2
'$route'(to, from) {
if (to.path == "/page") { /// 判斷條件2 監聽路由名 監聽你從什麼路由跳轉過來的
this.message = this.$route.query.msg
}
}
}
複製代碼
問題描述 : 在定時器或者其餘異步函數中使用傳統的func致使this指向不到vue實例,主要緣由是由於this指向的問題,詳細的能夠參考個人《神奇的this》這篇文章。
解決方案 :用箭頭函數或者指定變量賦值爲this(其餘一些不能用箭頭函數的地方本身也要注意)
問題描述 :一些耗費性能的計時器或者動畫在組件銷燬以後仍是執行的,致使性能變低。
解決方案 :在銷燬組件的生命週期中銷燬定時器或者一些動畫的js
//組件銷燬前執行的鉤子函數,跟其餘生命週期鉤子函數的用法相同。
beforeDestroy(){
//我一般是把setInterval()定時器賦值給this實例,而後就能夠像下面這麼中止。
clearInterval(this.intervalId);
},
複製代碼
問題描述:
This can lead to unexpected behavior when compiling on a filesystem with other case-semantic.
Use equal casing. Compare these module identifiers:
複製代碼
解決方案 :須要嚴格對應組件的大小寫,避免低級錯誤
問題描述:做爲常識咱們知道style中的樣式都會追加scoped,這樣針對模板dom中的樣式就能夠生效,但其生效後的最終樣式並非咱們寫的樣式名,而是編碼後的,因此咱們在js中拼接上的dom結構樣式並不會生效。
解決思路: 1 當添加的部分樣式不會太多,並且是動態加載的,能夠將其設置爲非scopred的
2 將添加dom部分用的樣式放到非scoped樣式標籤中
3 將添加的部分,若是有必要,能夠另外寫一個頁面拆分的vue組件
拓展 : 項目中引入的其餘ui框架的樣式,若是你想覆蓋修改,也是須要不加scoped的,若是你想整個項目覆蓋,就能夠在src/styles下定義customer-element.scss 這樣的來重寫覆蓋樣式。
問題描述 :在常規理解中,視圖與數據是雙向綁定的,可是有時候修改data的數組或者對象值,視圖不會更新 。
data() { // data數據
return {
arr: [1,2,3],
obj:{
a: 1,
b: 2
}
};
},
// 數據更新 數組視圖不更新
this.arr[0] = 'OBKoro1';
this.arr.length = 1;
console.log(arr);// ['OBKoro1'];
// 數據更新 對象視圖不更新
this.obj.c = 'OBKoro1';
delete this.obj.a;
console.log(obj); // {b:2,c:'OBKoro1'}
複製代碼
解決方案 :因爲js的限制,Vue 不能檢測以上數組的變更,以及對象的添加/刪除,不少人會由於像上面這樣操做,出現視圖沒有更新的問題。
1 this.$set(你要改變的數組/對象,你要改變的位置/key,你要改爲什麼value)
this.$set(this.arr, 0, "OBKoro1"); // 改變數組
this.$set(this.obj, "c", "OBKoro1"); // 改變對象
複製代碼
2 數組原生方法觸發視圖更新: splice()、 push()、pop()、shift()、unshift()、sort()、reverse() 推薦使用splice方法會比較好自定義,由於slice能夠在數組的任何位置進行刪除/添加操做
3 替換數組 比方說:你想遍歷這個數組/對象,對每一個元素進行處理,而後觸發視圖更新。
// 文檔中的栗子: filter遍歷數組,返回一個新數組,用新數組替換舊數組
example1.items = example1.items.filter(function (item) {
return item.message.match(/Foo/)
})
複製代碼
<div v-for="n in 5">
<span>這裏會被渲染5次,渲染模板{{n}}</span>
</div>
複製代碼
npm un babel-plugin-transform-runtime -D
,// .babelrc
{
//...
"plugins": [
// - "transform-runtime"
]
//...
}
複製代碼
npm i babel-polyfill -D
// src/main.js
import 'babel-polyfill'
複製代碼
在 ES6 中,模塊系統的導入與導出採用的是引用導出與導入(非簡單數據類型),也就是說,若是在一個模塊中定義了一個對象並導出,在其餘模塊中導入使用時,導入的實際上是一個變量引用(指針),若是修改了對象中的屬性,會影響到其餘模塊的使用。
一般狀況下,系統體量不大時,咱們可使用 JSON.parse(JSON.stringify(str)) 簡單粗暴地來生成一個全新的深度拷貝的 數據對象。不過當組件較多、數據對象複用程度較高時,很明顯會產生性能問題,這時咱們能夠考慮使用 Immutable.js。
鑑於這個緣由,進行復雜數據類型的導出時,須要注意多個組件導入同一個數據對象時修改數據後可能產生的問題。
此外,模塊定義變量或函數時即使使用 let 而不是 const,在導入使用時都會變成只讀,不能從新賦值,效果等同於用 const 聲明。
背景:在webpack的新特性中支持組件的懶加載,也就是說咱們能夠在加載到該路由的時候再把這部分腳本進行加載,同時這個在項目進行打包的時候,對應的文件也會被單獨打包,對於首屏優化以及其餘頁面的資源加載優化都是很是好的。這也要求咱們在每一個頁面組件使用組件的時候儘可能按需引入,提高體驗。
問題場景:那麼咱們須要解決的問題是: 0 webpack是靜態解析路徑的,直接傳入變量並不可行 1 每次都寫一串加載組件的代碼很不方便,是否能夠支持寫成一個加載組件的方法 2 是否支持區分生產和開發環境,由於開發環境使用懶加載會致使熱更新,致使更新變慢,因此開發環境使用全量默認加載,生產環境使用懶加載
解決方案以下 : 1 webpack的路徑使用變量拼接,必須預先給出一個相對路徑,而後把具體的組件路徑在傳入
2 用一個箭頭函數,將須要傳入的組件名或者相對路徑傳入
3 用process.env.NODE_ENV肯定使用哪一種加載方式
代碼以下: 在原來的router/index.js中,定義一個加載組件的_import方法。
// router/index.js
const _import = require('./_import_' + process.env.NODE_ENV)
//使用時
{
path: '/',
name: 'HelloWorld',
component: _import('HelloWorld')
},
// router/_import_development.js
module.exports = file => require('@/views/' + file + '.vue').default // vue-loader at least v13.0.0+
// router/_import_production.js 若是你加載的vue不是這個路徑 請自定義哦
module.exports = file => () => import('@/views/' + file + '.vue')
複製代碼
場景 :vue入門的人可能在頁面單獨引入vue的時候,直接使用data爲對象類型的,並無問題,可是在spa應用中,若是組件中的data爲對象類型就會報錯。
解決方案 :data換爲函數,返回對象類型的鍵值對。
拓展 :你可能知道要這樣作,這裏稍微科普下緣由,主要是由於根組件只會用一次,因此能夠用對象,而子組件可能在一個應用中被屢次使用,爲了不多個組件使用同一數據互相影響,因此講data約定爲了返回函數類型,返回須要的對象,以此保證子組件在數據渲染的時候不會互相影響。
場景 :在自定義組件的時候,不少時候須要將ul下的li標籤,table下的tr\td標籤進行封裝爲自定義組件,但直接使用自定義組件會致使其最終生成的位置不是咱們想要的。其標籤會渲染到tbody標籤之外。
Vue.component("row",{
template:'<tr><td>{{content}}</td></tr>',
data(){
return {
content:'this is a row'
}
},
})
複製代碼
解決方案 :緣由是由於html會進行標籤解析,tbody下的標籤必須爲tr,其餘的同理。那麼咱們能夠將其子標籤設置爲原來的標籤類型,而後用is="selfComponent" 來解決這個問題。
<tr is="row"></tr>
拓展:
Do not mount Vue to <html> or <body> - mount to normal elements instead.
場景 :雖然vue不建議直接操做dom,可是在複雜的場景中,咱們須要進行dom的操做,這時候就能夠藉助ref實現。好比下面咱們舉一個簡單的例子,經過ref獲取dom節點,拿到其內容。
解決方案 :
<div @click="handleClick" ref="hello">hello world
</div>
handleClick(){
console.log(this.$refs.hello)
}
複製代碼
代碼以下:
<counter ref="one" @change="handleChange"></counter>
<counter ref="two" @change="handleChange"></counter>
<span>{{total}}</span>
Vue.component("counter",{
template:"<div @click='change'>{{number}}</div>",
data(){
return {
number:0}
},
methods:{
change(){
this.number++;
this.$emit("change")
}
}
})
//app父組件方法
handleChange(){
this.total=this.$refs.one.number+this.$refs.two.number
},
複製代碼
拓展認知 : this.$refs.name中若是是原生標籤,拿到的是原生標籤的節點,若是是組件,拿到的是組件的引用。