Vue(十一):Vuex

目录

一、Vuex概述

1.1 组件之间共享数据的方式

1.2 Vuex是什么

1.3 使用Vuex统一管理状态的好处

二、VUex的基本使用

步骤一:可视化创建项目

三、Vuex的核心概念

3.1 核心概念概述

3.2 State--存储公共数据源

3.2.1 计数器案例演示访问State中的数据的两种方式

 3.3 Mutation--变更Store中的数据--commit调用

3.3.1 Mutations的基本用法

3.3.2 Mutations传递参数

3.3.3 触发Mutations函数的第二种方式

3.4 Action--处理异步任务--dispatch调用

3.4.1 Action的基本使用

3.4.2 Action传递参数

3.4.3 Action调用的两种方式

3.5 Getter--加工处理store中的数据,不改变原store数据


一、Vuex概述

1.1 组件之间共享数据的方式

父向子传值:v-bind属性绑定

子向父传值:v-on 事件绑定

兄弟组件之间共享数据:EventBus $on接收数据的那个组件 $emit发送数据的那个组件

1.2 Vuex是什么

Vuex是实现组件全局状态(数据)管理的一种机制,可以方便地实现组件之间数据的共享。

1.3 使用Vuex统一管理状态的好处

(1)能够在vuex中集中管理共享的数据,易于开发和后期维护

(2)能够高效地实现组件的数据共享,提高开发效率

(3)存储在vuex中的数据都是响应式的,能够实时保持数据与页面的同步

一般情况下,只有组件之间共享的数据,才有必要存储到vuex中;对于组件中的私有数据,依旧存储在组件自身的data中即可。

二、VUex的基本使用

1. 安装vuex依赖包

npm install vuex -S

2.导入vuex包(store/index.js)

import Vuex from 'vuex'
Vue.use(Vuex)

3.创建store对象(store/index.js)

const store = new Vuex.Store({
//state中存放的就是全局共享的数据
state: { count: 0 }
})

4.引入并将store对象挂载到vue实例中(main.js)

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

步骤一:可视化创建项目

(1)cmd窗口输入vue ui,可视化创建vue项目

(2)选择项目目录,及包管理器,点击下一步

 

(3)选择手动配置

 

(4)选择配置,打开Babel/Vuex/Lint Format/使用配置文件四项

 

(5)选择eslint为标准模式

 

(6)不保存该预设。至此,项目创建完成。

 vscode打开项目,发现src目录下新增store/index.js文件,且在main.js中挂载

//store/index.js
import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex)

export default new Vuex.Store({
  state: {
  },
  mutations: {
  },
  actions: {
  },
  modules: {
  }
})
//main.js
import Vue from 'vue'
import App from './App.vue'
import store from './store'

Vue.config.productionTip = false

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

三、Vuex的核心概念

3.1 核心概念概述

Vuex的主要核心概念如下:

  • state
  • Mutation
  • Action
  • Getter

3.2 State--存储公共数据源

State提供唯一的公共数据源,所有共享的数据都要统一放到Store的State中进行存储

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

组件访问State中的数据的两种方式:

方式一:this.$store.state.全局数据名称

方式二:

  • 从vuex中按需引入mapState函数
  • import { mapState } from 'vuex'
  • 将全局数据,映射为当前组件的computed计算属性
  •   computed: {
        ...mapState(['count'])
      }

3.2.1 计数器案例演示访问State中的数据的两种方式

(1)Store/index.js下state中声明公共数据变量:count

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

Vue.use(Vuex)

// 创建store数据源,提供唯一的公共数据
export default new Vuex.Store({
  state: {
    count: 0
  },
  mutations: {
  },
  actions: {
  },
  modules: {
  }
})

(2)创建两个子组件:Addition.vue和Subtraction.vue

// Addition.vue
<template>
  <div>
    <h3>count值为:</h3>
    <button>+1</button>
  </div>
</template>

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

    }
  }

}
</script>

<style>

</style>
// Subtraction.vue
<template>
  <div>
    <h3>count值为:</h3>
    <button>-1</button>
  </div>
</template>

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

    }
  }

}
</script>

<style>

</style>

(3)App.vue中引入两个子组件:

<template>
  <div>
    <my-addition></my-addition>
    <p>-----------</p>
    <my-subtraction></my-subtraction>
  </div>
</template>

<script>
import Addition from '@/components/Addition.vue'
import Subtraction from '@/components/Subtraction.vue'
export default {
  components: {
    'my-addition': Addition,
    'my-subtraction': Subtraction
  }

}
</script>

<style>

</style>

页面如下:

 若想获取全局变量count。

方式一:

 方式二:

 3.3 Mutation--变更Store中的数据--commit调用

如上计数器案例,若想实现点击+按钮自增1的操作,我们的初步思路是button定义click事件,在click事件中执行this.$store.state.count++操作,该方法可以实现count值自增,但不可取!!!缺陷在于若count值变更,不好找出是哪个组件操作的结果。

3.3.1 Mutations的基本用法

Mutation用于变更Store中的数据

  • 只能通过Mutation变更Store数据,不可以直接操作Store中的数据
  • 通过这种方式虽然操作起来复杂,但是可以集中监控所有数据的变化。

如上,用Mutation实现点击+按钮count值加1的效果:

(1)store/index.js中的mutations下定义add函数

(2)Addition.vue中调用mutations中的add函数

3.3.2 Mutations传递参数

 Mutations触发时支持传递参数,如下:

 3.3.3 触发Mutations函数的第二种方式

this.$store.commit()是触发mutations的第一种方式,触发的第二种方式是:

// 从vuex中按需引入mapMutations函数
import { mapMutations } from 'vuex'

 通过导入的mapMutation,将需要的mutation函数,映射为当前组件的methods方法:

  methods: {
    ...mapMutations(['substract', 'add'])
  }

 直接调用方法即可:

// Subtraction.vue
<template>
  <div>
    <h3>count值为:{{ count }}</h3>
    <button @click="substract">-1</button>
  </div>
</template>

<script>
// 从vuex中按需引入mapMutations函数
import { mapState, mapMutations } from 'vuex'

export default {
  data () {
    return {

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

<style>

</style>

3.4 Action--处理异步任务--dispatch调用

如上计数器案例,若想实现点击+1后1秒,count值加1。初始想法是在method中定义setTimeOut函数,并在函数内部执行count++的操作。发现页面count值在1秒后增加,但vue调试工具中查看,发现count值未改变。采用Action解决该问题。

3.4.1 Action的基本使用

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

 如上述计数器案例,实现点击+按钮3秒后,count值加1

(1)修改store/index.js中的Action

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

Vue.use(Vuex)

// 创建store数据源,提供唯一的公共数据
export default new Vuex.Store({
  state: {
    count: 0
  },
  mutations: {
    add (state) {
      state.count++
    },
  },
  actions: {
    addAsync (context) {
      setTimeout(() => {
        context.commit('add')
      }, 3000)
    }
  },
  modules: {
  }
})

(2)在Addition.vue中调用action中的addAsync方法

// Addition.vue
<template>
  <div>
    <h3>count值为:{{ $store.state.count }}</h3>
    <button @click=handler1>+1 async</button>
  </div>
</template>

<script>
export default {
  data () {
    return {
    }
  },
  methods: {
    handler1 () {
      this.$store.dispatch('addAsync')
    }
  }

}
</script>

<style>
</style>

注:在actions中,不能直接修改state中的数据,必须通过context.commit()触发某个mutation才可以

3.4.2 Action传递参数

触发actions异步任务时携带参数:

3.4.3 Action调用的两种方式

方式一:this.$store.dispatch()

方式二:

  • 从vuex中导入mapActions函数
import { mapActions } from 'vuex'
  • 通过导入的mapActions函数,将需要的actions函数,映射为当前组件的methods方法
  methods: {
    ...mapActions(['addAsync'])
  }
  • 方法调用:
    <button @click=addAsync()>+1 async</button>

3.5 Getter--加工处理store中的数据,不改变原store数据

  • Getter用于对Store中的数据进行加工处理形成新的数据。类似vue的计算属性
  • Store中的数据发生变化,Getter中的数据也会跟着变化

(1)Getter的定义

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

Vue.use(Vuex)

// 创建store数据源,提供唯一的公共数据
export default new Vuex.Store({
  state: {
    count: 0
  },
  getters: {
    // state为入参
    showNum: state => {
      return '当前最新的数量为【' + state.count + '】'
    }
  }
})

(2)getters的使用

方式一:this.$store.getters.名称

<template>
  <div>
    <h3>{{$store.getters.showNum}}</h3>
    <button @click=handler>+1</button>
  </div>
</template>

方式二:

<template>
  <div>
    <h3>{{ showNum }}</h3>
  </div>
</template>

<script>
import { mapGetters } from 'vuex'
export default {
  computed: {
    ...mapGetters(['showNum'])
  },

}
</script>

四、基于Vuex的案例-Todos

 如上,样例包含如下功能:

  • 输入任务,点击添加事项,事项添加至列表
  • 点击未完成,显示的是所有未完成的事项
  • 点击已完成,显示的是所有已完成的事项
  • 点击某条事项后的删除,可以删除该事项
  • 点击清除已完成,删除所有已完成的事项
  • 左下角显示当前未完成的事项条数

4.1 初始化项目

  • 创建新项目vuex-demo
  • 安装vuex依赖包: npm install vuex axios ant-design-vue -S
  • 实现Todos基本布局(基于已有样式模板替换原main.js和App.vue文件)

main.js代码如下:

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'

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

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

App.vue代码如下:

<template>
  <div id="app">
    <a-input placeholder="请输入任务" class="my_ipt" />
    <a-button type="primary">添加事项</a-button>

    <a-list bordered :dataSource="list" class="dt_list">
      <a-list-item slot="renderItem" slot-scope="item">
        <!-- 复选框 -->
        <a-checkbox>{{ item.info }}</a-checkbox>
        <!-- 删除链接 -->
        <a slot="actions">删除</a>
      </a-list-item>

      <!-- footer区域 -->
      <div class="footer" slot="footer">
        <span>0条剩余</span>
        <a-button-group>
          <a-button type="primary">全部</a-button>
          <a-button>未完成</a-button>
          <a-button>已完成</a-button>
        </a-button-group>
        <a>清除已完成</a>
      </div>
    </a-list>
  </div>
</template>
<script>
export default {
  name: "app",
  data() {
    return {
      list: [
        {
          id: 0,
          info: "Racing car sprays burning fuel into crowd.",
          done: false,
        },
        {
          id: 1,
          info: " Japanese princess to wed commoner.",
          done: false,
        },
        {
          id: 2,
          info: "Australian walks 100km after outback crash.",
          done: false,
        },
        {
          id: 3,
          info: "Man charged over missing wedding girl.",
          done: false,
        },
        {
          id: 4,
          info: "Los Angeles battles huge wildfires.",
          done: false,
        },
      ],
    };
  },
};
</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>

4.2 全部事项展示

(1)在public目录下新建list.json文件,并将App.vue中的list数组剪切后复制到该文件中,如下为修改后的list.json。App.vue中data中的list设置为空数组:list: []

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

(2)store/index.js:引入并安装vuex插件

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

Vue.use(Vuex)

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

(3)main.js中挂载store对象

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

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

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

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

(4)修改store/index.js。

  • state中声明list数组
  • actions中发起异步axios请求,获取list数据。
  • 将要获取的数据赋值给state中的list,因为actions中不能操作list,所以赋值操作需要由mutations完成。

--------store/index.js----------

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

Vue.use(Vuex)

export default new Vuex.Store({
  state: {
    list: []
  },
  mutations: {
    initList (state, list) {
      state.list = list
    }
  },
  actions: {
    getList (context) {
      axios.get('/list.json').then(({ data }) => {
        context.commit('initList', data)
      })
    }
  },
  modules: {
  }
})

(5)App.vue中获取并展示list数组的值。

  • 删除原data中的list数组
  • 定义create函数,并调用actions中的getList函数
  • 将store/index.js中的state中的list展示到页面中
<template>
  <div id="app">
    <a-input placeholder="请输入任务" class="my_ipt" />
    <a-button type="primary">添加事项</a-button>

    <a-list bordered :dataSource="list" class="dt_list">
      <a-list-item slot="renderItem" slot-scope="item">
        <!-- 复选框 -->
        <a-checkbox>{{ item.info }}</a-checkbox>
        <!-- 删除链接 -->
        <a slot="actions">删除</a>
      </a-list-item>

      <!-- footer区域 -->
      <div class="footer" slot="footer">
        <span>0条剩余</span>
        <a-button-group>
          <a-button type="primary">全部</a-button>
          <a-button>未完成</a-button>
          <a-button>已完成</a-button>
        </a-button-group>
        <a>清除已完成</a>
      </div>
    </a-list>
  </div>
</template>
<script>
import { mapState } from 'vuex'
export default {
  name: 'app',
  computed: {
    ...mapState(['list'])
  },
  created () {
    this.$store.dispatch('getList')
  },
  data () {
    return {
    }
  }
}
</script>

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值