2019-11-04
Vuex 是什么?
Vuex 是一個(gè)專為 Vue.js 應(yīng)用程序開發(fā)的狀態(tài)管理模式酒甸。它采用集中式存儲(chǔ)管理應(yīng)用的所有組件的狀態(tài)魄健,并以相應(yīng)的規(guī)則保證狀態(tài)以一種可預(yù)測的方式發(fā)生變化。Vuex 也集成到 Vue 的官方調(diào)試工具 devtools extension插勤,提供了諸如零配置的 time-travel 調(diào)試沽瘦、狀態(tài)快照導(dǎo)入導(dǎo)出等高級(jí)調(diào)試功能。
#什么是“狀態(tài)管理模式”农尖?
讓我們從一個(gè)簡單的 Vue 計(jì)數(shù)應(yīng)用開始:
new Vue({
// state
data () {
return {
count: 0
}
},
// view
template: `
<div>{{ count }}</div>
`,
// actions
methods: {
increment () {
this.count++
}
}
})
這個(gè)狀態(tài)自管理應(yīng)用包含以下幾個(gè)部分:
- state析恋,驅(qū)動(dòng)應(yīng)用的數(shù)據(jù)源;
- view卤橄,以聲明方式將 state 映射到視圖绿满;
- actions,響應(yīng)在 view 上的用戶輸入導(dǎo)致的狀態(tài)變化窟扑。
以下是一個(gè)表示“單向數(shù)據(jù)流”理念的簡單示意:
但是喇颁,當(dāng)我們的應(yīng)用遇到多個(gè)組件共享狀態(tài)時(shí),單向數(shù)據(jù)流的簡潔性很容易被破壞:
- 多個(gè)視圖依賴于同一狀態(tài)嚎货。
- 來自不同視圖的行為需要變更同一狀態(tài)橘霎。
對(duì)于問題一,傳參的方法對(duì)于多層嵌套的組件將會(huì)非常繁瑣殖属,并且對(duì)于兄弟組件間的狀態(tài)傳遞無能為力姐叁。對(duì)于問題二,我們經(jīng)常會(huì)采用父子組件直接引用或者通過事件來變更和同步狀態(tài)的多份拷貝。以上的這些模式非常脆弱外潜,通常會(huì)導(dǎo)致無法維護(hù)的代碼原环。
因此,我們?yōu)槭裁床话呀M件的共享狀態(tài)抽取出來处窥,以一個(gè)全局單例模式管理呢嘱吗?在這種模式下,我們的組件樹構(gòu)成了一個(gè)巨大的“視圖”滔驾,不管在樹的哪個(gè)位置谒麦,任何組件都能獲取狀態(tài)或者觸發(fā)行為!
通過定義和隔離狀態(tài)管理中的各種概念并通過強(qiáng)制規(guī)則維持視圖和狀態(tài)間的獨(dú)立性哆致,我們的代碼將會(huì)變得更結(jié)構(gòu)化且易維護(hù)绕德。
這就是 Vuex 背后的基本思想,借鑒了 Flux摊阀、Redux 和 The Elm Architecture耻蛇。與其他模式不同的是,Vuex 是專門為 Vue.js 設(shè)計(jì)的狀態(tài)管理庫驹溃,以利用 Vue.js 的細(xì)粒度數(shù)據(jù)響應(yīng)機(jī)制來進(jìn)行高效的狀態(tài)更新城丧。
如果你想交互式地學(xué)習(xí) Vuex,可以看這個(gè) Scrimba 上的 Vuex 課程豌鹤,它將錄屏和代碼試驗(yàn)場混合在了一起亡哄,你可以隨時(shí)暫停并嘗試。
#什么情況下我應(yīng)該使用 Vuex布疙?
Vuex 可以幫助我們管理共享狀態(tài)蚊惯,并附帶了更多的概念和框架。這需要對(duì)短期和長期效益進(jìn)行權(quán)衡灵临。
如果您不打算開發(fā)大型單頁應(yīng)用截型,使用 Vuex 可能是繁瑣冗余的。確實(shí)是如此——如果您的應(yīng)用夠簡單儒溉,您最好不要使用 Vuex宦焦。一個(gè)簡單的 store 模式就足夠您所需了。但是顿涣,如果您需要構(gòu)建一個(gè)中大型單頁應(yīng)用波闹,您很可能會(huì)考慮如何更好地在組件外部管理狀態(tài),Vuex 將會(huì)成為自然而然的選擇涛碑。引用 Redux 的作者 Dan Abramov 的話說就是:
Flux 架構(gòu)就像眼鏡:您自會(huì)知道什么時(shí)候需要它精堕。
一、先安裝下載vuex
npm install vuex --save
二蒲障、在main.js中引入
import Vue from 'vue'
import App from './App.vue'
import router from "./router/index"
import "./assets/css/common.css"
import "./assets/css/reset.css"
import "./assets/style/theme/default.less"
import store from "./store/index"
import mixin from "./mixin/index";
import 'amfe-flexible'
import $axios from '@/utils/request';
Vue.prototype.$axios = $axios;
// 有贊UI庫引入
import Vant from 'vant';
import 'vant/lib/index.css';
Vue.use(Vant);
Vue.mixin(mixin);
// Vue.config.productionTip = false
new Vue({
render: h => h(App),
router,store
}).$mount('#app')
三歹篓、在src下新建store文件夾瘫证,再新建index.js文件,代碼如下:(在state中定義變量preOrderId,在mutations中獲取到-存值庄撮。)
import Vue from "vue"
import Vuex from "vuex"
import createPersistedState from 'vuex-persistedstate'
Vue.use(Vuex)
const config = {
// 本地持久化
plugins: [createPersistedState()],
state:{
isLogin: false,
username:"",
payWayFlag:false,
token:"",
phone: "",
preOrderId:"",
totalMoney:"",
productNumber:"",
selectAddress:[]
// productId: "",
},
//對(duì)數(shù)據(jù)獲取之前的再次編譯背捌,可以理解為state的計(jì)算屬性。
getters:{
// token: state => state.token,
username: state => state.username,
isLogin: state => state.isLogin
},
mutations:{
updateToken(state,payload){
state.token = payload
},
updateUsername(state,payload){
state.username = payload
},
updateLogin(state,payload){
state.isLogin = payload
},
updatePhone(state,payload){
state.phone = payload
},
updatePreOrderId(state,payload){
state.preOrderId = payload
},
updateTotalMoney(state,payload){
state.totalMoney = payload
},
updateProductNumber(state,payload){
state.productNumber = payload
},
updateSelectAddress(state,payload){
state.selectAddress = payload || {}
},
// updateProductId(state,payload){
// state.productId = payload
// },
// 支付方式頁面的顯示與隱藏
payWayFlagChange(state,payload){
state.payWayFlag = payload
},
// // 獲取用戶名
// login(state,payload){
// }
},
actions:{
},
modules:{
}
}
export default new Vuex.Store(config)
四洞斯、在頁面文件src\pages\cart\children\CatEdit.vue下载萌,
存儲(chǔ)變量的值( this.$store.commit("updatePreOrderId", res.result.preOrderId);)
onSubmit() {
if (!this.isEdit) {
var id = this.cartList.filter(item => {
return item.checked;
});
id.map(item => {
return this.cartsId.push(item.cartId);
});
console.log("this.id", this.cartsId);
let url = "/preOrder/add";
let data = {
totalMoney: this.totalMoney,
cartId: this.cartsId
};
this.$axios
.post(url, data)
.then(res => {
console.log("res-preOrder", res);
this.$store.commit("updatePreOrderId", res.result.preOrderId);
this.$router.push("/order/confirm");
})
.catch(err => {
console.log(err);
});
} else {
let delId = [];
this.checkList = this.cartList.filter(item => {
return item.checked;
});
this.checkList.map(item => {
return delId.push(item.cartId);
});
let url = "/cart/del";
let data = {
cartId: delId
};
this.$axios
.post(url, data)
.then(res => {
console.log(res);
for (let i = 0; i < this.cartList.length; i++) {
for (let j = 0; j < this.checkList.length; j++) {
if (this.cartList[i].cartId == this.checkList[j].cartId) {
this.cartList.splice(i, 1);
}
}
}
})
.catch(err => {
console.log(err);
});
}
},
五、在頁面文件src\pages\order\children\ConfirmOrder.vue下巡扇,
獲取值( let data = {preOrderId: this.$store.state.preOrderId};)
//獲取訂單商品詳情
getPreOrder() {
let url = "/preOrder/detail";
let data = {
preOrderId: this.$store.state.preOrderId
};
console.log("pre-data", data);
this.$axios
.post(url, data)
.then(res => {
console.log("pre-ressult", res.result);
this.preOrderList = res.result;
this.$store.commit("updateTotalMoney", res.result.totalMoney);
if (res.result.totalMoney >= res.result.fullReduceMoney) {
this.preOrderList.expressFee = 0;
} else {
}
})
.catch(err => {
console.log(err);
});
},