最近一直,在搞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的后端接口。