Vue面試題(二)
theme: qklhk-chocolate
六、 vue-router路由高頻考題
1. vue-router是什麼?
這裡的路由就是SPA(單頁應用)的路徑管理器,vue-router是Vue.js官方的路由外掛,它和Vue是深度整合的,適合用於構建單頁面應用。Vue的單頁面應用是基於路由和元件的,路由用於設定訪問路徑,並將路徑和元件對映起來。
路由模組的本質:就是建立起url和頁面之間的對映關係
至於我們為啥不能用a標籤,這是因為用Vue做的都是單頁應用(當你的專案準備打包時,執行npm run build時,就會生成dist資料夾,這裡面只有靜態資源和一個index.html頁面),所以你寫的標籤是不起作用的,你必須使用vue-router來進行管理
2. vue-router的實現原理
SPA:單一頁面應用程式,只有一個完整的頁面;它在載入頁面的時候,不會載入整個頁面,而是隻更新某個指定容器中的內容。
單頁面應用(SPA)的核心之一:更新檢視而不重新請求頁面;vue-router在實現單頁面前端路由時,提供了兩種方式:Hash模式和History模式,根據mode引數來決定採用哪一種方式。
2.1 Hash模式
vue-router預設hash模式--使用URL的hash來模擬一個完整的URL,於是當URL改變時,頁面不會重新載入。
hash(#)是URL的錨點,代表的是網頁中的一個位置,單單改變#後面的部分,瀏覽器只會滾動到相應的位置,不會重新載入網頁,也就是說 hash出現在URL中,但不會被包含在http請求中,對後端完全沒有影響,因此改變hash不會重新載入頁面;
同時每一次改變#後面的部分,都會在瀏覽器的訪問歷史中增加一個記錄,使用“後退”按鈕,就可以回到上一個位置;所以說 Hash模式通過錨點值的改變,根據不同的值,渲染指定DOM位置的不同資料。hash模式的原理是通過location.hash = "/hashpath"
的方式修改瀏覽器的hash值,通過onhashchange
事件(監測hash值變化),可以在window上監聽這個事件
2.2 History模式
由於hash模式會在url中自帶#,如果不想要很醜的 hash,我們可以用路由的 history 模式,只需要在配置路由規則時,加入"mode: 'history'"
這種模式充分利用了html5 history interface 中新增的pushState() 和 replaceState() 方法。這兩個方法應用於瀏覽器記錄棧,在當前已有的 back、forward、go 基礎之上,它們提供了對歷史記錄修改的功能。只是當它們執行修改時,雖然改變了當前的 URL ,但瀏覽器不會立即向後端傳送請求。可以通過監聽popstate事件監聽history變化,也就是點選瀏覽器的前進或者後退功能時觸發。
js
//main.js檔案中
const router = new VueRouter({
mode: 'history',
routes: [...]
})
當你使用 history 模式時,URL 就像正常的 url,例如 yoursite.com/user/id,
不過這種模式要玩好,還需要後臺配置支援。因為我們的應用是個單頁客戶端應用,如果後臺沒有正確的配置,當用戶在瀏覽器直接訪問 oursite.com/user/id 就會返回 404 ,這就不好看了。 所以呢,你要在服務端增加一個覆蓋所有情況的候選資源:如果 URL 匹配不到任何靜態資源,則應該返回同一個 index.html頁面,這個頁面就是你 app 依賴的頁面。
js
export const routes = [
{path: "/", name: "homeLink", component:Home}
{path: "/register", name: "registerLink", component: Register},
{path: "/login", name: "loginLink", component: Login},
{path: "*", redirect: "/"}]
此處就設定如果URL輸入錯誤或者是URL 匹配不到任何靜態資源,就自動跳到到Home頁面
2.3使用路由模組來實現頁面跳轉的方式
- 直接修改位址列
- this.$router.push("路由地址")
- < router-link :to="路由地址"> 樣式類似於a標籤
3. vue-router使用方式
- 下載 npm i vue-router -S
- 在main.js中引入 import VueRouter from 'vue-router'
- 安裝外掛 Vue.use(VueRouter)
- 建立路由物件並配置路由規則 let router=new VueRouter({router: [{path:'/home',component:Home}]})
- 將其路由物件傳遞給路由例項,options中加入 router:router
- 在app.vue中留位置
<router-view></router-view>
4. vue-router引數傳遞
宣告式導航 <router-link :to="">
和程式設計式的導航 router.push(...)
都可以傳參,接下來介紹前者的傳參方式,同樣的規則也適用於程式設計式的導航
```js
this.$router.push({name:xxx,params:{key:value}}) ```
params傳參(不顯示在路由)
路由必須配置name:
js
{
path: '/child,
name: 'Child',
component: Child
}
傳遞引數:通過name ```js
//父路由程式設計式傳參(一般通過事件觸發) this.$router.push({ name:'Child', params:{ id:123 } })
``
使用
$route.params.id`來進行接收
params傳參(顯示在路由)
在路由中如下配置:
js
//接收引數的頁面路由
{
path:'/params/:newsId/:newsTitle',
component:Params
}
傳遞引數: ```js //父路由程式設計式傳參(一般通過事件觸發) this.$router.push({ path:'/params/newsIdValue/newsTitleValue', })
```
使用 $route.params.newsId
來進行接收
query傳參
```js
this.$router.push({ name:'Query',query: { queryId: status }}) ```
對應路由配置:
js
{
path: '/query',
name: 'Query',
component: Query
}
於是我們可以獲取引數:
this.$route.query.queryId
params和query兩種傳參方式的區別
-
區別一:
使用params傳參(路徑必須使用name指定):
js this.$router.push({ name:"detail", //params對應的是name,並且name不能加"/",不能使用 params:{ name:'nameValue', code:10011 } });
使用query傳參(路徑使用name或者path都可以)js this.$router.push({ name:"detail", (path:"/detial") query:{ name:'nameValue', code:10011 } });
-
區別二:query更加類似於我們ajax中get傳參,params則類似於post,說的再簡單一點,前者在瀏覽器位址列中顯示引數,後者則不顯
- 區別三:獲取值的方法不同
- 區別四:query傳值頁面重新整理資料還在,而params傳值不在路由顯示的會消失,在路由顯示的不會消失
5. vue-router配置子路由(二級路由)
在User中加入
html
<template>
<div class="hello">
<h1>{{ msg }}</h1>
<router-view></router-view>
</div>
</template>
之後將 Profile和Posts兩個元件的路由寫在 User的children中
js
routes: [
{
path: '/',
name: 'User',
component: User,
children: [
//子路由的<router-view>User.vue中出現
{path: '/Profile', name: 'Profile', component: Profile},
{path: '/Posts', name: 'Posts', component: Posts}
]
}
]
6. 單頁面多路由區域操作
在一個頁面裡我們有兩個以上<router-view>
區域,我們通過配置路由的js檔案,來操作這些區域的內容
- App.vue檔案,在
<router-view>
下面新寫了兩行<router-view>
標籤,並加入了些CSS樣式
html
<template>
<div id="app">
<img src="./assets/logo.png">
<router-link :to="{name:'HelloWorld'}"><h1>H1</h1></router-link>
<router-link :to="{name:'H1'}"><h1>H2</h1></router-link>
<router-view></router-view>
<router-view name="left" style="float:left;width:50%;background-
color:#ccc;height:300px;"/>
<router-view name="right" style="float:right;width:50%;background-
color:yellowgreen;height:300px;"/>
</div>
</template>
2. 需要在路由裡配置這三個區域,配置主要是在components欄位裡進行
js
export default new Router({
routes: [
{
path: '/',
name: 'HelloWorld',
components: {
default: HelloWorld,
left:H1,//顯示H1元件內容'I am H1 page,Welcome to H1'
right:H2//顯示H2元件內容'I am H2 page,Welcome to H2'
}
},
{
path: '/h1',
name: 'H1',
components: {
default: HelloWorld,
left:H2,//顯示H2元件內容
right:H1//顯示H1元件內容
}
}
]
})
7. $router
和$route
的區別
$route 是“路由資訊物件”,包括 path,params,hash,query,fullPath,matched,name 等路由資訊引數。
① $route.path
字串,對應當前路由的路徑,總是解析為絕對路徑,如 "/order"。
② $route.params
一個 key/value 物件,包含了 動態片段 和 全匹配片段, 如果沒有路由引數,就是一個空物件。
③ $route.query
一個 key/value 物件,表示 URL 查詢引數。 例如,對於路徑 /foo?user=1,則有$route.query.user為 1 , 如果沒有查詢引數,則是個空物件。
④ $route.hash
當前路由的 hash 值 (不帶 #) ,如果沒有 hash 值,則為空字串。
⑤ $route.fullPath
完成解析後的 URL,包含查詢引數和 hash 的完整路徑。
⑥ $route.matched
陣列,包含當前匹配的路徑中所包含的所有片段所對應的配置引數物件。
⑦ $route.name
當前路徑名字
$router 是“路由例項”物件,即使用 new VueRouter建立的例項,包括了路由的跳轉方法,鉤子函式等。
$router常見跳轉方法:
this.$router.go(-1)//跳轉到上一次瀏覽的頁面
this.$router.replace('/menu')//指定跳轉的地址
this.$router.replace({name:'menuLink'})//指定跳轉路由的名字下
this.$router.push('/menu')//通過push進行跳轉
this.$router.push({name:'menuLink'})//通過push進行跳轉路由的名字下
router.push和router.replace的區別:
- 使用push方法的跳轉會向 history 棧新增一個新的記錄,當我們點選瀏覽器的返回按鈕時可以看到之前的頁面。
- 使用replace方法不會向 history 新增新記錄,而是替換掉當前的 history 記錄,即當replace跳轉到的網頁後,‘後退’按鈕不能檢視之前的頁面。
8. 設定 404 頁面
使用者會經常輸錯頁面,當用戶輸錯頁面時,我們希望給他一個友好的提示頁面,這個頁面就是我們常說的 404 頁面。vue-router也為我們提供了這樣的機制。
- 設定我們的路由配置檔案(/src/router/index.js)
js
{
path:'*',
component:Error
}
這裡的path:'*'就是輸入地址不匹配時,自動顯示出Error.vue的檔案內容
- 在/src/components/資料夾下新建一個Error.vue的檔案。簡單輸入一些有關錯誤頁面的內容。
```html
```
9. vue-router如何響應路由引數的變化
當使用路由引數時,例如從 /user/foo導航到 user/bar, 原來的元件例項會被複用,因為兩個路由都渲染同一個元件,比起銷燬在建立,複用則顯得非常有效。不過,這意味著元件的生命週期鉤子函式不會再被呼叫
舉個例子:比如動態路由articleDeail/:id
,當從路由articleDeail/123
跳轉到articleDeail/234
的時候,兩個路由都渲染同一個元件
複用元件時,想對路由引數的變化作出響應的話, 可以watch (監測變化) $route 物件:
js
const User = {
template: '...',
watch: {
'$route' (to, from) {
// 對路由變化作出響應...
}
}
}
或者使用 2.2 中引入的 beforeRouteUpdate 守衛:
js
const User = {
template: '...',
beforeRouteUpdate (to, from, next) {
// react to route changes...
// don't forget to call next()
}
}
10.完整的vue-router導航解析流程
- 導航被觸發
- 在失活的元件裡呼叫離開守衛
- 呼叫全域性的 beforeEach 守衛
- 在重用的元件裡呼叫 beforeRouteUpdate 守衛 (2.2+)
- 在路由配置裡呼叫 beforeEnter
- 解析非同步路由元件
- 在被啟用的元件裡呼叫 beforeRouteEnter
- 呼叫全域性的 beforeResole 守衛 (2.5+)
- 導航被確認
- 呼叫全域性的 afterEach 鉤子
- 觸發 DOM 更新
- 用建立好的例項呼叫 beforeRouteEnter 守衛中傳給 next 的回撥函式
導航守衛
導航:表示路由正在發生改變
每個守衛方法接收三個引數:
- to: Route: 即將要進入的目標 路由物件
- from: Route: 當前導航正要離開的路由
- next: Function: 一定要呼叫該方法來 resolve 這個鉤子。執行效果依賴 next 方法的呼叫引數。
- next(): 進行管道中的下一個鉤子。如果全部鉤子執行完了,則導航的狀態就是conrmed (確認的)。
- next(false): 中斷當前的導航。如果瀏覽器的 URL 改變了 (可能是使用者手動或者瀏覽器後退按鈕),那麼 URL 地址會重置到 from 路由對應的地址。
- next('/') 或者 next({ path: '/' }): 跳轉到一個不同的地址。當前的導航被中斷,然後進行一個新的導航。你可以向 next 傳遞任意位置物件,且允許設定諸如 replace: true、name: 'home' 之類的選項以及任何用在 router-link 的 to prop 或router.push 中的選項。
- next(error): (2.4.0+) 如果傳入 next 的引數是一個 Error 例項,則導航會被終止且該錯誤會被傳遞給 router.onError() 註冊過的回撥。
確保要呼叫 next 方法,否則鉤子就不會被 resolved。
記住引數或查詢的改變並不會觸發進入/離開的導航守衛。你可以通過觀察 $route 物件來應對這些變化,或使用 beforeRouteUpdate 的元件內守衛。
- 全域性前置導航( router.beforeEach )
當一個導航觸發時,全域性前置守衛按照建立順序呼叫。守衛是非同步解析執行,此時導航在所有守衛resolve之前一直處於等待中。
- 全域性解析守衛( router.beforeResolve )
在導航被確認之前,同時在所有元件內守衛和一步路由元件被解析之後,解析守衛就被呼叫
- 全域性後置鉤子( beforeEnter )
這些鉤子不會接受next函式也不會改變導航本身
- 路由獨享的守衛 ( beforeEnter )
直接在路由配置上直接定義,這些與全域性前值守衛的方法引數一樣
5.元件內的守衛( beforeRouteEnter、beforeRouteUpdate、beforeRouteLeave )
13.vue-router的動態路由匹配以及使用
動態路徑匹配:即把某種模式匹配到的所有路由,全都對映到同個元件。使用動態路由引數來實現。
例如,我們有一個 User 元件,對於所有ID 各不相同的使用者,都要使用這個元件來渲染。那麼,我們可以在vue-router的路由路徑中使用“動態路徑引數”(dynamic segment)來達到這個效果。
舉例:A頁面中是一個使用者列表,點選每一個使用者都會進入使用者詳情頁B,每個使用者的詳情都是在B頁面展示的,這時就會用到路由匹配,即可以在路由位置寫 path:'/user/:id',這樣就可以通過不同的id獲取不同的使用者資訊在同一個B頁面顯示了。
14.vue-router實現路由懶載入(動態載入路由)
當打包構建應用時,JavaScript包會變得非常大,影響頁面載入。如果我們能把不同路由對應的元件分割成不同的程式碼塊,然後當路由被訪問的時候才載入對應元件,這樣就更高效了。
結合Vue的非同步元件和 webpack的程式碼分割功能,輕鬆實現路由元件的懶載入
首先,可以將非同步元件定義為返回一個Promise的工廠函式(該函式返回的Promise應該resolve元件本身)
js
const Foo = () => Promise.resolve({ /* 元件定義物件 */ })
第二,在webpack中,可以使用動態import語法來定義程式碼分快點(split point)
注意: 如果您使用的是 Babel,你將需要新增 syntax-dynamic-import 外掛,才能使 Babel 可以正確地解析語法。
結合這兩者,這就是如何定義一個能夠被 Webpack 自動程式碼分割的非同步元件。
js
const Foo = () => import('./Foo.vue')
在路由配置中什麼都不需要改變,只需要像往常一樣使用 Foo:
```js const router = new VueRouter({ routes: [ { path: '/foo', component: Foo } ] })
import Vue from 'vue' import VueRouter from 'vue-router'
Vue.use(VueRouter)
export default new VueRouter({ routes: [ { path: '/', name: 'Navigator', component: () => import(/ webpackChunkName: "navigator" / './../components/Navigator') }, { path: '/tucao', name: 'Tucao', component: () => import(/ webpackChunkName: "tucao" / './../components/Tucao') } ] }) ``` 以上是按照官方文件寫的懶載入程式碼,但是發現chunk命名並沒生效 ,再去仔細看看官方文件說明
“結合 Vue 的非同步元件和 Webpack 的程式碼分割功能,輕鬆實現路由元件的懶載入”
其實還差一個webpack配置,就是webpack output需要加個chunkFilename
js
chunkFilename: '[name].js'
七、vuex狀態管理高頻試題
1.前言
當我們的應用遇到多個元件共享狀態時,會需要多個元件依賴於同一狀態亦或是來自不同檢視的行為需要變更同一狀態。以前的解決辦法: - 將資料以及操作資料的行為都定義在父元件 - 將資料以及操作資料的行為傳遞給需要的各個子元件(有可能需要多級傳遞)
傳參的方法對於多層巢狀的元件將會非常繁瑣,並且對於兄弟元件間的狀態傳遞無能為力。在搭建下面頁面時,你可能會對 vue 元件之間的通訊感到崩潰 ,特別是非父子元件之間通訊。此時就應該使用vuex,輕鬆可以搞定元件間通訊問題。
2.什麼是Vuex
Vuex是一個專為Vue.js應用程式開發的狀態管理模式。它採用集中式儲存管理應用的所有元件的狀態,並以相應的規則保證狀態以一種可預測的方式發生變化。這裡的關鍵在於集中式儲存管理。
簡單來說,vue應用中多個元件的共享狀態進行集中式的管理(讀/寫)
3. Vuex的原理是什麼
3.1 簡要介紹vuex原理
vuex實現了一個單向資料流,在全域性有一個State存放資料,當元件要更改State中的資料時,必須通過Mutation進行,Mutation同時提供了訂閱者模式供外部外掛呼叫獲取State資料的更新。而當所有(常見於呼叫後端介面非同步獲取更新資料)非同步或批量的同步操作需要走Action,但Action也是無法直接修 改State的,還是需要通過Mutation來修改State的資料。最後,根據State的變化,渲染到檢視上。
3.2 簡要介紹各模組在流程中的功能
Vue Components:Vue元件。HTML頁面上,負責接收使用者操作等互動行為,執行dispatch方法觸發,對應action進行迴應。
dispatch:操作行為觸發方法,是唯一能執行action的方法。
actions:操作行為處理模組,由元件中的$store.dispatch('action 名稱', data1)來觸發。然後由commit()來觸發mutation的呼叫 , 間接更新 state。負責處理Vue Components接收到的所有互動行為。包含同步/非同步操作,支援多個同名方法,按照註冊的順序依次觸發。向後臺API請求的操作就在這個模組中進行,包括觸發其他action以及提交mutation的操作。該模組提供了Promise的封裝,以支援action的鏈式觸發。
commit:狀態改變提交操作方法。對mutation進行提交,是唯一能執行mutation的方法。
mutations:狀態改變操作方法,由actions中的commit('mutation 名稱')來觸發。是Vuex修改state的唯一推薦方法。該方法只能進行同步操作,且方法名只能全域性唯一。操作之中會有一些hook暴露出來,以進行state的監控等。
state:頁面狀態管理容器物件。集中儲存Vue components中data物件的零散資料,全域性唯一,以進行統一的狀態管理。頁面顯示所需的資料從該物件中進行讀取,利用Vue的細粒度資料響應機制來進行高效的狀態更新。
getters:state物件讀取方法。圖中沒有單獨列出該模組,應該被包含在了render中,Vue Components通過該方法讀取全域性state物件。
3.3.Vuex與localStorage
vuex 是 vue 的狀態管理器,儲存的資料是響應式的。但是並不會儲存起來,重新整理之後就回到了初始狀態。
具體做法應該在vuex裡資料改變的時候把資料拷貝一份儲存到localStorage裡面,重新整理之後,如果localStorage裡有儲存的資料,取出來再替換store裡的state。
```js let defaultCity = "上海" try { // 使用者關閉了本地儲存功能,此時在外層加個try...catch if (!defaultCity){ defaultCity =JSON.parse(window.localStorage.getItem('defaultCity')) } }catch(e){}
export default new Vuex.Store({ state: { city: defaultCity }, mutations: { changeCity(state, city) { state.city = city try { window.localStorage.setItem('defaultCity', JSON.stringify(state.city)); // 資料改變的時候把資料拷貝一份儲存到localStorage裡面 } catch (e) {} } } }) ``` 這裡需要注意的是:由於vuex裡,我們儲存的狀態,都是陣列,而localStorage只支援字串,所以需要用JSON轉換:
js
JSON.stringify(state.subscribeList); // array -> string
JSON.parse(window.localStorage.getItem("subscribeList")); // string
-> array
4. 什麼時候使用Vuex
雖然 Vuex 可以幫助我們管理共享狀態,但也附帶了更多的概念和框架。這需要對短期和長期效益進行權衡。 如果您的應用夠簡單,您最好不要使用 Vuex,因為使用 Vuex 可能是繁瑣冗餘的。一個簡單的global event bus 就足夠您所需了。但是,如果您需要構建一箇中大型單頁應用,您很可能會考慮如何更好地在元件外部管理狀態,Vuex 將會成為自然而然的選擇。
5. 如何使用Vuex
- 建立一個store.js檔案 ```js import Vue from 'vue' import Vuex from 'vuex' Vue.use(Vuex)
const store = new Vuex.Store({ state: { count: 0 }, mutations: {// 包含了多個直接更新state函式的物件 INCREMENT(state) { state.count = state.count + 1; }, DECREMENT(state) { state.count = state.count - 1; } }, getters: { // 當讀取屬性值時自動呼叫並返回屬性值 evenOrOdd(state) { return state.count % 2 === 0? "偶數" : "奇數"; } }, actions: { // 包含了多個對應事件回撥函式的物件 incrementIfOdd({ commit, state }) { // 帶條件的action if (state.count % 2 === 1) { commit('INCREMENT') } }, incrementAsync({ commit }) { //非同步的action setInterval(() => { commit('INCREMENT') }, 2000); }
}
}) export default store //用export default 封裝程式碼,讓外部可以引用
2. 在main.js中引入store.js檔案
js
import store from './store'
new Vue({
el: '#app',
router,
store,//註冊上vuex的store: 所有元件物件都多一個屬性$store
components: { App },
template: '
3. 建立一個模板
js
``` 由於 store 中的狀態是響應式的,當 Vue 元件從 store 中讀取狀態的時候,若 store 中的狀態發生變化,那麼相應的元件也會相應地得到高效更新。在元件中呼叫 store 中的狀態簡單到僅需要在計算屬性中返回即可。改變store 中的狀態的唯一途徑就是顯式地提交 (commit) mutations。
如何通mapState等輔助函式優化上面程式碼?
js
import { mapActions, mapGetters, mapState, mapMutations } from "vuex";
...
computed: {
...mapState(["count"]),
...mapGetters(["evenOrOdd"])
}
methods: {
...mapActions(["incrementIfOdd", "incrementAsync"]),
...mapMutations(["increment", "decrement"])
}
有點必須要注意:HelloWorld.vue檔案中increment函式名稱要跟store.js檔案mutations中一致,才可以寫成 ...mapMutations(["increment", "decrement"]),同樣的道理,incrementIfOdd和incrementAsync也要和store.js檔案actions保持一致。
注意點:
- 如何理解getters
getters表面是獲得的意思,可以把它看做在獲取資料之前進行的一種再編輯,相當於對資料的一個過濾加工。getters就像計算屬性一樣,getter的返回值會根據他們的依賴被快取起來,且只有當它的以來只發生了變化才會被重新計算。
- actions和mutations的區別
actions和上面的Mutations功能基本一樣,不同點是,actions是非同步的改變state狀態,而Mutations是同步改變狀態。
6. Vuex和單純的全域性物件有以下兩點不同(重點)
- Vuex的狀態儲存是響應式的。當Vue元件從store中讀取狀態的時候,那麼相應的元件也會相應的得到高效更新。
- 你不能直接改變store中的狀態。改變store中的狀態的唯一途徑就是顯式地提交(commit)mutation。這樣使得我們可以方便的跟蹤每一個狀態的變化,從而讓我們能夠實現一些工具幫助我們更好地瞭解我們的應用。
7.vuex在vue-cli中的應用
第一步:npm下載vuex資源包:
npm install vuex --save
第二步:在 src/main.js 中引入
```js import Vue from 'vue'
import Vuex from 'vuex' Vue.use(Vuex)
import store from './vuex/store' ``` 第三步:在 src 下 新建 vuex 資料夾
vuex下:
* modelus //資料夾,存放不同模組需要的共享狀態檔案
* index.js
* 等
*store.js
*types.js
說明:
vuex資料夾下store.js:
```js import Vue from 'vue' import Vuex from 'vuex' //引入不同模組需要的共享變數: import index from './modules/index'
//使用vuex Vue.use(Vuex)
//對外暴露 export default new Vuex.Store({ modules: { index } }) ``` vuex資料夾下 modelus資料夾下 index.js:
```js
//引入一個常量,保證 action 和 mutations 的統一。 import * as types from '../types' /* * App通用配置 / const state = { //vuex初始化值 count: 0 } const actions = { increment({ commit }, n) { commit(types.TEST_INCREMENT, n) }, decrement({ commit }, state) {
commit(types.TEST_DEREMENT, state)
}
} const getters = { count: state => state.count } const mutations = { types.TEST_INCREMENT { console.log(n); state.count = state.count + 5 + n }, types.TEST_DEREMENT { state.count = state.count - 3 } } export default { state, actions, getters, mutations } ``` vuex資料夾下type.js:
js
//暴露常量
export const TEST_INCREMENT='TEST_INCREMENT'
export const TEST_DEREMENT='TEST_DEREMENT'
八、vue如何優化首屏載入速度?
問題描述:
在Vue專案中,引入到工程中的所有js、css檔案,編譯時都會被打包進vendor.js,瀏覽器在載入該 檔案之後才能開始顯示首屏。若是引入的庫眾多,那麼vendor.js檔案體積將會相當的大,影響首 屏的體驗。
解決方法是:
將引用的外部js、css檔案剝離開來,不編譯到vendor.js中,而是用資源的形式引用,這樣瀏覽器 可以使用多個執行緒非同步將vendor.js、外部的js等載入下來,達到加速首開的目的。外部的庫檔案, 可以使用CDN資源,或者別的伺服器資源等。
幾種常用的優化方法:
- 使用npm run build --report命令進行大檔案定位
- 路由的按需載入
-
將打包生成後 index.html頁面 裡面的JS檔案引入方式放在 body 的最後
-
用文件的cdn檔案代替 npm 安裝包
- UI庫的按需載入
- 開啟 Gzip 壓縮
詳解:
1 、大檔案定位:
我們可以使用 webpack視覺化外掛Webpack Bundle Analyzer檢視工程js檔案大小,然後有目的的 解決過大的js檔案。 使用命令:
npm run build --report
2 、路由的按需載入
3 、將JS檔案引入方式放在 body 的最後 :
預設情況下,build 後的 index.html 中,js 的引入是在 head 中,使用html-webpack-plugin插 件,將inject的值改為body。就可以將 js 引入放到 body 最後。
首先下載外掛:(一般vue-cli專案裡預設有,可以package.json裡面檢查是否含有)
npm install [email protected] --save-dev
在 build資料夾下webpack.base.conf.js配置:
js
var htmlWebpackPlugin = require('html-webpack-plugin')
module.exports = {
entry: './src/script/main.js',
output: {
filename: 'js/bundle.js',
path: path.resolve(__dirname, 'dist')
},
plugins: [
new htmlWebpackPlugin({
inject: 'body'
})
]
}
即在 plugins 裡面加上 htmlWebpackPlugin 外掛。
4 、用文件的cdn檔案代替 npm 安裝包:
用文件的cdn檔案代替,而不用打包到vender裡面去。具體的做法是:
1 、在index.html裡面引入依賴庫js檔案
``` // index.html
``` 2 、在mian.js裡面去掉第三方js的import,因為在第一步已經通過script標籤引用進來了。
3 、把第三方庫的js檔案從打包檔案裡去掉
即在 build/webpack.base.conf.js檔案的module裡面與rules同層加入externals:
5 、UI庫的按需載入:
一般 UI庫 都提供按需載入的方法,按照文件即可配置。
6.、開啟 Gzip 壓縮
在 cong/index.js 設定 productionGzip 為 true,開啟 Gzip 壓縮