Vue專案實用技巧整理
1,css篇: 全域性引入公共的scss或者其他預編譯檔案 ,主要依賴:sass-resources-loader, 詳見我上一篇部落格
2. js篇:
2.1:props和$emit
巧用修飾符語法糖sync來優雅的更新props ,父子元件的傳值prop是很常用的業務,需要在子元件去更新prop的場景也很常見,但是prop是個只讀屬性,在子元件中直接修改其值因不符合單向資料流的設計,所以我們一般結合$emit來觸發父元件的方法, 但是有些場景
只是簡單的修改prop中的簡單的值, 比如切換顯示隱藏,更新type等等, 這時候就可以考慮使用sync修飾符了, 子元件更新prop的值也是必須要通過$emit來觸發, 這並沒有改變其單向資料流的設計的, 只是觸發的方法名前面多了一個 update: ,說白了就是你在父元件中使用了sync, Vue會幫你宣告一個method 名字就叫做 update:xxx 所以才免去你的手動新增這麼一個方法, 開始就說了這不過是個語法糖 , 具體程式碼如下:
parent.vue:
<child :title.sync="title"></child>
child.vue:
export defalut {
props: {
title: String
},
methods: {
changeTitle(){
this.$emit('update:title', 'hello')
}
}
2.2:provide和inject(主要在開發高階外掛/元件庫時使用。並不推薦用於普通應用程式程式碼中。但是某些時候,或許它能幫助到我們)
這對選項需要一起使用,以允許一個祖先元件向其所有子孫後代注入一個依賴,不論元件層次有多深,並在其上下游關係成立的時間裡始終生效。
簡單來說,一個元件將自己的屬性通過provide
暴露出去,其下面的子孫元件inject
即可接收到暴露的屬性
程式碼如下:
App.vue:
export default {
provide() {
return {
app: this
}
}
}
child.vue:
export default {
inject: ['app'],
created() {
console .log(this.app) // App.vue例項
}
}
ps:在 2.5.0+ 版本可以通過設定預設值使其變成可選項:
export default {
inject: {
app: {
default: () => ({})
}
},
created() {
console.log(this.app)
}
}
如果你想為inject
的屬性變更名稱,可以使用from
來表示其來源:
export default {
inject: {
myApp: {
// from的值和provide的屬性名保持一致
from: 'app',
default: () => ({})
}
},
created() {
console.log(this.myApp)
}
}
2.3:巧用template
相信v-if
在開發中是用得最多的指令,那麼你一定遇到過這樣的場景,多個元素需要切換,而且切換條件都一樣,一般都會使用一個元素包裹起來,在這個元素上做切換。
<div v-if="status==='ok'">
<h1>Title</h1>
<p>Paragraph 1</p>
<p>Paragraph 2</p>
</div>
如果像上面的 div 只是為了切換條件而存在,還導致元素層級巢狀多一層,那麼它沒有“存在的意義”。
我們都知道在宣告頁面模板時,所有元素需要放在<template>
元素內。除此之外,它還能在模板內使用,<template>
元素作為不可見的包裹元素,只是在執行時做處理,最終的渲染結果並不包含它。
<template>
<div>
<template v-if="status==='ok'">
<h1>Title</h1>
<p>Paragraph 1</p>
<p>Paragraph 2</p>
</template>
</div>
</template>
我們也可以在<template>上使用v-for指令, 這也不失為解決v-if和v-for同時使用報出警告的問題的方法之一了,(之前是通過過濾資料後渲染解決的)
<template v-for="item in 10">
<div v-if="item % 2 == 0" :key="item">{{item}}</div>
</template>
2.4: require.context (自動註冊全域性元件功能在之前的部落格,請移步)
這個並不是Vue提供的功能, 而是強大的Webpack提供的, 他還有另外一個妙用就是自動引入模組
像 api 檔案一般按功能劃分模組,在組合時可以使用require.context
一次引入資料夾所有的模組檔案,而不需要逐個模組檔案去引入。每當新增模組檔案時,就只需要關注邏輯的編寫和模組暴露,require.context
會幫助我們自動引入
程式碼如下: (可以做成外掛形式 具體請檢視vue外掛機制 ) import Request from '../service/request'
let importAll = require.context('./modules', false, /\.js$/) class Api extends Request{ constructor(){ super() //importAll.keys()為模組路徑陣列 importAll.keys().map(path =>{ //相容處理:.default獲取ES6規範暴露的內容; 後者獲取commonJS規範暴露的內容 let api = importAll(path).default || importAll(path) Object.keys(api).forEach(key => this[key] = api[key]) }) } } export default new Api()
路由懶載入(動態chunkName)
路由懶載入作為效能優化的一種手段,它能讓路由元件延遲載入。通常我們還會為延遲載入的路由新增“魔法註釋”(webpackChunkName),在打包時,該路由元件會被單獨打包出來。
let router = new Router({
routes: [
{
path:'/login',
name:'login',
component: import(/* webpackChunkName: "login" */ `@/views/login.vue`)
},
{
path:'/index',
name:'index',
component: import(/* webpackChunkName: "index" */ `@/views/index.vue`)
},
{
path:'/detail',
name:'detail',
component: import(/* webpackChunkName: "detail" */ `@/views/detail.vue`)
}
]
})
上面這種寫法沒問題,但仔細一看它們結構都是相似的,作為一名出色的開發者,我們可以使用map
迴圈來解決這種重複性的工作。
const routeOptions = [
{
path:'/login',
name:'login',
},
{
path:'/index',
name:'index',
},
{
path:'/detail',
name:'detail',
},
]
const routes = routeOptions.map(route => {
if (!route.component) {
route = {
...route,
component: () => import(`@/views/${route.name}.vue`)
}
}
return route
})
let router = new Router({
routes
})
在書寫更少程式碼的同時,我們也把“魔法註釋”給犧牲掉了。總所周知,程式碼中沒辦法編寫動態註釋。這個問題很尷尬,難道就沒有兩全其美的辦法了嗎?
強大的webpack
來救場了,從 webpack 2.6.0 開始,佔位符 [index] 和 [request] 被支援為遞增的數字或實際解析的檔名。我們可以這樣使用“魔法註釋”:
const routes = routeOptions.map(route => {
if (!route.component) {
route = {
...route,
component: () => import(/* webpackChunkName: "[request]" */ `@/views/${route.name}.vue`)
}
}
return route
})