Vuex简单案例
需求1.根据登录状态来跳转页面,通过state.userinfo控制用户登录限制:
1.在页面的src目录下新建一个store文件夹,专门存储相应的vuex
2.在store文件夹下新建一个index.js文件
// 实例化vuex对象
import Vue from 'vue'
import Vuex from 'vuex'
import state from './state'
import mutations from './mutations'
Vue.use(Vuex)
const store= new Vuex.Store({
state,
mutations
});
export default store
3.在store文件夹下新建一个state.js文件,存放数据状态,并且默认导出userInfo
export default{
userInfo:""
}
4.在store文件夹下新建一个mutations.js文件,存放数据修改方法,先默认导出一个登录函数
export default{
login(state,v){
state.userInfo=v;
}
}
5.在main.js中引入之前创建的store和vuex,并且创建vue-router的全局导航守卫,拦截路由
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)=>{
window.console.log(store.state,"store.state")
if(store.state.userInfo || to.path==="/login"){
next()
}else{
next({
path:"/login"
})
}
});
new Vue({
store,
router,
render: h => h(App),
}).$mount('#app')
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")
}
]
})
export default router
在登录页面的点击按钮上绑定事件,使用store的commit方法执行之前定义好的login方法,并且把表单提交的用户名和密码作为第二个参数传入,有userinfo值之后就可以通过路由跳转回首页
<button class="btn" @click="login">登录</button>
login() {
if (!this.form.account && !this.form.password) {
alert("请填写账号密码");
return false;
}
const that=this
setTimeout(()=>{
store.commit('login',{
account:that.form.account,
password:that.form.password
});
that.$router.push('./')
},500)
}
2.多组件共享state.userStatus和state.vipLevel状态
1.在state.js中新增两个变量存储用户会员状态和会员等级
export default{
userInfo:"",
userStatus:'', /*0表示普通会员1表示vip,2表示高级vip*/
vipLevel:"" /*vip等级*/
}
2.在mutation.js中添加设置用户vip等级的方法
export default{
login(state,v){
state.userInfo=v;
},
setMemberInfo(state,v){
state.userStatus=v.userStatus;
state.vipLevel=v.vipLevel
}
}
3.在login.vue中修改,使用store.commit方法登陆后模拟从后台拿到vip等级
login() {
if (!this.form.account && !this.form.password) {
alert("请填写账号密码");
return false;
}
// 模拟和后端的交互流程
const that=this
setTimeout(()=>{
store.commit('login',{
account:that.form.account,
password:that.form.password
});
// 假设从后台拿到的用户vip等级(默认是一个vip用户,普通vip)
store.commit('setMemberInfo',{
userStatus:1,
vipLevel:0
})
that.$router.push('./')
},500)
}
4.接下来在index.vue文件中修改
<h1>你好</h1>
<p class="text">
尊敬的
<span style="color: red;">{{this.$store.state.userStatus}}用户</span>
</p>
此时只能拿到这样的数据

5.接下来在store文件下新增getters.js文件,导出一个memberInfo方法,用于从现有store数据派生出新的数据
// 从现有的state数据中派生出新的数据
export default {
memberInfo(state) {
switch (state.userStatus) {
case 0:
return '普通会员'
case 1:
return 'vip会员'
case 2:
return `高级Vip${state.vipLevel}会员`
default:
return '普通会员'
}
}
}
6.在index.js中引入getters,并传入vue对象中
// 实例化vuex对象
import Vue from 'vue'
import Vuex from 'vuex'
import state from './state'
import mutations from './mutations'
import getters from './getters'
Vue.use(Vuex);
// 传递刚才创建的state和mutations
const store= new Vuex.Store({
state,
mutations,
getters
});
export default store
7.接下来在index.vue中就可以获取到这个数据了
<h1>你好</h1>
<p class="text">
尊敬的
<span style="color: red;">{{this.$store.getters.memberInfo}}用户</span>
</p>

效果是实现了,但是这样每次通过this.$store实例的渲染方式是不方便的,可读,可维护性也差
vuex提供了一种解构的方法,叫做mapGetters,通过这种 方法可以再配合计算属性加解构的符号,解构出需要的getters,具体使用方法:
从vuex中引入mapGetters
import {mapGetters} from "vuex"
使用计算属性方法,在里面传入一个数组,数组中的每个元素就是getters中的方法名
computed:{
...mapGetters(['memberInfo'])
}
定义好之后直接在页面上使用{{memberInfo}},这样形式的getters的方法名就可以了
<h1>你好</h1>
<p class="text">
尊敬的
<span style="color: red;">{{memberInfo}}用户</span>
</p>
有了这个方法,其他组件共享同一个数据也很方便了,在userCenter中引用mapState和mapGetters
import { mapState, mapGetters} from "vuex";
在计算属性方法中解构
computed:{
...mapState(['userInfo']),
...mapGetters(['memberInfo'])
},
在页面中直接调用
<section class="user-info">
<label for class="user-info-label">账号</label>
<span class="user-info-value">{{userInfo.account}}</span>
</section>
<section class="user-info">
<label for class="user-info-label">身份</label>
<span class="user-info-value">{{memberInfo}}</span>
</section>
查看一下效果:


3.在用户中心修改state.userStatus和state.vipLevel
在userCenter组件中给每个购买按钮添加点击事件,并把当前循环出来的item传递进去

<button class="item-content__btn" @click="buy(item)">购买</button>
前面都是获取store存储的数据,要改变数据进行异步操作则需要使用actions,在store目录下新建一个actions.js文件,定义一个buyvip方法,该方法有两个参数,第一个传入一个commit,第二个是传入的数据
使用promise模拟一下后端请求
// 第一个传入一个对象传入commit,第一个则是传入的数据
export default{
buyVip({ commit },e){
return new Promise((resolve)=>{
//模拟和后端的交互
setTimeout(()=>{
// 修改本地state
commit('setMemberInfo',{
userStatus:e.userStatus,
vipLevel:e.vipLevel
});
resolve('购买成功')
},500)
})
}
}
在index.js中引入actions对象并挂载到vue实例中
// 实例化vuex对象
import Vue from 'vue'
import Vuex from 'vuex'
import state from './state'
import mutations from './mutations'
import getters from './getters'
import actions from './actions'
Vue.use(Vuex);
// 传递刚才创建的state和mutations
const store= new Vuex.Store({
state,
mutations,
getters,
actions
});
export default store
在usercenter组件中引入store
import store from '../store';
在的methods中添加buy函数,使用store的dispath方法向仓库派发buyvip事件,并把点击组件的数据作为参数传递进去
methods: {
buy(e) {
store.dispatch('buyVip',e).then(res=>{
alert(res)
})
}
}
看一下效果,进入用户中心后购买高级vip,由于数据是响应式的,所以购买成功以后身份立刻会改变

4.实现观看各种vip视频的权限控制

首先这里每块卡片都是组件,都是mock模拟从后台拿到的数据渲染出来的
<card :course="item" @goVideoList="goVideoList" v-for="(item, index) in courseList" :key="index"></card>

在card.vue中定义props,把course作为接收父组件传递进来数据的对象
再向外触发的emit事件,把点击后拿到相应的数据再传递回父组件
export default {
props: {
course: {
type: Object,
default: () => {}
}
},
methods: {
goVideoList(){
this.$emit('goVideoList',this.course)
}
}
};
之前mock的数据中就有需要观看的vip等级

在子组件派发给父组件的点击事件中添加一个checkPermission方法,当传递进去的值为true的时候,实现路由跳转

接下来实现checkPermission方法,其实就是拿到用户数据去对比课程所需的vip等级

完整代码
goVideoList(e){
// 把对象传递进去:
const res=this.checkPermission(e);
if(res){
this.$router.push({
name:"course",
params:{
id:e.id
}
})
}else{
alert('您的权限不足,请重置')
}
},
checkPermission(e){
// 对比用户的数据和课程所需要的数据
const userStatus = this.$store.state.userStatus;
const vipLevel=this.$store.state.vipLevel;
// 如果用户数据满足课程信息
if(userStatus>=e.userStatus){
if(vipLevel>=e.vipLevel){
return true
}else{
return false
}
}
}
到这里就实现了组件跳转权限的控制,权限不足的vip12课程要经过充值才能进行跳转

5.实现分享功能
分享即可获得一个月vip的权限
针对的分享课程只有普通的用户分享之后才有一个月的观看权限

给组件的分享按钮添加点击事件
<button class="share-btn" @click="share">分享</button>
点击事件,和之前充值会员一样,实际交互也是异步的,所以需要在actions中定义方法
export default {
data() {
return {};
},
methods: {
share(){
// 简单分享:
let c=confirm('课程分享,地址:http://www.baidu.com');
// 如果点击了确定分享
if(c){
// 修改state的userStatus
store.dispatch('getFreeVip').then(res=>{
alert(res)
})
}else{
// 如果点击取消:
window.console.log('取消了分享')
}
}
}
};
actions,js中新增:
// 获取免费会员:
getFreeVip({commit,state}){
//mock api
return new Promise((resolve)=>{
setTimeout(()=>{
// 只有在usersStatus是0的情况下
if(state.userStatus===0){
// 把普通会员变成高级会员
commit('setMemberInfo',{
userStatus:1,
vipLevel:0
})
resolve('分享成功,获得了一个月的高级vip')
}else{
// 如果不是普通的会员分享:
resolve('分享成功')
}
},500)
})
}
到此完整的功能就做完啦

页面源码已经上传至码云
https://gitee.com/delisteam/vuex_practice

浙公网安备 33010602011771号