需求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