在这几个过程中都可以在网上查找优秀的博客文章辅助理解学习。
最后可以通过 5W1H 来检验自己对技术的掌握程度。
对于 vuex 相关的面试题,我们可以从vuex 是什么?为什么要使用 vuex ? 适用于哪些场景?如何使用 vuex ? 它的实现原理是什么样的?这几个方面准备。以下是简洁描述,具体的需要参照 vuex 的官网进行学习。
根据官网上的描述,vuex是一个专为vue.js应用程序开发的状态管理模式。
它采用集中式存储/管理 应用的所有组件的状态,并以相应的规则保证 状态以一种可预测的方式发生变化。
当应用遇到多个组件共享状态的时候,可能会出现,多个视图依赖于同一状态,来自不用视图的行为需要变更同一状态;像这种比较复杂的数据传递问题,就可以使用 vuex 帮助我们进行开发。
有五种,分别是 State、 Getter、Mutation 、Action、 Module
mutations 里面的每个函数都会有一个 state 参数,这样就可以在 mutations 里面进行 state 的数据修改,当数据修改完毕后,会传导给页面。页面的数据也会发生改变。
当组件进行数据修改的时候我们需要调用 dispatch 来触发 actions 里面的方法。actions 里面的每个方法中都会有一个 commit 方法,当方法执行的时候会通过 commit 来触发 mutations 里面的方法进行数据的修改。
通过 vuex 基础知识的学习,根据官网的示例,我们可以进行实战训练。先来做一个简单的 demo。实现的效果很简单,直接看图。
首先创建一个vue项目
vue init webpack projectName
安装vuex
npm install vuex --save
在 src 下创建一个 store 目录, 新建以下文件:
在 main.js 中引入和使用
import Vue from ‘vue‘
import App from ‘./App‘
import router from ‘./router‘
import Vuex from "vuex"
import store from "./store"
Vue.config.productionTip = false
Vue.use(Vuex)
/* eslint-disable no-new */
new Vue({
el: ‘#app‘,
router,
store,
components: { App },
template: ‘<App/>‘
})
在 index.js 中
import Vue from ‘vue‘
import Vuex from ‘vuex‘
import state from ‘./state‘
import getters from ‘./getters‘
import mutations from ‘./mutations‘
import actions from ‘./actions‘
Vue.use(Vuex)
export default new Vuex.Store({
state,
getters,
mutations,
actions
})
首先实现第一个,count1
在state.js中
export default {
count1: 0
}
在 mutations.js 中
export default {
countInc(state, v) {
state.count1 = state.count1 + v
}
}
在 App.vue 中
<template>
<div id="app">
<h1>count1: {{count1}}</h1>
<button @click="countIncrease">点我+100</button>
</div>
</template>
<script>
export default {
name: ‘App‘,
computed: {
count1() {
return this.$store.state.count1;
}
},
methods: {
countIncrease() {
this.$store.commit("countInc", 100);
}
}
}
</script>
<style>
</style>
使用 mapState, mapMutations 辅助函数简化代码
export default {
name: ‘App‘,
computed: {
/* count1() {
return this.$store.state.count1;
} */
// 将 this.count1 为 this.$store.state.count1
...mapState([‘count1‘])
},
methods: {
/* countIncrease() {
this.$store.commit("countInc", 100);
}, */
// 将 `this.countInc(100)` 映射为 `this.$store.commit(‘countInc‘, 100)`
...mapMutations([‘countInc‘]),
countIncrease() {
this.countInc(100);
},
}
}
实现 count2 和 count3
在state.js中增加
export default {
count1: 0,
count2: 0,
count3: 0
}
在 mutations.js 中增加
export default {
countInc(state, v) {
state.count1 = state.count1 + v
},
increment(state) {
state.count2++
},
incrementAsync(state) {
state.count3++
}
}
在 actions 中
export default {
/* increment(context) {
context.commit(‘increment‘)
} */
increment({
commit
}) {
commit(‘increment‘)
},
incrementAsync({
commit
}) {
setTimeout(() => {
commit(‘incrementAsync‘)
}, 1000)
}
}
在 App.vue 中增加
<template>
<div id="app">
<h1>count1: {{count1}}</h1>
<button @click="countIncrease">点我+100</button>
<h1>count2: {{count2}}</h1>
<button @click="incrementFn">点我+1</button>
<h1>count3: {{count3}}</h1>
<button @click="incrementAsyncFn">点我延时1秒+1</button>
<h3>花名册</h3>
<ul class="ul">
<li v-for="item in people">姓名:{{item.name}}---年龄:{{item.age}}</li>
</ul>
<h3>年满十八</h3>
<ul class="ul">
<li v-for="item in adults">姓名:{{item.name}}---年龄:{{item.age}}</li>
</ul>
</div>
</template>
<script>
import {
mapState,
mapMutations,
mapActions
} from ‘vuex‘
export default {
name: ‘App‘,
components: {},
computed: {
// 将 this.count 为 this.$store.state.count
...mapState([
‘count1‘,
‘count2‘,
‘count3‘
])
},
methods: {
// 将 `this.countInc(100)` 映射为 `this.$store.commit(‘countInc‘, 100)`
...mapMutations([‘countInc‘]),
countIncrease() {
this.countInc(100);
},
// 将 `this.increment()` 映射为 `this.$store.dispatch(‘increment‘)`
...mapActions([‘increment‘, ‘incrementAsync‘]),
incrementFn() {
this.increment()
},
incrementAsyncFn() {
this.incrementAsync()
}
}
}
</script>
<style>
</style>
getter用法示例
在state.js中增加
export default {
count1: 0,
count2: 0,
count3: 0,
people: [{
name: ‘小易‘,
age: 20
},
{
name: ‘小烊‘,
age: 18
},
{
name: ‘小千‘,
age: 36
},
{
name: ‘小玺‘,
age: 27
},
{
name: ‘小江‘,
age: 24
},
{
name: ‘小六‘,
age: 8
},
{
name: ‘小七‘,
age: 6
}
]
}
在 getters.js 中
export default {
adults: (state) => {
return state.people.filter(item => {
if (item.age >= 18) {
return true
}
})
}
}
在 App.vue 中增加
<template>
<div id="app">
<h1>count1: {{count1}}</h1>
<button @click="countIncrease">点我+100</button>
<h1>count2: {{count2}}</h1>
<button @click="incrementFn">点我+1</button>
<h1>count3: {{count3}}</h1>
<button @click="incrementAsyncFn">点我延时1秒+1</button>
<h3>花名册</h3>
<ul class="ul">
<li v-for="item in people">姓名:{{item.name}}---年龄:{{item.age}}</li>
</ul>
<h3>年满十八</h3>
<ul class="ul">
<li v-for="item in adults">姓名:{{item.name}}---年龄:{{item.age}}</li>
</ul>
</div>
</template>
<script>
import {
mapState,
mapGetters,
mapMutations,
mapActions
} from ‘vuex‘;
export default {
name: ‘App‘,
components: {},
computed: {
// 将 this.count 为 this.$store.state.count
...mapState([
‘count1‘,
‘count2‘,
‘count3‘,
‘people‘
]),
// 使用对象展开运算符将 getter 混入 computed 对象中
...mapGetters([‘adults‘])
},
methods: {
// 将 `this.countInc(100)` 映射为 `this.$store.commit(‘countInc‘, 100)`
...mapMutations([‘countInc‘]),
countIncrease() {
this.countInc(100);
},
// 将 `this.increment()` 映射为 `this.$store.dispatch(‘increment‘)`
...mapActions([‘increment‘, ‘incrementAsync‘]),
incrementFn() {
this.increment()
},
incrementAsyncFn() {
this.incrementAsync()
}
}
}
</script>
<style>
</style>
项目来源
vuex基础入门
目标
功能
先看一下实现的效果
首先创建一个vue项目
vue init webpack projectName
安装 vuex vue-router less less-loader
npm install vuex --save
npm?install?vue?vue-router?--save
npm?install?less?less-loader?--save
在 src 下创建一个 store 目录, 新建以下文件:
在 main.js 中引入和使用,同时创建全局的导航守卫
import Vue from "vue"
import App from "./App.vue"
import Vuex from "vuex"
import router from "./router"
import store from "./store"
Vue.config.productionTip = false
Vue.use(Vuex)
// 创建全局的导航守卫
router.beforeEach((to, from, next) => {
if (store.state.userInfo || to.path === "/login") {
next()
} else {
next({
path: "/login"
})
}
})
new Vue({
el: ‘#app‘,
router,
store,
components: { App },
template: ‘<App/>‘
})
在 index.js 中
import Vue from ‘vue‘
import Vuex from ‘vuex‘
import state from ‘./state‘
import getters from ‘./getters‘
import mutations from ‘./mutations‘
import actions from ‘./actions‘
Vue.use(Vuex)
export default new Vuex.Store({
state,
getters,
mutations,
actions
})
router.js
import Vue from "vue"
import VueRouter from "vue-router"
Vue.use(VueRouter)
const router = new VueRouter({
mode: "history",
base: "/",
routes: [
{
path: "/login",
name: "login",
component: () => import("./pages/login.vue")
},
{
path: "/",
name: "index",
component: () => import("./pages/index.vue")
},
{
path: "/userCenter",
name: "userCenter",
component: () => import("./pages/userCenter.vue")
},
{
path: "/course/:id",
name: "course",
component: () => import("./pages/course.vue")
}
]
})
export default router
在 state.js 中
export default {
userInfo: "",
userStatus: "",
vipLevel: ""
}
userStatus 三种取值情况:0 -> 普通;1 -> vip;2-> 高级vip
getters.js
export default {
memberInfo(state) {
switch (state.userStatus) {
case 0:
return "普通会员"
case 1:
return "vip会员"
case 2:
return `高级V${state.vipLevel}会员`
default:
return "普通会员"
}
}
}
mutations.js
export default {
login(state, v) {
state.userInfo = v
},
// 创建用户信息
setMemberInfo(state, v) {
state.userStatus = v.userStatus
state.vipLevel = v.vipLevel
}
}
actions.js
import { resolve } from "any-promise"
export default {
// 第二个参数表示要修改的数据
buyVip({ commit }, e) {
// 这里简单模拟一下异步操作, 模拟与后端的交互
return new Promise((resolve, reject) => {
// mock api 交互
setTimeout(() => {
// 修改本地state
commit("setMemberInfo", {
userStatus: e.userStatus,
vipLevel: e.vipLevel
})
resolve("购买成功")
}, 1000)
})
},
getFreeVip({ commit, state }) {
// mock api 交互
return new Promise((resolve, reject) => {
setTimeout(() => {
if (state.userStatus === 0) {
commit("setMemberInfo", {
userStatus: 1,
vipLevel: 0
})
resolve("分享成功,您已获得一个月的高级vip会员")
} else {
resolve("分享成功")
}
}, 1000)
})
}
}
关键代码
<template>
<div class="login">
<button class="btn" @click="login">登录</button>
</div>
</template>
<script>
export default {
data() {
return {
isHidden: false,
isPassword: true,
logs: [],
form: {
account: "",
password: ""
}
};
},
methods: {
login() {
if (!this.form.account && !this.form.password) {
alert("请填写账号密码");
return false;
}
const that = this;
setTimeout(() => {
this.$store.commit("login", {
account: that.form.account,
password: that.form.password
});
// 假设拿到用户的数据,存到 store 里
this.$store.commit("setMemberInfo", {
userStatus: 0,
vipLevel: 0
});
// 提交完成后,跳转到首页?
that.$router.push("./");
}, 500);
}
}
};
</script>
与 mutations.js 结合看
export default {
login(state, v) {
state.userInfo = v
},
// 创建用户信息
setMemberInfo(state, v) {
state.userStatus = v.userStatus
state.vipLevel = v.vipLevel
}
}
登录成功后,进入首页 index.vue
<template>
<div class="index">
<h1>你好</h1>
<p class="text">
尊敬的
<!-- <span style="color: red;">{{this.$store.getters.memberInfo}}用户</span>,欢迎来到德莱联盟! -->
<span style="color: red;">{{memberInfo}}用户</span>,欢迎来到前端学堂!
</p>
<button class="footer-opt btn" @click="recharge">充值</button>
</div>
</template>
<script>
import card from "../components/card";
import { mapGetters, mapState } from "vuex";
export default {
components: {
card
},
data() {
return {
courseList: []
};
},
computed: {
...mapState(["userStatus", "vipLevel"]),
...mapGetters(["memberInfo"])
},
mounted() {},
methods: {
recharge() {
this.$router.push("./userCenter");
},
goVideoList(e) {
const res = this.checkPermission(e);
if (res) {
this.$router.push({
name: "course",
params: {
id: e.id
}
});
} else {
alert("权限不足,无法观看");
}
},
checkPermission(e) {
if (this.userStatus >= e.userStatus) {
if (this.vipLevel >= e.vipLevel) {
return true;
} else {
return false;
}
} else {
return false;
}
}
}
};
</script>
memberInfo 来自于
export default {
memberInfo(state) {
switch (state.userStatus) {
case 0:
return "普通会员"
case 1:
return "vip会员"
case 2:
return `高级V${state.vipLevel}会员`
default:
return "普通会员"
}
}
}
点击充值,进入用户中心 userCenter.vue
<template>
<button class="item-content__btn" @click="buy(item)">购买</button>
</template>
<script>
import { mapState, mapGetters } from "vuex";
export default {
data() {
return {
vipList: []
};
},
computed: {
...mapState(["userInfo"]),
...mapGetters(["memberInfo"])
},
methods: {
buy(e) {
this.$store.dispatch("buyVip", e).then(res => {
alert(res);
});
}
}
};
</script>
触发 actions.js 中的
import { resolve } from "any-promise"
export default {
// 第二个参数表示要修改的数据
buyVip({ commit }, e) {
// 这里简单模拟一下异步操作, 模拟与后端的交互
return new Promise((resolve, reject) => {
// mock api 交互
setTimeout(() => {
// 修改本地state
commit("setMemberInfo", {
userStatus: e.userStatus,
vipLevel: e.vipLevel
})
resolve("购买成功")
}, 1000)
})
}
}
<template>
<div class="course">
<button class="share-btn" @click="share">分享</button>
</div>
</template>
<script>
import { mapState, mapGetters } from "vuex";
export default {
data() {
return {};
},
methods: {
share() {
// 简单分享
let c = confirm("课程分享,地址: http://www.muke.com");
if (c) {
// 修改state userStatus
this.$store.dispatch("getFreeVip").then(res => {
alert(res);
});
} else {
console.log("取消");
}
}
}
};
</script>
这个页面要关注的是分享的功能,普通的会员用户点击分享按钮,确定后完成分享,即可获得免费的一个月的 VIP 权限,给它绑定一个 click 事件.
触发 actions.js 中的 getFreeVip
import { resolve } from "any-promise"
export default {
getFreeVip({ commit, state }) {
// mock api 交互
return new Promise((resolve, reject) => {
setTimeout(() => {
if (state.userStatus === 0) {
commit("setMemberInfo", {
userStatus: 1,
vipLevel: 0
})
resolve("分享成功,您已获得一个月的高级vip会员")
} else {
resolve("分享成功")
}
}, 1000)
})
}
}
完整的代码可以在我的仓库里查看。vuex-demo
可以参考我写的另一篇文章,Vue.js开发去哪儿网WebApp。
2.4 使用vuex实现数据共享
原文:https://www.cnblogs.com/chrislinlin/p/12577813.html