陣陣鍵盤聲,隱隱測試言。 產品不穩定,今夜無人還。javascript
在開發Vue
的過程當中,咱們常常會遇到一些這樣那樣的問題,而後要卡好半天,等問題解決了才發現原來一些細節知識點仍是沒有掌握好。今天小編就整理了幾個在項目中會用到的一些實戰技巧點,但願能夠幫助到正在努力賺錢的你。江湖規矩,先贊後看,豔遇不斷。css
閱讀小編近期的熱門
Vue
相關文章,我是子君,每週一,不見不散前端
實戰技巧,Vue原來還能夠這樣寫 獲贊 2600+vue
絕對乾貨~!學會這些Vue小技巧,能夠早點下班和女神約會了 獲贊 1200+java
我在項目中是這樣配置Vue的 獲贊 1000+git
前方高能,這是最新的一波Vue實戰技巧,不用則已,一用驚人 獲贊 1000+github
學會使用Vue JSX,一車老乾媽都是你的 獲贊700+web
看到賺到!重讀vue2.0風格指南,我整理了這些關鍵規則 獲贊 150+算法
前幾天有朋友給我發了一段代碼,而後說Vue
有bug
,他明明寫的沒問題,爲啥數據就不響應呢,必定是Vue
的bug
?我感受他比尤雨溪要牛逼,高攀不起,就沒有理他了。可是確實有時候咱們在開發時候會遇到數據不響應的狀況,那怎麼辦呢?好比下面這段代碼:element-ui
<template>
<div> <div> <span>用戶名: {{ userInfo.name }}</span> <span>用戶性別: {{ userInfo.sex }}</span> <span v-if="userInfo.officialAccount"> 公衆號: {{ userInfo.officialAccount }} </span> </div> <button @click="handleAddOfficialAccount">添加公衆號</button> </div> </template> <script> export default { data() { return { userInfo: { name: '子君', sex: '男' } } }, methods: { // 在這裏添加用戶的公衆號 handleAddOfficialAccount() { this.userInfo.officialAccount = '前端有的玩' } } } </script> 複製代碼
在上面的代碼中,咱們但願給用戶信息裏面添加公衆號屬性,可是經過this.userInfo.officialAccount = '前端有的玩'
添加以後,並無生效,這是爲何呢?
這是由於在Vue
內部,數據響應是經過使用Object.definePrototype
監聽對象的每個鍵的getter
,setter
方法來實現的,但經過這種方法只能監聽到已有屬性,新增的屬性是沒法監聽到的,但我就是想監聽,小編你說咋辦吧。下面小編提供了四種方式,若是有更多方式,歡迎下方評論區告訴我。
data
中定義好好比上面的公衆號,我能夠提早在userInfo
裏面定義好,這樣就不是新增屬性了,就像下面這樣
data() {
return { userInfo: { name: '子君', sex: '男', // 我先提早定義好 officialAccount: '' } } } 複製代碼
userInfo
雖然沒法給userInfo
裏面添加新的屬性,可是由於userInfo
已經定義好了,因此我直接修改userInfo
的值不就能夠了麼,因此也能夠像下面這樣寫
this.userInfo = {
// 將原來的userInfo 經過擴展運算法複製到新的對象裏面 ...this.userInfo, // 添加新屬性 officialAccount: '前端有的玩' } 複製代碼
Vue.set
其實上面兩種方法都有點取巧的嫌疑,其實對於新增屬性,Vue
官方專門提供了一個新的方法Vue.set
用來解決新增屬性沒法觸發數據響應。
Vue.set 方法定義
/** * target 要修改的對象 * prpertyName 要添加的屬性名稱 * value 要添加的屬性值 */ Vue.set( target, propertyName, value ) 複製代碼
上面的代碼使用Vue.set
能夠修改成
import Vue from 'vue'
// 在這裏添加用戶的公衆號 handleAddOfficialAccount() { Vue.set(this.userInfo,'officialAccount', '前端有的玩') } 複製代碼
可是每次要用到set
方法的時候,還要把Vue
引入進來,好麻煩,因此爲了簡便起見,Vue
又將set
方法掛載到了Vue
的原型鏈上了,即Vue.prototype.$set = Vue.set
,因此在Vue
組件內部能夠直接使用this.$set
代替Vue.set
this.$set(this.userInfo,'officialAccount', '前端有的玩')
複製代碼
小編髮現有許多同窗不知道何時應該用Vue.set
,其實只有當你要賦值的屬性尚未定義的時候須要使用Vue,set
,其餘時候通常不會須要使用。
$forceUpdate
我以爲$forceUpdate
的存在,讓許多前端開發者不會再去注意數據雙向綁定的原理,由於不論何時,反正我修改了data
以後,調用一下$forceUpdate
就會讓Vue
組件從新渲染,bug
是不會存在的。可是實際上這個方法並不建議使用,由於它會引發許多沒必要要的性能消耗。
其實不只僅是對象,數組也存在數據修改以後不響應的狀況,好比下面這段代碼
<template> <div> <ul> <li v-for="item in list" :key="item"> {{ item }} </li> </ul> <button @click="handleChangeName">修更名稱</button> </div> </template> <script> export default { data() { return { list: ['張三', '李四'] } }, methods: { // 修改用戶名稱 handleChangeName() { this.list[0] = '王五' } } } </script> 複製代碼複製代碼
上面的代碼但願將張三的名字修改成王五,實際上這個修改並不能生效,這是由於Vue
不能檢測到如下變更的數組:
this.list[index] = newValue
length
屬性,例如:
this.list.length = 0
因此在上例中經過this.list[0] = '王五'
是沒法觸發數據響應的,那應該怎麼辦呢?像上面提到的Vue.set
和$forceUpdate
均可以解決這個問題,好比Vue.set
能夠這樣寫
Vue.set(this.list,0,'王五')
複製代碼
除了那些方法以外,Vue
還針對數組提供了變異方法
在操做數組的時候,咱們通常會用到數據提供的許多方法,好比push
,pop
,splice
等等,在Vue
中調用數組上面提供的這些方法修改數組的值是能夠觸發數據響應的,好比上面的代碼改成如下代碼便可觸發數據響應
this.list.splice(0,1,'王五')
複製代碼
實際上,若是Vue
僅僅依賴getter
與setter
,是沒法作到在數組調用push
,pop
等方法時候觸發數據響應的,所以Vue
其實是經過劫持這些方法,對這些方法進行包裝變異來實現的。
Vue
對數組的如下方法進行的包裝變異:
因此在操做數組的時候,調用上面這些方法是能夠保證數據能夠正常響應,下面是Vue
源碼中包裝數組方法的代碼:
var original = arrayProto[method];
def(arrayMethods, method, function mutator () { // 將 arguments 轉換爲數組 var args = [], len = arguments.length; while ( len-- ) args[ len ] = arguments[ len ]; var result = original.apply(this, args); // 這兒的用法同dependArray(value),就是爲了取得dep var ob = this.__ob__; var inserted; switch (method) { case 'push': case 'unshift': inserted = args; break case 'splice': inserted = args.slice(2); break } // 若是有新的數據插入,則插入的數據也要進行一個響應式 if (inserted) { ob.observeArray(inserted); } // 通知依賴進行更新 ob.dep.notify(); return result }); 複製代碼
filter
更簡單filter
簡化邏輯我想把時間戳顯示成yyyy-MM-DD HH:mm:ss
的格式怎麼辦?是須要在代碼中先將日期格式化以後,再渲染到模板嗎?就像下面這樣
<template> <div> {{ dateStr }} <ul> <li v-for="(item, index) in getList" :key="index"> {{ item.date }} </li> </ul> </div> </template> <script> import { format } from '@/utils/date' export default { data() { return { date: Date.now(), list: [ { date: Date.now() } ] } }, computed: { dateStr() { return format(this.date, 'yyyy-MM-DD HH:mm:ss') }, getList() { return this.list.map(item => { return { ...item, date: format(item.date, 'yyyy-MM-DD HH:mm:ss') } }) } } } </script> 複製代碼複製代碼
像上面的寫法,針對每個日期字段都須要調用format
,而後經過計算屬性進行轉換?這時候能夠考慮使用Vue
提供的filter
去簡化
<template>
<div>
<!--使用過濾器-->
{{ dateStr | formatDate }}
<ul>
<li v-for="(item, index) in list" :key="index">
<!--在v-for中使用過濾器-->
{{ item.date | formatDate }}
</li>
</ul>
</div>
</template>
<script>
import { format } from '@/utils/date'
export default {
filters: {
formatDate(value) {
return format(value, 'yyyy-MM-DD HH:mm:ss')
}
},
data() {
return {
date: Date.now(),
list: [
{
date: Date.now()
}
]
}
}
}
</script>
複製代碼
經過上面的修改是否是就簡單多了
filter
有些過濾器使用的很頻繁,好比上面提到的日期過濾器,在不少地方都要使用,這時候若是在每個要用到的組件裏面都去定義一遍,就顯得有些多餘了,這時候就能夠考慮Vue.filter
註冊全局過濾器
對於全局過濾器,通常建議在項目裏面添加filters
目錄,而後在filters目錄裏面添加
// filters\index.js
import Vue from 'vue' import { format } from '@/utils/date' Vue.filter('formatDate', value => { return format(value, 'yyyy-MM-DD HH:mm:ss') }) 複製代碼
而後將filters
裏面的文件引入到main.js
裏面,這時候就能夠在組件裏面直接用了,好比將前面的代碼能夠修改成
<template>
<div>
<!--使用過濾器-->
{{ dateStr | formatDate }}
<ul>
<li v-for="(item, index) in list" :key="index">
<!--在v-for中使用過濾器-->
{{ item.date | formatDate }}
</li>
</ul>
</div>
</template>
<script>
export default {
data() {
return {
date: Date.now(),
list: [
{
date: Date.now()
}
]
}
}
}
</script>
複製代碼
是否是更簡單了
在使用一些UI
框架的時候,常常須要使用Vue.use
來安裝, 好比使用element-ui
時候,常常會這樣寫:
import Vue from 'vue';
import ElementUI from 'element-ui'; import 'element-ui/lib/theme-chalk/index.css'; Vue.use(ElementUI,{size: 'small'}); 複製代碼
使用了Vue.use
以後,element-ui
就能夠直接在組件裏面使用了,好神奇哦(呸,娘炮)。接下來咱們實現一個簡化版的element
來看如何去安裝。
Vue.use
的用法Vue.use
是一個全局的方法,它須要在你調用 new Vue()
啓動應用以前完成,Vue.use
的參數以下
/** * plugin: 要安裝的插件 如 ElementUI * options: 插件的配置信息 如 {size: 'small'} */ Vue.use(plugin, options) 複製代碼
element-ui
的安裝邏輯想一下,使用Vue.use(ElementUI,{size: 'small'})
以後咱們能夠用到哪些element-ui
提供的東西
element-ui
的組件,不須要再
import
v-loading
指令
this.$loading
在組件裏面顯示
loading
// 這個是一個按鈕組件
import Button from '@/components/button' // loading 指令 import loadingDirective from '@/components/loading/directive' // loading 方法 import loadingMethod from '@/components/loading' export default { /** * Vue.use 須要插件提供一個install方法 * @param {*} Vue Vue * @param {*} options 插件配置信息 */ install(Vue, options) { console.log(options) // 將組件經過Vue.components 進行註冊 Vue.components(Button.name, Button) // 註冊全局指令 Vue.directive('loading', loadingDirective) // 將loadingMethod 掛載到 Vue原型鏈上面,方便調用 Vue.prototype.$loading = loadingMethod } } 複製代碼
經過上面的代碼,已經實現了一個丐版的element-ui
插件,這時候就能夠在main.js
裏面經過Vue.use
進行插件安裝了。你們可能會有疑問,爲何我要用這種寫法,不用這種寫法我照樣能夠實現功能啊。小編認爲這種寫法有兩個優點
Vue.use
在安裝插件的時候,會對插件進行緩存,即一個插件若是安裝屢次,實際上只會在第一次安裝時生效。
Vue.prototype
上實現。
element-ui
當一個 Vue 實例被建立時,它將 data
對象中的全部的 property 加入到 Vue 的響應式系統中。當這些 property 的值發生改變時,視圖將會產生「響應」,即匹配更新爲新的值。可是這個過程其實是比較消耗性能的,因此對於一些有大量數據但只是展現的界面來講,並不須要將property
加入到響應式系統中,這樣能夠提升渲染性能,怎麼作呢,你須要瞭解一下Object.freeze
。
在Vue
官網中,有這樣一段話:這裏惟一的例外是使用 Object.freeze()
,這會阻止修改現有的 property,也意味着響應系統沒法再追蹤變化。這段話的意思是,若是咱們的數據使用了Object.freeze
,就可讓數據脫離響應式系統,那麼該如何作呢?
好比下面這個表格,由於只是渲染數據,這時候咱們就能夠經過Object.freeze
來優化性能
<template>
<el-table :data="tableData" style="width: 100%">
<el-table-column prop="date" label="日期" width="180" />
<el-table-column prop="name" label="姓名" width="180" />
<el-table-column prop="address" label="地址" />
</el-table>
</template>
<script>
export default {
data() {
const data = Array(1000)
.fill(1)
.map((item, index) => {
return {
date: '2020-07-11',
name: `子君${index}`,
address: '大西安'
}
})
return {
// 在這裏咱們用了Object.freeze
tableData: Object.freeze(data)
}
}
}
</script>
複製代碼
有的同窗可能會有疑問,若是我這個表格的數據是滾動加載的,你這樣寫我不就無法再給tableData
添加數據了嗎?是,確實沒辦法去添加數據了,但仍是有辦法解決的,好比像下面這樣
export default {
data() { return { tableData: [] } }, created() { setInterval(() => { const data = Array(1000) .fill(1) .map((item, index) => { // 雖然不能凍結整個數組,可是能夠凍結每一項數據 return Object.freeze({ date: '2020-07-11', name: `子君${index}`, address: '大西安' }) }) this.tableData = this.tableData.concat(data) }, 2000) } } 複製代碼
合理的使用Object.freeze
,是能夠節省很多渲染性能,特別對於IE瀏覽器,效果仍是很明顯的,趕快去試試吧。
最後若是你如今須要開發移動端項目,能夠了解一下小編整理的一個開箱即用框架 vue-vant-base,也許能夠幫到你哦
不要吹滅你的靈感和你的想象力; 不要成爲你的模型的奴隸。 ——文森特・梵高
本文使用 mdnice 排版