Vuex 是一個專為 Vue.js 應用程式開發的狀態管理模式。每一個 Vuex 應用的核心就是 store(倉庫)。「store」 基本上就是一個容器,它包含著你的應用中大部分的狀態 ( state )。
(1)Vuex 的狀態存儲是響應式的。當 Vue 組件從 store 中讀取狀態的時候,若 store 中的狀態發生變化,那麼相應的組件也會相應地得到高效更新。
(2)改變 store 中的狀態的唯一途徑就是顯式地提交 (commit) mutation。這樣使得我們可以方便地跟蹤每一個狀態的變化。
主要包括以下幾個模塊:
· State:定義了應用狀態的數據結構,可以在這裡設置默認的初始狀態。
· Getter:允許組件從 Store 中獲取數據,mapGetters 輔助函數僅僅是將 store 中的 getter 映射到局部計算屬性。
· Mutation:是唯一更改 store 中狀態的方法,且必須是同步函數。
· Action:用於提交 mutation,而不是直接變更狀態,可以包含任意異步操作。
· Module:允許將單一的 Store 拆分為多個 store 且同時保存在單一的狀態樹中。
2、action 和 mutation 區別mutation 是同步更新數據(內部會進行是否為異步方式更新數據的檢測)
內部並不能檢測到是否異步更新,而是實例上有一個開關變量 _committing,
只有在 mutation 執行之前才會把開關打開,允許修改 state 上的屬性。
並且在 mutation 同步執行完成後立刻關閉。
異步更新的話由於已經出了 mutation 的調用棧,此時的開關已經是關上的,自然能檢測到對 state 的修改並報錯。具體可以查看源碼中的 withCommit 函數。這是一種很經典對於 js單線程機制 的利用。
Store.prototype._withCommit = function _withCommit(fn) {
var committing = this._committing
this._committing = true
fn()
this._committing = committing
}
Vuex 是一個專為 Vue.js 應用程式開發的狀態管理模式,Vuex 的狀態存儲是響應式的。
當 Vue 組件從 store 中讀取狀態的時候,若 store 中的狀態發生變化,那麼相應的組件也會相應地得到高效更新。
當多個組件擁有同一個狀態的時候,vuex能夠很好的幫我們處理。、
可以很好的使用vue開發者工具調試vuex的狀態 。
這些優勢是localStorage不能夠很好的模擬的。
4、頁面刷新後vuex的state數據丟失怎麼解決?store裡的數據是保存在運行內存中的,當頁面刷新時,頁面會重新加載vue實例,store裡面的數據就會被重新賦值初始化。
理論上我們是不需要持久存儲vuex的值的,因為請求我們會去接口拿數據,進行重新渲染,和第一次進入一樣 。
但是如果非要保存上一次的臨時狀態,其實可以使用localStorage進行持久化存儲,但是這個時候又得去處理和服務端數據同步的問題。
5、Vuex和localStorage的區別是什麼?1.最重要的區別
vuex存儲在內存
localstorage以文件的方式存儲在本地
localstorage只能存儲字符串類型的數據,存儲對象需要JSON的stringify和parse方法進行處理。讀取內存比讀取硬碟速度要快
2.應用場景
vuex是一個專門為Vue.js應用程式開發的狀態管理模式。它採用集中式存儲管理應用的所有組件的狀態,並以相應的規則保證狀態以一種可預測的方式發生變化。vuex用於組件之間的傳值
localstorage是本地存儲,是將數據存儲到瀏覽器的方法,一般是在跨頁面傳遞數據時使用的
vuex能做到數據的響應式,localstorage不能做到
3.永久性
很多人覺得用localstorage可以代替vuex,對於不變的數據確實可以,但是當兩個組件公用一個數據源(對象或數組)時,如果其中一個組件改變了該數據源,希望另一個組件響應該變化時,localstorage無法做到,原因在區別1那裡
6、vue-router的原理是什麼?實現原理:vue-router的原理就是更新視圖而不重新請求頁面
vue-router可以通過mode參數設置為三種模式:hash模式、history模式、abstract模式。
1.hash模式 默認是hash模式,基於瀏覽器history api,使用window.addEventListener('hashchange',callback,false)對瀏覽器地址進行監聽。
當調用push時,把新路由添加到瀏覽器訪問歷史的棧頂。
使用replace時,把瀏覽器訪問歷史的棧頂路由替換成新路由 hash的值等於url中#及其以後的內容。
瀏覽器是根據hash值的變化,將頁面加載到相應的DOM位置。錨點變化只是瀏覽器的行為,每次錨點變化後依然會在瀏覽器中留下一條歷史記錄,可以通過瀏覽器的後退按鈕回到上一個位置
2.History history模式,基於瀏覽器history api ,使用window.onpopstate對瀏覽器地址進行監聽。
對瀏覽器history api中的pushState()、replaceState()進行封裝,當方法調用,會對瀏覽器的歷史棧進行修改。從而實現URL的跳轉而無需加載頁面 。但是他的問題在於當刷新頁面的時候會走後端路由,所以需要服務端的輔助來兜底,避免URL無法匹配到資源時能返回頁面。
3.abstract 不涉及和瀏覽器地址的相關記錄。
流程跟hash模式一樣,通過數組維護模擬瀏覽器的歷史記錄棧 。服務端下使用。使用一個不依賴於瀏覽器的瀏覽器歷史虛擬管理後臺。
4.總結:
hash模式和history模式都是通過window.addEvevtListenter()方法監聽 hashchange和popState進行相應路由的操作。可以通過back、foward、go等方法訪問瀏覽器的歷史記錄棧,進行各種跳轉。
而abstract模式是自己維護一個模擬的瀏覽器歷史記錄棧的數組。
7、hash路由和history路由實現原理說一下8、請介紹一下你對vue-router的理解?第一,vue-router 有 3 種路由模式:hash、history、abstract,
hash: 使用 URL hash 值來作路由。支持所有瀏覽器,包括不支持 HTML5 History Api 的瀏覽
history : 依賴 HTML5 History API 和伺服器配置。具體可以查看 HTML5 History 模式;
abstract : 支持所有 JavaScript 運行環境,如 Node.js 伺服器端。如果發現沒有瀏覽器的 API,路由會自動強制進入這個模式.
(1)hash 模式的實現原理
早期的前端路由的實現就是基於 location.hash 來實現的。其實現原理很簡單,location.hash 的值就是 URL 中 # 後面的內容。比如,location.hash 的值為 '#search':
hash 路由模式的實現主要是基於下面幾個特性:
URL 中 hash 值只是客戶端的一種狀態,也就是說當向伺服器端發出請求時,hash 部分不會被發送;
hash 值的改變,都會在瀏覽器的訪問歷史中增加一個記錄。因此我們能通過瀏覽器的回退、前進按鈕控制hash 的切換;
可以通過 a 標籤,並設置 href 屬性,當用戶點擊這個標籤後,URL 的 hash 值會發生改變;或者使用 JavaScript 來對 loaction.hash 進行賦值,改變 URL 的 hash 值;
我們可以使用 hashchange 事件來監聽 hash 值的變化,從而對頁面進行跳轉(渲染)。
(2)history 模式的實現原理
HTML5 提供了 History API 來實現 URL 的變化。其中做最主要的 API 有以下兩個:history.pushState() 和 history.repalceState()。這兩個 API 可以在不進行刷新的情況下,操作瀏覽器的歷史記錄。唯一不同的是,前者是新增一個歷史記錄,後者是直接替換當前的歷史記錄,如下所示:
window.history.pushState(null, null, path);
window.history.replaceState(null, null, path);
history 路由模式的實現主要基於存在下面幾個特性:
pushState 和 repalceState 兩個 API 來操作實現 URL 的變化 ;
我們可以使用 popstate 事件來監聽 url 的變化,從而對頁面進行跳轉(渲染);
history.pushState() 或 history.replaceState() 不會觸發 popstate 事件,這時我們需要手動觸發頁面跳轉(渲染)。
第二,說一下導航鉤子函數(導航守衛)
全局守衛
router.beforeEach 全局前置守衛 進入路由之前
router.beforeResolve 全局解析守衛(2.5.0+) 在beforeRouteEnter調用之後調用
router.afterEach 全局後置鉤子 進入路由之後
main.js 入口文件
import router from './router'; // 引入路由
router.beforeEach((to, from, next) => {
next();
});
router.beforeResolve((to, from, next) => {
next();
});
router.afterEach((to, from) => {
console.log('afterEach 全局後置鉤子');
});
路由獨享的守衛
你可以在路由配置上直接定義 beforeEnter 守衛
const router = new VueRouter({
routes: [
{
path: '/foo',
component: Foo,
beforeEnter: (to, from, next) => {
// ...
}
}
]
})
組件內的守衛
你可以在路由組件內直接定義以下路由導航守衛
const Foo = {
template: `...`,
beforeRouteEnter (to, from, next) {
// 在渲染該組件的對應路由被 confirm 前調用
// 不!能!獲取組件實例 `this`
// 因為當守衛執行前,組件實例還沒被創建
},
beforeRouteUpdate (to, from, next) {
// 在當前路由改變,但是該組件被復用時調用
// 舉例來說,對於一個帶有動態參數的路徑 /foo/:id,在 /foo/1 和 /foo/2 之間跳轉的時候,
// 由於會渲染同樣的 Foo 組件,因此組件實例會被復用。而這個鉤子就會在這個情況下被調用。
// 可以訪問組件實例 `this`
},
beforeRouteLeave (to, from, next) {
// 導航離開該組件的對應路由時調用,我們用它來禁止用戶離開
// 可以訪問組件實例 `this`
// 比如還未保存草稿,或者在用戶離開前,
將setInterval銷毀,防止離開之後,定時器還在調用。
}
}
使用location.href='/url'來跳轉,簡單方便,但是刷新了頁面;
使用history.pushState('/url'),無刷新頁面,靜態跳轉;
引進router,然後使用router.push('/url')來跳轉,使用了diff算法,實現了按需加載,減少了dom的消耗。
其實使用router跳轉和使用history.pushState()沒什麼差別的,因為vue-router就是用了history.pushState(),尤其是在history模式下。
10、怎麼定義 vue-router 的動態路由? 怎麼獲取傳過來的值?在router目錄下的index.js文件中,對path屬性加上/:id。使用router對象的params.id。
{
name: 'monitor',
path: '/monitor/:projectInfo',
component: () => import('@/pages/monitor/Index'),
meta: {
breadcrumbName: 'ViewRecorder',
parentParam: true
}
}
第一種:vue異步組件技術:異步加載,vue-router配置路由 , 使用vue的異步組件技術 , 可以實現按需加載 .但是,這種情況下一個組件生成一個js文件。
第二種:路由懶加載(使用import)。
第三種:webpack提供的require.ensure(),vue-router配置路由,使用webpack的require.ensure技術,也可以實現按需加載。這種情況下,多個路由指定相同的chunkName,會合併打包成一個js文件。
const routes = [
{
path: '/login',
name: 'login',
component: () => import('@/pages/Login')
},
{
path: '/',
name: 'main',
component: () => import('@/pages/Main'),
children: [{
name: 'index',
path: '',
component: () => import('@/pages/system/Index'),
meta: {
breadcrumbName: 'HomePage'
}
},
]
用法:query要用path來引入,params要用name來引入