一、合理利用watch的immediate屬性
例如在組件創建時需要獲取一次數據列表,然後監聽數據的變化,根據數據改變重新獲取列表。通常這麼寫:
created(){
this.fetchPostList()
},
watch: {
changeValue(){
this.fetchPostList()
}
}
但是上面的這種寫法我們可以精簡寫成如下:
watch: {
changeValue:{
handler: 'fetchPostList',
immediate: true
}
}
聲明 immediate:true
, 表示創建的時候立即執行一次。
二、利用require.context()進行組件引入和註冊
一般情況下,組件寫法如下:
import BaseButton from './baseButton'
import BaseIcon from './baseIcon'
import BaseInput from './baseInput'
export default {
components: {
BaseButton,
BaseIcon,
BaseInput
}
}
<BaseInput v-model="searchText" @keydown.enter="search" />
<BaseButton @click="search"> <BaseIcon name="search"/></BaseButton>
一般步驟有三步:
- 引入
- 註冊組件
- 正式使用
這是最常見和通用的寫法。但是如果組件過多,則要引入多次,註冊多次。
我們可以藉助一下webpack,使用 require.context() 方法來創建自己的(模塊)上下文,從而實現自動動態require組件。
思路是:在src文件夾下面main.js中,藉助webpack動態地將需要的基礎組件統統打包進來。
代碼如下:
一些方法解釋: upperFirst 、camelCase 、require.context()
import Vue from 'vue'
import upperFirst from 'lodash/upperFirst'
import camelCase from 'lodash/camelCase'
// Require in a base component context
const requireComponent = require.context(
‘./components', false, /base-[\w-]+\.vue$/
)
requireComponent.keys().forEach(fileName => {
// Get component config
const componentConfig = requireComponent(fileName)
// Get PascalCase name of component
const componentName = upperFirst(
camelCase(fileName.replace(/^\.\//, '').replace(/\.\w+$/, ''))
)
// Register component globally
Vue.component(componentName, componentConfig.default || componentConfig)
})
這樣我們引入組件只需要第三步就可以了:
<BaseInput v-model="searchText" @keydown.enter="search" />
<BaseButton @click="search">
<BaseIcon name="search" /></BaseButton>
三、精簡vuex的modules引入
對於vuex,我們輸出store寫法如下:
import auth from './modules/auth'
import posts from './modules/posts'
import comments from './modules/comments'
...
export default new Vuex.Store({
modules: {
auth,
posts,
comments,
...
}
})
要引入很多modules,然後再註冊到Vuex.Store中。。
精簡的做法也是運用 require.context()讀取文件,代碼如下:
import camelCase from 'lodash/camelCase'
const requireModule = require.context('.', false, /\.js$/)
const modules = {}
requireModule.keys().forEach(fileName => {
// Don't register this file as a Vuex module
if (fileName === './index.js') return
const moduleName = camelCase(
fileName.replace(/(\.\/|\.js)/g, '')
)
modules[moduleName] = {
namespaced: true,
...requireModule(fileName),
}
})
export default modules
這樣我們只需如下代碼就可以了:
import modules from './modules'
export default new Vuex.Store({
modules
})
四、組件的異步加載(按需加載組件)
在平時的demo中,可能不會遇見這個需求。當頁面很多,組件很多的時候,SPA頁面在首次加載的時候,就會變的很慢。這是因爲vue首次加載的時候把可能一開始看不見的組件也一次加載了,這個時候就需要對頁面進行優化,就需要異步組件了。
在路由index.js裏(路徑: src/router/index.js
),通過require方式或者import()方式動態加載組件。像下面這樣:
{
path: '/home',
name: 'home',
component:require('@views/home').default
}
或者
{
path: '/home',
name: 'home',
component:() => import('@views/home')
}
五、通過router :key
進行組件刷新
首先默認使用的是Vue-router來實現路由的控制。假設現在在寫一個網站,需求是從
/post/a
跳轉到/post/b
。然後我們就會發現,頁面跳轉後數據竟然沒更新?!原因是vue-router “智能地” 發現這是同一個組件,然後它就決定要複用這個組件,所以在created函數裏寫的方法全部沒有執行。
通常的解決方案是監聽$route的變化來初始化數據,如下:
data() {
return {
loading: false,
error: null,
post: null
}
},
watch: {
'$route': {
handler: 'resetData',
immediate: true
}
},
methods: {
resetData() {
this.loading = false
this.error = null
this.post = null
this.getPost(this.$route.params.id)
},
getPost(id){}
}
問題是解決了,但是這樣的處理方式不夠優雅。我們希望代碼這樣寫:
data() {
return {
loading: false,
error: null,
post: null
}
},
created () {
this.getPost(this.$route.params.id)
},
methods () {
getPost(postId) {
...
}
}
如何達到這樣的效果:給router-view添加一個唯一的key
,這樣只要url
變化了,就一定會重新創建這個組件。就避免了vue-rouer因爲複用組件導致created函數中的方法不執行的問題。
<router-view :key="$route.fullpath"></router-view>
注: 這個一般應用在子路由裏面,這樣纔可以避免大量重繪,假設App.vue根目錄添加這個屬性,那麼每次點擊改變地址都會重繪!