vue中的状态管理vuex(一)

  • Post author:
  • Post category:vue


最近一直,在搞mpvue,发现vue中为我们提供的vuex这个状态管理是多么的好用,所以就拿出来和大家分享一下,

一 什么是vuex

Vuex 是一个专门为 Vue.js 应用所设计的集中式状态管理架构。它借鉴了 Flux 和Redux 的设计思想,但简化了概念,并且采用了一种为能更好发挥 Vue.js 数据响应机制而专门设计的实现。

小提示,我们在写vuex的时候只要记住下面这个图的过程和原理就可以了。

这里写图片描述

我来简单的介绍一下vuex的工作流程。

假设我们这里有home.vue文件

home.vue

        <div id="app">
            <button @click="add">+</button>
        </div>//页面上有一个按钮

当我们点击button按钮,触发add这个点击事件,它是这样工作的,

1)通过$store.dispatch(“自定义名称”,”你想要传递的参数”)发送到actions

            new Vue({
                el:"#app",
                methods:{
                    add(){
                        this.$store.dispatch("addEvent",1)//第一步
                    }
                }
            })

2)actions接收到传递过来的addEvent后,通过commit(“自定义名称”,”参数”)方法传递到mutations

        addEvent(ctx,num){
                ctx.commit("addEvent",num)//这里的addEvent,
                必须与actions提交
                过来的名
            }

3)mutations接收到actions到的数据,在编写以下的代码,

addEvent(state,num){

            }

要记住是在mutations中修改state中的值。

二) 实例 利用vuex实现的本地存储的留言板

留言板可以说是一个比较经典的入门案例,我们尝试着利用vuex和HTML5中localstroage来实现

目录结构

这里写图片描述

我在components下面创建了一个page,下面的组件都是Home.vue中映射出来。

Home.vue

<template>
    <div>
        <HomeHeader></HomeHeader>
        <HomeAdd></HomeAdd>
        <HomeList></HomeList>
        <tips></tips>
    </div>
</template>

<script>
    import HomeHeader from "./page/Header"
    import HomeAdd from "./page/add"
    import HomeList from "./page/list"
    import tips from "./page/tips"
    export default {
        name:"Home",
        components:{
            HomeHeader,
            HomeAdd,
            HomeList,
            tips
        }
    }
</script>

<style>
</style>

add.vue

<template>
    <div class="container">
        <div class="event-add">
            <input type="text" class="n-input" placeholder="待办事项" v-model="content" />
            <button class="add-btn" @click="add">提交</button>
        </div>
    </div>
</template>

<script>
    export default {
        name:"add",
        data(){
            return {
                content:""
            }
        },
        methods:{
            add:function(){
                var obj={
                    content:this.content,
                    id:0
                }

                this.$store.dispatch("addEvent",obj)
                this.content=""
            }
        }
    }
</script>

<style scoped="scoped">
    .container{
        width: 100%;
        padding: 0 10px;
        max-width: 800px;
        margin: auto;
        box-sizing: border-box;
    }
    .event-add{
        position: relative;
        padding: 30px 90px 30px 0;
        font-size: 16px;
    }
    .event-add .n-input{
        width: 100%;
        height: 40px;
        padding: 7px 10px;
        line-height: 26px;
        border: 1px solid #c0ccda;
        box-sizing: border-box;
        border-radius: 4px;
    }
    .event-add .n-input:focus{
        outline: none;
    }
    .event-add .add-btn{
        position: absolute;
        right: 0;
        top: 30px;
        width: 80px;
        height: 40px;
        line-height: 26px;
        color: #fff;
        outline: none;
        border: 1px solid #00d1b2;
        background: #00d1b2;
    }
</style>

Header.vue

<template>
    <header class="home_header">
        <h1>记事本
            <a class="t-btn">
                <span></span>

            </a>
        </h1>
    </header>
</template>

<script>
    export default {
        name:"HomeHeader"
    }
</script>

<style scoped="scoped">
    header{
        position: relative;
        width: 100%;
        height: 70px;
        z-index: 100;
        background: #00d1b2;

    }
    header h1{
        position: relative;
        width: 100%;
        max-width: 800px;
        margin: 0 auto;
        line-height: 70px;
        text-align: center;
        color: #fff;
        font-size:2rem;
        font-weight: bold;
    }
    header h1 a.t-btn{
        position: absolute;
        right: 10px;
        top: 22px;
        width: 30px;
        height: 26px;
        cursor: pointer;
    }
    header h1 span:before{
        top: 11px;
    }
    header h1 span:after{
        top: 22px;
    }
    header h1 span,header h1 span:before,header h1 span:after{
          position: absolute;
          left:0;
          width:30px;
          height:4px;
          content: '';
          background: #fff;
    }
</style>

list.vue

<template>
    <div class="event-content">
        <div class="event-tab">
            未完成{{noDone}}
            <span class="col-span"></span>
        </div>
        <div class="event-box">
            <div class="event-list" v-for="(item,index) in list" :key="index">
                <input type="checkbox" @click="itemDone(item)" :key="item.id" />
                <div>{{item.content}}</div>
                <button class="cancel-btn" @click="canel(index)">删除</button>
            </div>

        </div>

        <div class="event-tab">
            完成{{done}}
            <span class="col-span"></span>
        </div>
        <div class="event-box">
            <div class="event-list" v-for="(item,index) in doneList" :key="index">
                <div>{{item.content}}</div>
            </div>

        </div>


    </div>
</template>

<script>
    export default {
        name:"List",
        computed:{
            list(){
                return this.$store.getters.list
            },
            noDone(){
                return this.$store.getters.noDone
            },
            done(){
                return this.$store.getters.done
            },
            doneList(){
                return this.$store.getters.doneList
            }
        },
        methods:{
            canel:function(i){
                this.$store.dispatch("canelEvent",i)
            },
            itemDone:function(obj){
//              console.log(index)
                this.$store.dispatch("itemDone",obj)
//              this.$store.dispatch("getShow",)
//              this.selected = false
            }
        },
        data(){
            return {
//              selected:false
            }
        }
    }
</script>

<style scoped="scoped">
    ul li{
        list-style: none;
        padding: 0;
        margin: 0;
    }
    .event-content{
        width: 100%;
        padding: 0 10px;
        max-width: 800px;
        margin: auto;
        box-sizing: border-box;
    }
    .event-content .event-tab{
        position: relative;
        height: 44px;
        line-height: 44px;
        padding-left:20px;
        border-bottom:1px solid #fff;
        box-sizing: border-box;
        color: #fff;
        cursor:pointer;
        background: #00d1b2;
    }
    .event-content .event-tab span{
        position: absolute;
        right: 20px;
        top: 15px;
        width: 10px;
        height: 10px;
        content: "";
        border-top: 2px solid #fff;
        border-right: 2px solid #fff;
        transform: rotate(45deg);
        transition: transform .3s;
    }
    .event-content .event-box{
        list-style: none;
        overflow: hidden;
        border-left:1px solid #eee;
        border-right:1px solid #eee;
        transition: height .3s;
        display: block;
        height: auto;
    }
    .event-content .event-box .event-list{
            position: relative;
            min-height: 44px;
            line-height: 25px;
           padding: 10px 100px 10px 50px;
            box-sizing: border-box;
            border-bottom: 1px solid #eee;
            color: #373e40;
    }

    .event-content .event-box .event-list input[type=checkbox]{
            position: absolute;
        left: 15px;
        top: 12px;
        width: 20px;
        height: 20px;
    }
    .event-content .event-box .event-list .cancel-btn{
            position: absolute;
        right: 10px;
        top: 7px;
        width: 50px;
        height: 30px;
        line-height: 30px;
        padding: 0;
        background: #fff;
        border: 1px solid #c0ccda;
        color: #666;
        font-size: 12px;
        text-align: center;
        border-radius: 4px;
        box-sizing: border-box;
        cursor: pointer;
    }
</style>

tips.vue

<template>
    <div class="tips" id="tips" v-show="isShow">
        <div class="tips-mask" :class="{move:domove}">
            {{msg}}
            <button class="btn btn-danger" @click="queDel">确定</button>
            <button class="btn btn-primary" @click="quxiao">取消</button>
        </div>
    </div>
</template>

<script>
    export default {
        name:"Tips",
        mounted(){
            var _this = this
            this.getSize()
            window.onresize = function(){
                _this.getSize()
            }

        },
        methods:{
            getSize:function(){
                var oTips = document.getElementById("tips")
                var cW = document.documentElement.clientWidth
                if(cW>375){
                    var cH = document.documentElement.clientHeight
                    oTips.style.height = cH+"px"
                }else{
                    var cH = document.body.clientHeight
                    oTips.style.height = cH+"px"
                }
            },
            queDel:function(){
                this.$store.dispatch("cancel")
            },
            quxiao:function(){
                this.$store.dispatch("quxiao")
            }
        },
        data(){
            return {
                msg:"你确定要删除吗?!",
                domove:false
            }
        },
        computed:{
            isShow(){
                return this.$store.getters.show
            }
        }

    }
</script>

<style scoped="scoped">
    .tips{
        width: 100%;
        position: absolute;
        left: 0;
        top: 0;
        bottom: 0;
        z-index:100;

    }
    .tips .tips-mask{
        width: 200px;
        margin: 0 auto;
        background:;
        /*height: 120px;*/
        position: relative;
        background:rgba(0,0,0,0.5);
        border-radius:4px;
        transform: translate(0px,20px);
        transition: transform 0.5s;
        padding: 10px 15px;
        color: #fff;
        text-align: center;
        line-height: 40px;
        z-index:99999 }
    .tips .tips-mask.move{
        transform: translate(0px,120px);
    }
</style>

store/index.js

import Vue from 'vue'
import Vuex from "vuex"

Vue.use(Vuex)
const state = {
    listArr:localStorage["listArr"]?JSON.parse(localStorage["listArr"]):[],
    doneArr:localStorage["doneArr"]?JSON.parse(localStorage["doneArr"]):[],
    count:0,
    show:false,
    index:0
}
const mutations = {
    addEvent(state,obj){
        state.count++
        obj.id = state.count
        state.listArr.push(obj)
        localStorage.setItem("listArr",JSON.stringify(state.listArr))
    },
    canelEvent(state,i){
        state.index = i
        state.show = !state.show 
    },
    itemDone(state,obj){
        for (var j=0;j<state.listArr.length;j++) {
            if(state.listArr[j].id===obj.id){
                var item = state.listArr[j]
                state.listArr.splice(j,1)
                break;
            }
        }
        state.doneArr.push(item)
        localStorage.setItem("doneArr",JSON.stringify(state.doneArr))
        localStorage.setItem("listArr",JSON.stringify(state.listArr))
    },
    isShow(state,isShow){
        state.show = isShow
    },
    cancel(state){
        state.listArr.splice(state.index,1)
        state.show = !state.show
        localStorage.setItem("listArr",JSON.stringify(state.listArr))
    },
    quxiao(){
        state.show = false
    }
}
const actions = {
    addEvent(ctx,obj){
        ctx.commit("addEvent",obj)
    },
    canelEvent(ctx,i){
        ctx.commit("canelEvent",i)
    },
    itemDone(ctx,obj){
        ctx.commit("itemDone",obj)
    },
    getShow(ctx,isShow){
        ctx.commit("isShow",isShow)
    },
    cancel(ctx){
        ctx.commit("cancel")
    },
    quxiao(ctx){
        ctx.commit("quxiao")
    }
}
const getters = {
    list(){
        return state.listArr
    },
    noDone(){
        return state.listArr.length
    },
    done(){
        return state.doneArr.length
    },
    doneList(){
        return state.doneArr
    },
    show(){
        return state.show
    }
}



export default new Vuex.Store({
    state,
    mutations,
    actions,
    getters
})

这里的vuex我并没有做目录分解,也是为了方便大家观看

完成效果图

这里写图片描述

这里写图片描述

这里写图片描述

我下次会给大家带来,我会介绍一下这个案例,如何做前后端分离的效果,以及如何在vue-cli中访问php的后端接口。



版权声明:本文为Only_ruiwen原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。