zoukankan      html  css  js  c++  java
  • 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

     

     

  • 相关阅读:
    小小不爽一下
    银行家算法的讨论
    【转】C字符串处理函数的实现
    Oracle物理存储结构文件
    RAC和ASM环境下修改控制文件control file
    TNS01190: The user is not authorized to execute the requested listener comm (oracle”用户没有启动lisener的权限?)
    RAC环境ASM存储新增控制文件的方法
    Oracle RAC 修改 spfile 文件位置
    Rman通过duplicate创建standby
    rman恢复手册
  • 原文地址:https://www.cnblogs.com/rmty/p/12125230.html
Copyright © 2011-2022 走看看