vue開發(fā)必須知道的小技巧

近年來,vue越來越火,使用它的人也越來越多。vue基本用法很容易上手,但是還有很多優(yōu)化的寫法你就不一定知道了。本文列舉了一些vue常用的開發(fā)技巧。
require.context()

在實(shí)際開發(fā)中,絕大部分人都是以組件化的方式進(jìn)行開發(fā)。隨之而來就有了許多的組件需要引入。比如以下場景:

import outExperInfo from "@/components/userInfo/outExperInfo";
import baseUserInfo from "@/components/userInfo/baseUserInfo";
import technicalExperInfo from "@/components/userInfo/technicalExperInfo";
import skillExperInfo from "@/components/userInfo/skillExperInfo";

components:{
    outExperInfo,
    baseUserInfo,
    technicalExperInfo,
    skillExperInfo
}



這樣寫并沒有錯,但是仔細(xì)觀察發(fā)現(xiàn)寫了很多重復(fù)的代碼,這個時候利用require.context()可以寫成:

const path = require('path')
const files = require.context('@/components/userInfo', false, /\.vue$/)
const userComponents = {}
files.keys().forEach(key => {
 const name = path.basename(key, '.vue')
 userComponents[name] = files(key).default || files(key)
})
components:userComponents



這樣不管需要引入多少組件,都可以使用這一個方法。
路由的按需加載

隨著項(xiàng)目功能模塊的增加,引入的文件數(shù)量劇增。如果不做任何處理,那么首屏加載會相當(dāng)?shù)木徛?,這個時候,路由按需加載就閃亮登場了。

webpack< 2.4 時
{
 path:'/',
 name:'home',
 components:resolve=>require(['@/components/home'],resolve)
}
 
webpack> 2.4 時
{
 path:'/',
 name:'home',
 components:()=>import('@/components/home')
}



import()方法是由es6提出的,動態(tài)加載返回一個Promise對象,then方法的參數(shù)是加載到的模塊。類似于Node.js的require方法,主要import()方法是異步加載的。
動態(tài)組件

場景:如果項(xiàng)目中有tab切換的需求,那么就會涉及到組件動態(tài)加載,一般寫法如下:

<component v-bind:is="currentTab"></component>



這樣寫也沒有錯,但是如果這樣寫的話,每次切換的時候,當(dāng)前組件都會銷毀并且重新加載下一個組件。會消耗大量的性能,所以 就起到了作用。

<keep-alive>
 <component v-bind:is="currentTab"></component>
</keep-alive>



有的小伙伴會說,這樣切換雖然不消耗性能了,但是切換效果沒有動畫效果了,別著急,這時可以利用內(nèi)置的

<transition>
<keep-alive>
 <component v-bind:is="currentTab"></component>
</keep-alive>
</transition>



components和vue.component

前者是局部注冊組件,用法如下:

export default{
 components:{home}
}



后者是全局注冊組件,主要針對一些全局使用的組件,用法如下:

Vue.component('home',home)



Vue.nextTick

Vue.nextTick()方法在下次DOM更新循環(huán)結(jié)束之后執(zhí)行延遲回調(diào),因此可以頁面更新加載完畢之后再執(zhí)行回調(diào)函數(shù)。下面介紹幾個常用場景:
場景一

<template>
    <div>
        <div ref = "ref"/>
    </div>
</template>
<script>
export default {
    created(){
        console.log(this.$refs.ref)
        //undefined
    })
}
}
</script>



因?yàn)檫@個時候created階段dom并未完全渲染完成,所以獲取值為undefined,我們對其改造一下:

<template>
    <div>
        <div ref = "ref"/>
    </div>
</template>
<script>
export default {
    created(){
        Vue.nextTick(()=>{
            console.log(this.$refs.ref)
        })
        //<div></div>
        
    })
}
}
</script>







這樣就可以獲取到dom了。
場景二

<template>
    <div>
        <div v-if="visible" ref = "ref"/>
    </div>
</template>
<script>
export default {
    data() {
        return {
          visible: false
        };
    },
    showRef() {
        this.visible = true;
        console.log(this.$refs.ref);
        //undefined
    },
}
}
</script>



因?yàn)檫@個時候雖然visible的值為true,但是頁面dom并沒有更新完成,所以獲取值為undefined,我們對其改造一下:

<template>
    <div>
        <div v-if="visible" ref = "ref"/>
    </div>
</template>
<script>
export default {
    data() {
        return {
          visible: false
        };
    },
    showRef() {
        this.visible = true;
        Vue.nextTick(()=>{
            console.log(this.$refs.ref)
        })
        //<div></div>
    },
}
}
</script>


這樣就可以獲取到dom了。
Vue.directive

場景:官方給我們提供了很多指令,但是我們?nèi)绻雽⑽淖肿兂芍付ǖ念伾x成指令使用,這個時候就需要用到Vue.directive,示例如下:

// 全局定義
Vue.directive("change-color",function(el,binding,vnode){
 el.style["color"]= binding.value;
})
 
// 使用
<template>
    <div v-change-color>{{message}}
    </div>
</template>
<script>
 export default{
     data(){
      return{
      color:'green'
      }
     }
 }
</script>



Vue.set()

當(dāng)在項(xiàng)目中直接設(shè)置數(shù)組的某一項(xiàng)的值,或者直接設(shè)置對象的某個屬性值,這個時候,你會發(fā)現(xiàn)頁面并沒有更新。這是因?yàn)镺bject.defineprototype()限制,監(jiān)聽不到變化。
解決方式:

    this.$set(你要改變的數(shù)組/對象,你要改變的位置/key,你要改成什么value)

this.$set(this.arr, 0, "OBKoro1"); // 改變數(shù)組
this.$set(this.obj, "c", "OBKoro1"); // 改變對象


    數(shù)組原生方法觸發(fā)視圖更新,vue可以監(jiān)聽到數(shù)組原生方法導(dǎo)致的數(shù)據(jù)數(shù)據(jù)變化

splice()、 push()、pop()、shift()、unshift()、sort()、reverse()



意思是使用這些方法不用我們再進(jìn)行額外的操作,視圖自動進(jìn)行更新。
推薦使用splice方法會比較好自定義,因?yàn)閟lice可以在數(shù)組的任何位置進(jìn)行刪除/添加操作
事件修飾符

    .stop:阻止冒泡
    .prevent:阻止默認(rèn)行為
    .self:僅綁定元素自身觸發(fā)
    .once: 2.1.4 新增,只觸發(fā)一次
    passive: 2.3.0 新增,滾動事件的默認(rèn)行為 (即滾動行為) 將會立即觸發(fā),不能和.prevent 一起使用
    .sync 修飾符

從 2.3.0 起vue重新引入了 .sync 修飾符,但是這次它只是作為一個編譯時的語法糖存在。它會被擴(kuò)展為一個自動更新父組件屬性的 v-on 監(jiān)聽器。示例代碼如下:

<comp :foo.sync="bar"></comp>



會被擴(kuò)展為:

<comp :foo="bar" @update:foo="val => bar = val"></comp>



當(dāng)子組件需要更新 foo 的值時,它需要顯式地觸發(fā)一個更新事件:

this.$emit('update:foo', newValue)



長列表性能優(yōu)化(數(shù)據(jù)凍結(jié))

眾所周知,vue會通過object.defineProperty對數(shù)據(jù)進(jìn)行劫持,進(jìn)而實(shí)現(xiàn)頁面實(shí)時相應(yīng)數(shù)據(jù)的變化,然而我們有些時候,需要的僅僅就是純粹的展示數(shù)據(jù),因?yàn)閿?shù)據(jù)不會有任何改變,我們就不需要vue來劫持我們的數(shù)據(jù)。在數(shù)據(jù)量很大的情況下,這可以很明顯的減少加載時間。

那么如何實(shí)現(xiàn)禁止vue劫持我們的數(shù)據(jù)尼?可以通過object.freeze方法來凍結(jié)數(shù)據(jù),凍結(jié)之后數(shù)據(jù)也就不能再修改了。示例如下:

let longList = [
    {name:'monkeysoft'},
    ...
]
this.longList = Object.freeze(longList)


歡迎關(guān)注微信公眾號:猴哥說前端