Vue全家桶09(黑马vue)--vuex管理数据,基本使用,mutation,mapMutation,action处理异步,action带参,getter,todo案例

1、使用Vuex管理数据的好处:

  • A.能够在vuex中集中管理共享的数据,便于开发和后期进行维护
  • B.能够高效的实现组件之间的数据共享,提高开发效率
  • C.存储在vuex中的数据是响应式的,当数据发生改变时,页面中的数据也会同步更新

有点类似于安卓的信息中心,有一个store对象用来存储所有共享数据

2、Vuex的基本使用

  • 1、安装vuex依赖包
    npm install vuex --save

  • 2、导入vuex包
    import Vuex from ‘vuex’

  • 3、创建sore对象

const store =new Vuex.Store({
	//state中存放的就是全局共享数据
	state:{
		count:0
	}
})
  • 4、将store对象挂载到vue实例中
new Vue(){
	el:'#app',
	render:h=>h(app),
	router,
	//将创建的共享数据对象,挂载到vue实例中
	//所有的组件,就可以直接从store中获取全局的数据了
	store
}
  • 5、组件访问state中数据的第一种方式
this.$store.state.全局数据名称
  • 6、组件访问state中数据的第二种方式
    从vuex中按需导入mapState函数
import { mapState } from 'vuex'

通过刚才导入的mapState函数,将当前组件需要的全局数据,映射为当前组件的computed计算属性

computed:{
	...mapState(['count]}

案例:
stroe.js

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

Vue.use(Vuex)

export default new Vuex.Store({
  state: {
    count:0
  },
  mutations: {

  },
  actions: {

  }
})

app.vue

<template>
  <div id="app">
   <my-addition></my-addition>

   <hr>

    <my-subtraction></my-subtraction>

  </div>
</template>

<script>
import Addition from './components/Addition'
import Subtraction from './components/Subtraction'

export default {
  data(){
    return {

    }
  },
  components: {
    'my-addition':Addition,
    'my-subtraction':Subtraction
  }
}
</script>

<style>

</style>

Addition.vue

<template>
  <div>
    <h3>当前最新的count值为:{{this.$store.state.count}}</h3>
    <button>+1</button>
  </div>
</template>

<script>
  export default {
    data(){
      return {
      }
    }
  }
</script>

<style scoped>

</style>

Subtraction

<template>
  <div>
    <h3>当前最新的count值为:{{count}}</h3>
    <button>-1</button>
  </div>
</template>

<script>
  //从vuex中按需导入mapState函数
  import { mapState } from 'vuex'
  export default {
    data (){
      return {

      }
    },
    computed:{
      ...mapState(['count'])
    }
  }
</script>

<style scoped>

</style>

3、Mutation变更store中的数据(第一种方式)

  • 只能通过mutation更变store数据,不可以直接操作store中的数据
  • 通过mutation操作store的数据,但可以集中监控所有数据的变化
    案例:
    定义Mutation
export default new Vuex.Store({
  state: {
    count:0
  },
  mutations: {
    add(state){
      //变更状态
      state.count++
    },
  },
  actions: {

  }
})

触发Mutation

methods:{
      btnHander1(){
        //触发mutation的第一种方式
        this.$store.commit('add')
      }
    }

完整案例
store.js

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

Vue.use(Vuex)

export default new Vuex.Store({
  state: {
    count:0
  },
  mutations: {
    add(state){
      //变更状态
      state.count++
    },
  },
  actions: {

  }
})

app.vue

<template>
  <div id="app">
   <my-addition></my-addition>

   <hr>

    <my-subtraction></my-subtraction>

  </div>
</template>

<script>
import Addition from './components/Addition'
import Subtraction from './components/Subtraction'

export default {
  data(){
    return {

    }
  },
  components: {
    'my-addition':Addition,
    'my-subtraction':Subtraction
  }
}
</script>

<style>

</style>

Addition.vue

<template>
  <div>
    <h3>当前最新的count值为:{{this.$store.state.count}}</h3>
    <button @click="btnHander1">+1</button>
  </div>
</template>

<script>
  export default {
    data(){
      return {
      }
    },
    methods:{
      btnHander1(){
        //触发mutation的第一种方式
        this.$store.commit('add')
      }
    }
  }
</script>

<style scoped>

</style>

4、Mutation以传参的形式变更store中的数据

stroe.js

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

Vue.use(Vuex)

export default new Vuex.Store({
  state: {
    count:0
  },
  mutations: {
    addN(state,step){
      //变更状态
      state.count +=step
    },
  },
  actions: {

  }
})

Addition.vue

<template>
  <div>
    <h3>当前最新的count值为:{{this.$store.state.count}}</h3>
    <button @click="btnHander1">+N</button>
  </div>
</template>

<script>
  export default {
    data(){
      return {
      }
    },
    methods:{
      btnHander1(){
        //触发mutation的第一种方式
        this.$store.commit('addN',3)
      }
    }
  }
</script>

<style scoped>

</style>

5、mapMutation第二种触发mutation的方式

  • 1、从vuex中按需导入mapMutation函数

import { maoMutations } from ‘vuex’
通过刚才导入的mapMutation函数,将需要的mutations函数,映射为当前组件的methods方法:

  • 2、将指定的mutations函数,映射为当前组件的methods方法:
methods:{
	...mapMutation(['add','addN'])
}

案例
store.js

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

Vue.use(Vuex)

export default new Vuex.Store({
  state: {
    count:0
  },
  mutations: {
    addN(state,step){
      //变更状态
      state.count +=step
    },
    sub(state){
      state.count--
    },
    subN(state,step){
      state.count-=step
    }
  },
  actions: {
    
  }
})

app.vue

<template>
  <div id="app">
   <my-addition></my-addition>

   <hr>

    <my-subtraction></my-subtraction>

  </div>
</template>

<script>
import Addition from './components/Addition'
import Subtraction from './components/Subtraction'

export default {
  data(){
    return {

    }
  },
  components: {
    'my-addition':Addition,
    'my-subtraction':Subtraction
  }
}
</script>

<style>

</style>

Subtraction.vue

<template>
  <div>
    <h3>当前最新的count值为:{{count}}</h3>
    <button @click="btnhander1">-1</button>
    <button @click="btnhander2">-N</button>
  </div>
</template>

<script>
  //从vuex中按需导入mapState函数
  import { mapState,mapMutations } from 'vuex'
  export default {
    data (){
      return {

      }
    },
    computed:{
      ...mapState(['count'])
    },
    methods:{
      ...mapMutations(['sub','subN']),

      btnhander1(){
        this.sub()
      },
      btnhander2(){
        this.subN(3)
      }
    }
  }
</script>

<style scoped>

</style>

6、Action用于处理异步任务

如果通过异步操作变更数据,必须通过Action,而不能使用Mutation,但是在action中还是要通过触发Mutation的方式间接变更数据

案例:
stroe.js

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

Vue.use(Vuex)

export default new Vuex.Store({
  state: {
    count:0
  },
  mutations: {
    add(state){
      //变更状态
      state.count ++
    },
    addN(state,step){
      //变更状态
      state.count +=step
    },
    sub(state){
      state.count--
    },
    subN(state,step){
      state.count-=step
    }
  },
  actions: {
    addAsync(context){
      setTimeout(()=>{
        context.commit('add')
      },2000)
    }
  }
})

Addition.vue

<template>
  <div>
    <h3>当前最新的count值为:{{this.$store.state.count}}</h3>
    <button @click="btnHander1">+N</button>
  </div>
</template>

<script>
  export default {
    data(){
      return {
      }
    },
    methods:{
      btnHander1(){
        //触发mutation的第一种方式
        this.$store.dispatch('addAsync')
      }
    }
  }
</script>

<style scoped>

</style>

app.vue

<template>
  <div id="app">
   <my-addition></my-addition>

   <hr>

    <my-subtraction></my-subtraction>

  </div>
</template>

<script>
import Addition from './components/Addition'
import Subtraction from './components/Subtraction'

export default {
  data(){
    return {

    }
  },
  components: {
    'my-addition':Addition,
    'my-subtraction':Subtraction
  }
}
</script>

<style>

</style>

7、Action携带参数处理异步任务

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

Vue.use(Vuex)

export default new Vuex.Store({
  state: {
    count:0
  },
  mutations: {
    add(state){
      //变更状态
      state.count ++
    },
    addN(state,step){
      //变更状态
      state.count +=step
    },
    sub(state){
      state.count--
    },
    subN(state,step){
      state.count-=step
    }
  },
  actions: {
    addAsync(context,step){
      setTimeout(()=>{
        context.commit('addN',step)
      },2000)
    }
  }
})

Addition.vue

<template>
  <div>
    <h3>当前最新的count值为:{{this.$store.state.count}}</h3>
    <button @click="btnHander1">+1</button>
    <button @click="btnHander2">+N</button>
  </div>
</template>

<script>
  export default {
    data(){
      return {
      }
    },
    methods:{
      btnHander1(){
        //触发mutation的第一种方式
        this.$store.dispatch('addAsync')
      },
      btnHander2(){
        //触发mutation的
        this.$store.dispatch('addAsync',5)
      }
    }
  }
</script>

<style scoped>

</style>

8、Action触发的第二种方式

1、从vuex中按需导入mapAction函数

import {mapAction} from ‘vuex’

2、通过刚才导入的mapActions函数,将需要的action函数,映射为当前组件的methods函数

methods:{
...mapActions(['addAsync','addNAsync']}

案例
store.js

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

Vue.use(Vuex)

export default new Vuex.Store({
  state: {
    count:0
  },
  mutations: {
    add(state){
      //变更状态
      state.count ++
    },
    addN(state,step){
      //变更状态
      state.count +=step
    },
    sub(state){
      state.count--
    },
    subN(state,step){
      state.count-=step
    }
  },
  actions: {
    addAsync(context,step){
      setTimeout(()=>{
        context.commit('addN',step)
      },2000)
    },
    subAsync(context){
      setTimeout(()=>{
        context.commit('sub')
      },2000)
    },
    subNAsync(context,step){
      setTimeout(()=>{
        context.commit('subN',step)
      },2000)
    },
  }
})

Subtraction.vue

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

Vue.use(Vuex)

export default new Vuex.Store({
  state: {
    count:0
  },
  mutations: {
    add(state){
      //变更状态
      state.count ++
    },
    addN(state,step){
      //变更状态
      state.count +=step
    },
    sub(state){
      state.count--
    },
    subN(state,step){
      state.count-=step
    }
  },
  actions: {
    addAsync(context,step){
      setTimeout(()=>{
        context.commit('addN',step)
      },2000)
    },
    subAsync(context){
      setTimeout(()=>{
        context.commit('sub')
      },2000)
    },
    subNAsync(context,step){
      setTimeout(()=>{
        context.commit('subN',step)
      },2000)
    },
  }
})

9、Getter对数据进行处理

Getter用于对store中的数据进行加工处理形成的新的数据(包装),类似于java的getter和setter

  • 1、getter可以对store中已有的的数据加工处理会后形成新的数据,类似vue的计算属性
  • 2、store中数据发生变化,getter的数据也会跟着变化

范例:

const store =new Vuex.Store({
	state:{
		count:0
	},
	getter:{
	showNum:state=>{
		return '当前最新的数据是【'+state.count+'】'
	}
}
})

10、使用Getter的第一种方式:

this.$store.getters.名称

范例:
store.js

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

Vue.use(Vuex)

export default new Vuex.Store({
  state: {
    count:0
  },
  mutations: {
    add(state){
      //变更状态
      state.count ++
    },
    addN(state,step){
      //变更状态
      state.count +=step
    },
    sub(state){
      state.count--
    },
    subN(state,step){
      state.count-=step
    }
  },
  actions: {
    addAsync(context,step){
      setTimeout(()=>{
        context.commit('addN',step)
      },2000)
    },
    subAsync(context){
      setTimeout(()=>{
        context.commit('sub')
      },2000)
    },
    subNAsync(context,step){
      setTimeout(()=>{
        context.commit('subN',step)
      },2000)
    },
  },
  getters:{
    showNum(state){
      return '当前最最最最新的数量是【'+state.count+'】'
    }
  }
})

Substration.vue

<template>
  <div>
    <h3>{{$store.getters.showNum}}</h3>
    <button @click="btnhander1">-1</button>
    <button @click="btnhander2">-N</button>
    <button @click="btnhander3">-N async</button>
    <button @click="btnhander4">-1 async</button>
  </div>
</template>

<script>
  //从vuex中按需导入mapState函数
  import { mapState,mapMutations,mapActions } from 'vuex'
  export default {
    data (){
      return {

      }
    },
    computed:{
      ...mapState(['count'])
    },
    methods:{
      ...mapMutations(['sub','subN']),
      ...mapActions(['subAsync','subNAsync']),
      btnhander1(){
        this.sub()
      },
      btnhander2(){
        this.subN(3)
      },
      btnhander3(){
        this.subNAsync(3)
      },
      btnhander4(){
        this.subAsync()
      }
    }
  }
</script>

<style scoped>

</style>

11、使用Getter的第二种方式:

store.js

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

Vue.use(Vuex)

export default new Vuex.Store({
  state: {
    count:0
  },
  mutations: {
    add(state){
      //变更状态
      state.count ++
    },
    addN(state,step){
      //变更状态
      state.count +=step
    },
    sub(state){
      state.count--
    },
    subN(state,step){
      state.count-=step
    }
  },
  actions: {
    addAsync(context,step){
      setTimeout(()=>{
        context.commit('addN',step)
      },2000)
    },
    subAsync(context){
      setTimeout(()=>{
        context.commit('sub')
      },2000)
    },
    subNAsync(context,step){
      setTimeout(()=>{
        context.commit('subN',step)
      },2000)
    },
  },
  getters:{
    showNum(state){
      return '当前最最最最新的数量是【'+state.count+'】'
    }
  }
})

Substraction.vue

<template>
  <div>
    <h3>{{showNum}}</h3>
    <button @click="btnhander1">-1</button>
    <button @click="btnhander2">-N</button>
    <button @click="btnhander3">-N async</button>
    <button @click="btnhander4">-1 async</button>
  </div>
</template>

<script>
  //从vuex中按需导入mapState函数
  import { mapState,mapMutations,mapActions,mapGetters } from 'vuex'
  export default {
    data (){
      return {

      }
    },
    computed:{
      ...mapState(['count']),
      ...mapGetters(['showNum']),
    },
    methods:{
      ...mapMutations(['sub','subN']),
      ...mapActions(['subAsync','subNAsync']),

      btnhander1(){
        this.sub()
      },
      btnhander2(){
        this.subN(3)
      },
      btnhander3(){
        this.subNAsync(3)
      },
      btnhander4(){
        this.subAsync()
      }
    }
  }
</script>

<style scoped>

</style>

12、实现ToDo小软件的案例

文件结构
Vue全家桶09(黑马vue)--vuex管理数据,基本使用,mutation,mapMutation,action处理异步,action带参,getter,todo案例_第1张图片
数据文件

list.json

[
  {
    "id": 0,
    "info": "Racing car sprays burning fuel into crowd.",
    "done": true
  },
  { "id": 1,
    "info": "Japanese princess to wed commoner.",
    "done": false },
  {
    "id": 2,
    "info": "Australian walks 100km after outback crash.",
    "done": true
  },
  { "id": 3,
    "info": "Man charged over missing wedding girl.",
    "done": false },
  { "id": 4,
    "info": "Los Angeles battles huge wildfires.",
    "done": false }
]

main.js
需要安装ant-design-vue组件做外观

import Vue from 'vue'
import App from './App.vue'

// 1. 导入 ant-design-vue 组件库
import Antd from 'ant-design-vue'
// 2. 导入组件库的样式表
import 'ant-design-vue/dist/antd.css'
// 3、导入store
import store from './store'

Vue.config.productionTip = false
// 3. 安装组件库
Vue.use(Antd)

new Vue({
  store,
  render: h => h(App)
}).$mount('#app')

store.js

import Vue from 'vue'
import Vuex from 'vuex'
import axios from 'axios'


Vue.use(Vuex)

export default new Vuex.Store({
  state: {
    //所有的任务列表
    list:[],
    //文本框内容
    inputValue:'aaa',
    nextId:5,
    viewKey:'all'
  },
  mutations: {
    //获取列表数据
    initList (state, list) {
      state.list = list
    },
    //设置输入文本
    setInputValue (state, value) {
      state.inputValue = value
    },
    //添加文本
    addItem (state) {
      const obj = {
        id: state.nextId,
        info: state.inputValue.trim(),
        done: false
      }

      state.list.push(obj)
      state.nextId++
      state.inputValue = ''
    },
    //删除列表item
    removeItem(state,id){
      //根据id查找对应项索引
      let index=state.list.findIndex(x=> x.id==id)

      //根据索引删除数组元素
      if (index!=-1){
        state.list.splice(index,1)
      }
    },
    //修改列表项参数
    changeStatus(state,param){
      const index=state.list.findIndex(x=>x.id==param.id)
      if (index !=-1){
        state.list[index].done=param.status
      }

    },
    //清除完成的任务
    clearDone(state){
      state.list=state.list.filter(x=>x.done===false)

    },
    //改变任务显示
    changeViewKey(state,key){
      state.viewKey=key
    }
  },
  actions: {
      getList(context) {
        axios.get('/list.json').then(({ data }) => {
          // console.log(data)
          context.commit('initList', data)
        })
      }
  },
  getters:{
    //统计未完成任务的条数
    unDoneLength(state){
      return state.list.filter(x=>x.done===false).length
    },
    //包装list,获取各种状态下的list
    infoList(state){
      if (state.viewKey==='all'){
        return state.list
      }
      if (state.viewKey =='undone'){
        return state.list.filter(x=>!x.done)
      }
      if (state.viewKey =='done'){
        return state.list.filter(x=>x.done)
      }

      return state.list
    }

  }
})

app.vue

<template>
  <div id="app">
    <a-input placeholder="请输入任务" class="my_ipt" :value="inputValue"
             @change="handleInputChange" />
    <a-button type="primary" @click="addItemToList">添加事项</a-button>

    <a-list bordered :dataSource="infoList" class="dt_list">
      <a-list-item slot="renderItem" slot-scope="item">
        <!-- 复选框 -->
        <a-checkbox :checked="item.done" @change="(e)=>{cbStatusChange(e,item.id)}">{{item.info}}</a-checkbox>
        <!-- 删除链接 -->
        <a slot="actions" @click="removeItemById(item.id)">删除</a>
      </a-list-item>

      <!-- footer区域 -->
      <div slot="footer" class="footer">
        <!-- 未完成的任务个数 -->
        <span>{{unDoneLength}}条剩余</span>
        <!-- 操作按钮 -->
        <a-button-group>
          <a-button :type="viewKey === 'all' ? 'primary' : 'default'" @click="changeList('all')">全部</a-button>
          <a-button :type="viewKey === 'undone' ? 'primary' : 'default'" @click="changeList('undone')">未完成</a-button>
          <a-button :type="viewKey === 'done' ? 'primary' :'default'" @click="changeList('done')">已完成</a-button>
        </a-button-group>
        <!-- 把已经完成的任务清空 -->
        <a @click="clean">清除已完成</a>
      </div>
    </a-list>
  </div>
</template>

<script>
  import { mapState,mapGetters } from 'vuex'

  export default {
    name: 'app',
    data() {
      return {

      }
    },
    created () {
      this.$store.dispatch('getList')
    },
    computed:{
      ...mapState(['inputValue','viewKey']),
      ...mapGetters(['unDoneLength','infoList'])
    },
    methods:{
      //监听文本框内容变化
      handleInputChange(e){
        // console.log(e.target.value)
        this.$store.commit('setInputValue',e.target.value)
      },
      //向列表中新增item项
      addItemToList(){
        if (this.inputValue.trim().length<=0){
          return this.$message.error('请输入内容')
        }

        this.$store.commit('addItem')

      },
      //通过id删除item项
      removeItemById(id){
        // console.log(id)
        this.$store.commit('removeItem',id)
      },
      //监听复选框选中状态事件,列表item选中与否
      cbStatusChange(e,id){
        //接受最先的选中状态
        // console.log(e.target.checked,id)
        const param={
          id:id,
          status:e.target.checked
        }

        this.$store.commit('changeStatus',param)
      },

      //清除已经完成的任务
      clean(){
        this.$store.commit('clearDone')
      },

      //查看完成与否
      changeList(key){
        // console.log(key)
        this.$store.commit('changeViewKey',key)
      }
    }
  }
</script>

<style scoped>
  #app {
    padding: 10px;
  }

  .my_ipt {
    width: 500px;
    margin-right: 10px;
  }

  .dt_list {
    width: 500px;
    margin-top: 10px;
  }

  .footer {
    display: flex;
    justify-content: space-between;
    align-items: center;
  }
</style>

效果:
Vue全家桶09(黑马vue)--vuex管理数据,基本使用,mutation,mapMutation,action处理异步,action带参,getter,todo案例_第2张图片

你可能感兴趣的:(Vue)