自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

不可錯(cuò)過的 vue 開發(fā)技巧

原創(chuàng)
開發(fā) 前端
本文主要介紹日常項(xiàng)目開發(fā)過程中的一些技巧,幫助大家規(guī)避錯(cuò)誤的同時(shí)還能提高應(yīng)用的性能。以下是我總結(jié)一些平時(shí)工作中的經(jīng)驗(yàn)。

【51CTO.com原創(chuàng)稿件】

前言

本文主要介紹日常項(xiàng)目開發(fā)過程中的一些技巧,幫助大家規(guī)避錯(cuò)誤的同時(shí)還能提高應(yīng)用的性能。以下是我總結(jié)的一些平時(shí)工作中的經(jīng)驗(yàn)。

在v-if/v-if-else/v-else中使用key

如果一組v-if 與v-else的元素類型相同,最好使用屬性key。這是因?yàn)閂ue2.0引入虛擬DOM,為了避免不必要的DOM操作,虛擬DOM在虛擬節(jié)點(diǎn)映射到視圖過程中,將虛擬節(jié)點(diǎn)與上一次渲染視圖所使用的舊虛擬節(jié)點(diǎn)做對(duì)比,找出真正需要更新的節(jié)點(diǎn)來進(jìn)行DOM操作。但有時(shí)如果兩個(gè)本不相同的節(jié)點(diǎn)被識(shí)別為相同,便會(huì)出現(xiàn)意料之外的問題。我們看下面的一個(gè)例子:

  1. // 這種寫法會(huì)出bug 
  2. <div v-if="flag"
  3.   <label>浪里行舟</label> 
  4.   <input type="text" /> 
  5. </div> 
  6. <div v-else
  7.   <label>前端工匠</label> 
  8.   <input type="text" /> 
  9. </div> 
  10. <button @click="flag = !flag">切換</button>  

如果添加了屬性key,那么在對(duì)比虛擬DOM時(shí),則會(huì)認(rèn)為它們是兩個(gè)不同的節(jié)點(diǎn),于是會(huì)將舊元素移除并在相同位置添加新元素,從而避免漏洞的出現(xiàn)。

  1. // 最佳寫法 
  2. <div v-if="flag"
  3.   <label>浪里行舟</label> 
  4.   <input key="1" type="text" /> 
  5. </div> 
  6. <div v-else
  7.   <label>前端工匠</label> 
  8.   <input key="2" type="text" /> 
  9. </div> 
  10. <button @click="flag = !flag">切換</button> 

v-for循環(huán)中不要使用index作為key

我們會(huì)給列表渲染設(shè)置屬性key,這個(gè)key屬性主要用在虛擬DOM算法上,在對(duì)比新舊虛擬節(jié)點(diǎn)時(shí)辨識(shí)虛擬節(jié)點(diǎn)。但如果key用得不合理,就會(huì)出現(xiàn)bug,比如我們使用index作為key(見下面例子),核心代碼如下:

  1. <div class="border"
  2.   <Children v-for="(key, index) in list" :key="index">//使用index作為key 
  3.     <button @click="() => handleDelete(key)">刪除</button> 
  4.   </Children> 
  5.   <button @click="handleAdd">添加</button> 
  6. </div> 
  7. ...... 
  8.   handleAdd() { 
  9.     this.list.push(key++); 
  10.   }, 
  11.   handleDelete(key) { 
  12.     const index = this.list.findIndex(k => k === key); 
  13.     this.list.splice(index, 1); 
  14.   } 

上例中,我們想刪除第二個(gè)輸入框,卻誤刪了第三個(gè)輸入框,這因?yàn)楫?dāng)使用splice()方法刪除數(shù)組的某個(gè)元素時(shí)數(shù)組的index會(huì)被重新索引,造成數(shù)組的最后一個(gè)index丟失,從而會(huì)使虛擬DOM的最后一個(gè)結(jié)點(diǎn)(key)丟失,造成無論刪除哪個(gè)結(jié)點(diǎn)都會(huì)誤刪除最后一個(gè)結(jié)點(diǎn)的bug。但如果我們使用傳入的key作為key,就可以避免這種問題出現(xiàn)。

  1. <div class="border"
  2.   <Children v-for="key in list" :key="key"
  3.     <button @click="() => handleDelete(key)">刪除</button> 
  4.   </Children> 
  5.   <button @click="handleAdd">添加</button> 
  6. </div> 

簡單暴力的router key

我們?cè)陧?xiàng)目開發(fā)時(shí),可能會(huì)遇到這樣問題:當(dāng)頁面切換到同一個(gè)路由但不同參數(shù)地址時(shí),比如/detail/1,跳轉(zhuǎn)到/detail/2,頁面跳轉(zhuǎn)后數(shù)據(jù)竟然沒更新?路由配置如下:

  1.     path: "/detail/:id"
  2.     name:"detail"
  3.     component: Detail 

這是因?yàn)関ue-router會(huì)識(shí)別出兩個(gè)路由使用的是同一個(gè)組件從而進(jìn)行復(fù)用,并不會(huì)重新創(chuàng)建組件,而且組件的生命周期鉤子自然也不會(huì)被觸發(fā),導(dǎo)致跳轉(zhuǎn)后數(shù)據(jù)沒有更新。那我們?nèi)绾谓鉀Q這個(gè)問題呢? 我們可以為router-view組件添加屬性key,例子如下: 

  1. <router-view :key="$route.fullpath"></router-view

這種辦法主要是利用虛擬DOM在渲染時(shí)候通過key來對(duì)比兩個(gè)節(jié)點(diǎn)是否相同,如果key不相同,就會(huì)判定router-view組件是一個(gè)新節(jié)點(diǎn),從而先銷毀組件,然后再重新創(chuàng)建新組件,這樣組件內(nèi)的生命周期會(huì)重新觸發(fā)。

路由懶加載

當(dāng)打包構(gòu)建應(yīng)用時(shí),JavaScript 包會(huì)變得非常大,影響頁面加載。如果我們能把不同路由對(duì)應(yīng)的組件分割成不同的代碼塊,然后當(dāng)路由被訪問的時(shí)候才加載對(duì)應(yīng)組件,這樣就更加高效了。 配合webpack支持的路由懶加載方法有:

  • 這種方法比較通用,而且支持性好

  1. resolve => require([./Foo], resolve) 
  1. const Foo = () => import('./Foo'

接下來我們以官方文檔的寫法為例,對(duì)比這兩種寫法:

  1. // 非懶加載寫法 
  2. import Vue from 'vue' 
  3. import Router from 'vue-router' 
  4. import Home from 'pages/home' 
  5. ... 
  6. ​ 
  7. Vue.use(Router) 
  8. ​ 
  9. export default new Router({ 
  10. routes: [ 
  11.   { 
  12.       path: '/'
  13.       name'home'
  14.       component: Home 
  15.   } 
  16.   ... 
  17. }) 

推薦以下寫法,路由懶加載可以幫我們?cè)谶M(jìn)入首屏?xí)r不用加載過多的資源,從而減少首屏加載速度。

  1. // 路由懶加載寫法 
  2. import Vue from 'vue' 
  3. import Router from 'vue-router' 
  4. ​ 
  5. // 其它都不用變,就是這么簡單 
  6. const Home = () => import('./home'
  7. ... 
  8. ​ 
  9. Vue.use(Router) 
  10. ​ 
  11. export default new Router({ 
  12. routes: [ 
  13.   { 
  14.       path: '/'
  15.       name'home'
  16.       component: Home 
  17.   } 
  18.   ... 
  19. }) 

不要在使用v-for的同一元素上使用v-if

Vue官方文檔強(qiáng)烈建議永遠(yuǎn)不要把 v-if 和 v-for 同時(shí)用在同一個(gè)元素上。一般我們?cè)趦煞N常見的情況下會(huì)傾向于這樣做:

  • 1)為了過濾一個(gè)列表中的項(xiàng)目 (比如 v-for="user in users" v-if="user.isActive")。在這種情形下,請(qǐng)將 users 替換為一個(gè)計(jì)算屬性 (比如 activeUsers),讓其返回過濾后的列表(見下面例子)。

  1. // 第一種情形 反例 
  2. <ul> 
  3. <li 
  4.   v-for="user in users" 
  5.   v-if="user.isActive" 
  6.   :key="user.id" 
  7.   {{ user.name }} 
  8. </li> 
  9. </ul> 

當(dāng) Vue 處理指令時(shí),v-for 比 v-if 具有更高的優(yōu)先級(jí),所以哪怕我們只渲染出一小部分用戶的元素,也得在每次重渲染的時(shí)候遍歷整個(gè)列表,不論活躍用戶是否發(fā)生了變化。我們可通過將其更換為在如下的一個(gè)計(jì)算屬性上遍歷:

  1. // 好例子 
  2. computed: { 
  3. activeUsers: function () { 
  4.   return this.users.filter(function (user) { 
  5.     return user.isActive 
  6.   }) 
  1. <ul> 
  2. <li 
  3.   v-for="user in activeUsers" 
  4.   :key="user.id" 
  5.   {{ user.name }} 
  6. </li> 
  7. </ul> 
  • 2)為了避免渲染本應(yīng)該被隱藏的列表 (比如 v-for="user in users" v-if="shouldShowUsers")。這種情形下,請(qǐng)將 v-if 移動(dòng)至容器元素上 (比如 ul, ol)(見下面例子)。

  1. // 第二種情形 反例 
  2. <ul> 
  3. <li 
  4.   v-for="user in users" 
  5.   v-if="shouldShowUsers" 
  6.   :key="user.id" 
  7.   {{ user.name }} 
  8. </li> 
  9. </ul> 

更新為:

  1. // 好例子 
  2. <ul v-if="shouldShowUsers"
  3. <li 
  4.   v-for="user in users" 
  5.   :key="user.id" 
  6.   {{ user.name }} 
  7. </li> 
  8. </ul> 

過濾器讓數(shù)據(jù)處理更便利

Vue.js 允許你自定義過濾器,它的用法其實(shí)是很簡單,但是可能有些朋友沒有用過,接下來我們介紹下:

1.理解過濾器

  • 功能:對(duì)要顯示的數(shù)據(jù)進(jìn)行特定格式化后再顯示。

  • 注意:過濾器并沒有改變?cè)镜臄?shù)據(jù),需要對(duì)展現(xiàn)的數(shù)據(jù)進(jìn)行包裝

  • 使用場景:雙花括號(hào)插值和 v-bind 表達(dá)式 (后者從 2.1.0+ 開始支持)。

2.定義過濾器

可以在一個(gè)組件的選項(xiàng)中定義本地的過濾器:

  1. filters: { 
  2. capitalize: function (value) { 
  3.   if (!value) return '' 
  4.   value = value.toString() 
  5.   return value.charAt(0).toUpperCase() + value.slice(1) 

也可以在創(chuàng)建 Vue 實(shí)例之前全局定義過濾器:

  1. Vue.filter('capitalize'function (value) { 
  2. if (!value) return '' 
  3. value = value.toString() 
  4. return value.charAt(0).toUpperCase() + value.slice(1) 
  5. }) 

3.使用過濾器

使用方法也簡單,即在雙花括號(hào)中使用管道符(pipeline) |隔開:

  1. <!-- 在雙花括號(hào)中 --> 
  2. <div>{{ myData| filterName}}</div> 
  3. <div>{{ myData| filterName(arg)}}</div> 
  4. <!-- 在 v-bind 中 --> 
  5. <div v-bind:id="rawId | formatId"></div> 

接下來我們看個(gè)如何使用過濾器格式化日期的例子:

  1. <div> 
  2.   <h2>顯示格式化的日期時(shí)間</h2> 
  3.   <p>{{ date }}</p> 
  4.   <p>{{ date | filterDate }}</p> 
  5.   <p>年月日: {{ date | filterDate("YYYY-MM-DD") }}</p> 
  6. </div> 
  7. ...... 
  8. filters: { 
  9.   filterDate(value, format = "YYYY-MM-DD HH:mm:ss") { 
  10.     console.log(this)//undefined 過濾器沒有this指向的 
  11.     return moment(value).format(format); 
  12.   } 
  13. }, 
  14. data() { 
  15.   return { 
  16.     date: new Date() 
  17.   }; 

 

能用computed的盡量用computed代替 watch

很多時(shí)候頁面會(huì)出現(xiàn) watch 的濫用而導(dǎo)致一系列問題的產(chǎn)生,而通常更好的辦法是使用 computed 屬性,先從一張圖區(qū)別它們有什么區(qū)別?

從上面流程圖中,我們可以看出它們之間的區(qū)別:

  • watch:監(jiān)測的是屬性值, 只要屬性值發(fā)生變化,其都會(huì)觸發(fā)執(zhí)行回調(diào)函數(shù)來執(zhí)行一系列操作。

  • computed:監(jiān)測的是依賴值,依賴值不變的情況下其會(huì)直接讀取緩存進(jìn)行復(fù)用,變化的情況下才會(huì)重新計(jì)算。

除此之外,有點(diǎn)很重要的區(qū)別是:計(jì)算屬性不能執(zhí)行異步任務(wù),計(jì)算屬性必須同步執(zhí)行。也就是說計(jì)算屬性不能向服務(wù)器請(qǐng)求或者執(zhí)行異步任務(wù)。如果遇到異步任務(wù),就交給偵聽屬性。watch也可以檢測computed屬性。總而言之,兩者的區(qū)別歸納為以下兩句話:

  • computed能做的,watch都能做,反之則不行

  • 能用computed的盡量用computed

為啥提倡使用 computed 代替 watch,這是因?yàn)橛袝r(shí)候可以實(shí)現(xiàn)同樣的效果,而 computed 會(huì)更勝一籌,比如在處理多數(shù)據(jù)聯(lián)動(dòng)的情況下,使用 computed 會(huì)更加合理一點(diǎn)。

  1. <template> 
  2.   <div> 
  3.       <input type="text" v-model="firstName"
  4.       <input type="text" v-model="lastName"
  5.       <span>{{ fullName }}</span> 
  6.       <span>{{ fullName2 }}</span> 
  7.   </div> 
  8. </template> 
  9. ​ 
  10. <script> 
  11. export default { 
  12.   data() { 
  13.       reurn { 
  14.           firstName: ''
  15.           lastName: ''
  16.           fullName2: '' 
  17.       } 
  18.   }, 
  19.     
  20.   // 使用 computed 
  21.   computed: { 
  22.       fullName() { 
  23.           return this.firstName + ' ' + this.lastName 
  24.       } 
  25.   }, 
  26.     
  27.   // 使用 watch 
  28.   watch: { 
  29.       firstName: function(newVal, oldVal) { 
  30.           this.fullName2 = newVal + ' ' + this.lastName; 
  31.       }, 
  32.       lastName: function(newVal, oldVal) { 
  33.           this.fullName2 = this.firstName + ' ' + newVal; 
  34.       }, 
  35.   } 
  36. </script> 

化繁為簡的Watchers

如果我們需要在組件初始化以及偵聽屬性變化時(shí)調(diào)用同一個(gè)方法,通常的做法像下面這樣:

  1. watch: { 
  2. myProperty() { 
  3.   this.doSomething(); 
  4. }, 
  5. created() { 
  6. this.doSomething(); 
  7. }, 
  8. methods: { 
  9. doSomething() { 
  10.     console.log('doing something...'); 

盡管上面這段代碼看起來沒什么問題,但created鉤子里面執(zhí)行的方法是多余的。我們可以把所需要執(zhí)行的方法放到watch里面,避免在created鉤子里寫重復(fù)代碼,那將會(huì)在組件實(shí)例化的時(shí)候觸發(fā)多一次。 那如何優(yōu)化呢?代碼如下:

  1. watch: { 
  2. myProperty: { 
  3.   immediate: true,//表示創(chuàng)建組件時(shí)立馬執(zhí)行一次 
  4.   handler() { 
  5.     console.log('doing something...'); // 只用一次的方法沒必要在methods里面聲明了 
  6.   } 

參考文章與書籍

作者介紹

浪里行舟,慕課網(wǎng)認(rèn)證作者,前端愛好者,立志往全棧工程師發(fā)展,從事前端一年多,目前技術(shù)棧有vue全家桶、ES6以及l(fā)ess等,樂于分享,最近一年寫了五六十篇原創(chuàng)技術(shù)文章,得到諸多好評(píng)!

【51CTO原創(chuàng)稿件,合作站點(diǎn)轉(zhuǎn)載請(qǐng)注明原文作者和出處為51CTO.com】

 

責(zé)任編輯:龐桂玉 來源: 51CTO
相關(guān)推薦

2015-07-06 10:09:33

iosFoundationNSHashTable

2015-10-21 13:42:54

iOS開發(fā)watch OS2

2015-07-07 10:15:56

iOSUIVisualEffweak

2015-07-07 14:05:22

iOS技巧

2014-07-23 10:08:34

Angular前端項(xiàng)目

2021-04-21 07:51:06

Vue 開發(fā)VS CodeVetur

2024-01-09 18:01:38

2024-08-13 08:00:00

2021-10-27 08:00:00

DevSecOps開發(fā)安全

2015-07-28 20:34:01

Android開發(fā)框架

2016-10-25 14:27:16

開源Ruby on RaiWeb框架

2016-12-01 08:36:18

編程云環(huán)境云戰(zhàn)略

2019-04-09 15:12:43

開發(fā)者技能工具

2020-06-30 08:28:29

Vue開發(fā)前端

2025-03-24 15:00:13

鴻蒙HarmonyOS

2020-03-05 12:12:54

數(shù)據(jù)Python開發(fā)

2022-12-15 16:38:17

2018-10-23 10:35:20

react.jsReact面試題前端

2021-01-05 05:15:02

Github 前端倉庫

2015-04-01 10:55:55

點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)