VUE開發者必須知道的實用技術點!

前言

vue 做爲目前前端三大框架之一,對於前端開發者能夠說是必備技能。掌握這些實用小技巧,可讓你事半功倍。javascript

一、路由懶加載,能讓你首次加載更快

路由懶加載可讓咱們的包不須要一次把全部的頁面的加載進來,只加載當前頁面的路由組件就行。html

舉個栗子🌰,若是這樣寫,加載的時候會所有都加載進來。前端

const router = new VueRouter({
  routes:[
    {
      path: '/',
      name: 'Home',
      component: Home
    },
    {
      path: '/about',
      name: 'About',
      component: About
    }
  ]
})
複製代碼

因此,應該避免上面的寫法,儘可能使用懶加載。vue

路由的懶加載能夠分爲如下三種寫法。java

  • Vue異步組件webpack

  • es6的importes6

  • webpack提供的require.ensure()web

    // 一、Vue異步組件 VueRouter({ routes:[ { path: '/about', name: 'About', component: resolve => reqire(['path路徑'], resolve) } ] })vuex

    // 二、es6的import VueRouter({ routes:[ { path: '/about', name: 'About', component: () => import('path路徑') } ] })數組

    // 三、webpack提供的require.ensure() VueRouter({ routes:[ { path: '/about', name: 'About', component: r => require.ensure([],() => r(require('path路徑')), 'demo') } ] })

二、異步組件

異步組件可讓咱們在須要一些組件時纔將它加載進來,而不是一初始化就加載進來,這跟路由懶加載是一個概念。

之前是這麼引入組件的

import BureauDetail from './components/ChildFirst'
import addBureau from './components/ChildSecond'

//在vue的comoinents中
components: {
  ChildFirst,
  ChildSecond 
}
複製代碼

若是不是一開始就要加載的組件,咱們可使用組件懶加載

//在vue的comoinents中
components: {
  BureauDetail: () => import('./components/ChildFirst'),
  addBureau: () => import('./components/ChildSecond')
},
複製代碼

異步組件還有一種比較完善的寫法

export default {
  components:{
    ChildFirst:()=>({
      component:import(/* webpackChunkName: "ChildFirst" */ './Async'),
      delay:200, // 延遲幾毫秒,默認200
      timeout:3000, // 加載幾毫米以後就超時,觸發error組件
      loading:LoadingComponent, // 組件未加載回來前顯示
      error:ErrorComponent // 組件超時時顯示
    })
  }
}
複製代碼

三、require.context()引入多個組件

經常用來在組件內引入多個組件, require.context(directory, useSubdirectories, regExp)

原始寫法:

// 原始寫法
import titleCom from '@/components/home/titleCom'
import bannerCom from '@/components/home/bannerCom'
import cellCom from '@/components/home/cellCom'
components: {
  titleCom, bannerCom, cellCom
}
複製代碼

這樣就寫了大量重複的代碼,利用 require.context 能夠寫成

const path = require('path')
const files = require.context('@/components/home', false, /\.vue$/)
const modules = {}
files.keys().forEach(key => {
  const name = path.basename(key, '.vue')
  modules[name] = files(key).default || files(key)
})
components: modules
複製代碼

在main.js中引入大量公共組件,利用 require.context 能夠寫成

import Vue from 'vue'
// 自定義組件
const requireComponents = require.context('../views/components', true, /\.vue/)
// 打印結果
// 遍歷出每一個組件的路徑
requireComponents.keys().forEach(fileName => {
  // 組件實例
  const reqCom = requireComponents(fileName)
  // 截取路徑做爲組件名
  const reqComName =reqCom.name|| fileName.replace(/\.\/(.*)\.vue/,'$1')
  // 組件掛載
  Vue.component(reqComName, reqCom.default || reqCom)
})
複製代碼

四、在父組件裏監聽子組件的生命週期

好比有父組件 Parent 和子組件 Child,若是父組件監聽到子組件掛載 mounted 就作一些邏輯處理,常規的寫法可能以下:

// Parent.vue
<Child @mounted="doSomething"/>

// Child.vue
mounted() {
  this.$emit("mounted");
}
複製代碼

此外,還有一種特別簡單的方式,子組件不須要任何處理,只須要在父組件引用的時候經過@hook 來監聽便可,@hook也能夠監聽其它的生命週期事件,代碼以下:

<Child @hook:mounted="doSomething" /> 
<Child @hook:updated="doSomething" />
複製代碼

五、computed中使用this?

在computed屬性中經過this.xxx去拿data裏面的數據,和methods裏面的方法吧,或許還會經過this. s t o r e 去拿 v u e x s t a t e , c o m m i t 等,甚至,還會經過 t h i s . store去拿vuex的state,和commit等,甚至,還會經過this. route去獲取路由裏面的數據吧。

其實,咱們能夠避免這些醜陋的this,它甚至會給咱們帶來看不見的性能問題。

實現上,咱們經過this能訪問到的數據,在computed的第一個參數上都能結構出來。

export default {
  watch: {
    haha({$attrs,$route,$store,$listeners,$ref}){
     // 還能結構不少屬性,可自行打印看看
     return 
   }
  }
}
複製代碼

六、初始化的時候,讓watch當即執行

watch每當監聽的數據變化時都會執行回調進行後續操做。

可是當 watch 一個變量的時候,在頁面或者組件初始化時並不會執行,以下面的例子,你須要在 created 的時候手動調用一次。

created() {
  this.getList();
},
watch: {
  keyWord: 'getList',
}
複製代碼

上面這樣的作法可使用,但很麻煩,咱們能夠添加 immediate 屬性,這樣初始化的時候就會自動觸發

watch 有三個參數

  • handler:其值是一個回調函數。即監聽到變化時應該執行的函數

  • deep:其值是 true 或 false;確認是否深刻監聽。當要監聽數組或對象等引用類型數據時,可使用deep屬性

  • immediate:其值是 true 或 false,確認是否以當前的初始值執行 handler 的函數

    watch: { keyWord: { handler(val) {}, immediate: true } }

七、遞歸組件本身調用本身

遞歸組件: 組件在它的模板內能夠遞歸的調用本身,只要給組件設置 name 組件就能夠了。

注意:必須給一個條件來限制數量,不然會拋出錯誤: max stack size exceeded

<template>
  <div v-for="(item,index) in treeArr"> {{index}} <br/>
      <tree :item="item.arr" v-if="item.flag"></tree>
  </div>
</template>
<script>
export default {
  // 必須定義name,組件內部才能遞歸調用
  name: 'tree',
  data(){
    return {}
  },
  // 接收外部傳入的值
  props: {
     item: {
      type:Array,
      default: ()=>[]
    }
  }
}
</script>
複製代碼

看Element ui源碼時,封裝的tree控件、級聯選擇其,也是這麼使用的。

八、object.freeze性能優化

vue 2.0版本會經過 object.defineProperty 對數據進行劫持,遇到數組和對象必須循環遍歷全部的域值才能劫持每個屬性。

vue 3.0版本會經過Proxy構造函數來進行數據劫持,來實現視圖響應數據的變化

然而有些時候咱們的組件就是純粹的數據展現,不會有任何改變,咱們就不須要 vue 來劫持咱們的數據,在大量數據展現的狀況下,這可以很明顯的減小組件初始化的時間。

因此,咱們能夠經過 object.freeze 方法來凍結一個對象,這個對象一旦被凍結,vue就不會對數據進行劫持了。

Object.freeze() 能夠凍結一個對象,凍結以後不能向這個對象添加新的屬性,不能修改其已有屬性的值,不能刪除已有屬性,以及不能修改該對象已有屬性的可枚舉性、可配置性、可寫性。該方法返回被凍結的對象。

<p v-for="item in list">{{ item.value }}</p>

export default {
  data: {
        // vue不會對list裏的object作getter、setter綁定
        list: Object.freeze([
            { value: 1 },
            { value: 2 }
        ])
    },
    created () {
        // 界面不會有響應
        this.list[0].value = 100;

        // 下面兩種作法,界面都會響應
        this.list = [
            { value: 100 },
            { value: 200 }
        ];
        this.list = Object.freeze([
            { value: 100 },
            { value: 200 }
        ]);
    }
}
複製代碼

九、修改引用類型的數據,視圖不更新?

當vue的data裏邊聲明或者已經賦值過的對象或者數組(數組裏邊的值是對象)時,向對象中添加新的屬性,若是更新此屬性的值,是不會更新視圖的。

調用方法: this.$set( target , key , value)

  • target: 要更改的數據源(能夠是一個對象或者數組)

  • key 要更改的具體數據 (索引)

  • value 從新賦的值

    export default { name: 'App', data () { return { items: [ { message: "one", id: "1" }, { message: "two", id: "2" }, { message: "three", id: "3" } ] } }, mounted () { //此時對象的值更改了,可是視圖沒有更新 this.items[0] = { message:'first',id:'4'}

    // s e t 能夠觸發更新視圖 t h i s . set 能夠觸發更新視圖 this. set(this.items,0,art) }, methods: { handClick(){ let change = this.items[0] change.message="shen" // s e t 能夠觸發更新視圖 t h i s . set 能夠觸發更新視圖 this. set(this.items,0,change) } } }

十、.sync修飾符

.sync提供了一種與父組件溝通的思路!你若是隻是單純的在子組件當中修改父組件的某個數據時,建議使用sync,簡單,快捷,不須要在傳一個自定義方法來接收了

vue中咱們常常會用v-bind(縮寫爲:)給子組件傳入參數。或者咱們會給子組件傳入一個函數,子組件經過調用傳入的函數來改變父組件的狀態。舉個例子🌰

//父組件 給子組件傳入一個函數
 <MyFooter :age="age" @setAge="(res)=> age = res">
 </MyFooter>
 
 
 //子組件 經過調用這個函數來實現修改父組件的狀態。
 mounted () {
    console.log(this.$emit('setAge',1234567));
 }
複製代碼

如今只須要使用.sync就能夠輕鬆更新賦組件的值

//父組件 將age傳給子組件並使用.sync修飾符。
<MyFooter :age.sync="age">
</MyFooter>


//子組件 觸發事件
 mounted () {
   console.log(this.$emit('update:age',1234567));
 }
複製代碼

十一、Vue.mixin混入,複用代碼

混入 (mixin) 提供了一種很是靈活的方式,來分發 Vue 組件中的可複用功能。一個混入對象能夠包含任意組件選項。當組件使用混入對象時,全部混入對象的選項將被「混合」進入該組件自己的選項。

通俗的說,mixin能夠定義公用的data,created,methods,computed,watch等。而後混入到你當前的vue文件中。

minxin還有一個強大之處就是合併選項,相同的變量/方法名會合並在一塊兒,若是有相同名字,當前文件的變量或者方法會覆蓋mixin文件的名字或者方法。

  • data對象在內部會進行遞歸合併,並在發生衝突時以組件數據優先。

  • 同名鉤子函數將合併爲一個數組,所以都將被調用。混入對象的鉤子將在組件自身鉤子以前調用。

  • 值爲對象的選項,例如 methods、components 和 directives,將被合併爲同一個對象。兩個對象鍵名衝突時,取組件對象的鍵值對。

一、定義一個 mixin.js

export default mixin {
 data() {
  return {
   name: 'mixin'
  }
 },
 created() {
  console.log('mixin...', this.name);
 },
 mounted() {},
 methods: {  //日期轉換
   formatDate (dateTime, fmt = 'YYYY年MM月DD日 HH:mm:ss') {
     if (!dateTime) {
      return ''
     }
     moment.locale('zh-CN')
     dateTime = moment(dateTime).format(fmt)
     return dateTime
  }
 }
}
複製代碼

二、在vue文件中使用mixin

import '@/mixin'; // 引入mixin文件
export default {
 mixins: [mixin],  //用法
 data() {
  return {
   userName: "adimin",
   time: this.formatDate(new Date()) //這個vue文件的數據源data裏面的time就是引用混入進來的方法
  }
 }
} 
複製代碼

十二、provide/inject

經常使用的父子組件通訊方式都是父組件綁定要傳遞給子組件的數據,子組件經過props屬性接收,一旦組件層級變多時,採用這種方式一級一級傳遞值很是麻煩,並且代碼可讀性不高,不便後期維護。

vue提供了provide和inject幫助咱們解決多層次嵌套嵌套通訊問題。在provide中指定要傳遞給子孫組件的數據,子孫組件經過inject注入祖父組件傳遞過來的數據。

其實,provide 和 inject 主要爲高階插件/組件庫提供用例。

讀Element UI源碼時,發現不少高階組件使用了provide和inject,減小了不少父組件向子組件以及孫子組件一層層通訊的工做量。

elementUI組件庫中,在el-form組件中將組件實例暴露給子孫組件

在el-form-item組件中注入el-form組件實例,而後就可使用el-form組件實例的方法、變量等等

一、在父組件中provide提供變量

<template>
  <div>
    <p>{{ title }}</p>
    <son></son>
  </div>
</template>
<script>
  import Son from "./son"
  export default {
    name: 'Father',
    components: { Son },
    // provide選項提供變量
    provide: {
      message: 'provided by father'
    },
    data () {
      return {
        title: '父組件'
      }
    },
    methods: { ... }
  }
</script>
複製代碼

二、在子孫組件中,均可以使用inject來注入

<template>
  <div>
    <p>message:{{ message }}</p>
  </div>
</template>
<script>
export default {
  name: "GrandSon",
  inject: [ "message" ],
  data () {
    return {
      title: '孫組件'
    }
  },
  methods: { ... }
};
</script>
複製代碼

▼更多精彩推薦,請關注javascript藝術▼

相關文章
相關標籤/搜索