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

 

 

 

 

 

 

 

 

 

 

 

posted @ 2020-01-08 16:49  日暮途远i  阅读(339)  评论(0编辑  收藏  举报