父向子传值: v-bind 属性绑定
子向父传值: v-on 事件绑定
兄弟组件之间共享数据 EventBus
$on 接收数据的那个组件
$emit 发送数据的那个组件
Vuex是实现组件全局状态(数据)管理的一种机制,可以方便的实现组件之间数据的共享
为什么要使用vuex?
我们先来看看如果没有vuex,不同组件之间想要进行数据传递的过程:
当组件A想要和组件B进行数据共享的时候,需要经过多条路径去和B进行数据同步
如果有vuex,不同组件之间想要进行数据传递的过程:
有了vuex当“中间商”后,我们就能让组件和组件之间的数据传递变得简单起来
1、 能够在vuex中集中管理共享的数据,易于开发和后期的维护
2、 能够高效的在组件间实现数据共享,提高开发效率
3、 存储在vuex中的数据都是响应式的,能够实时保持数据与页面的同步
什么情况下的数据适合储存到vuex中呢?
一般情况下,只有组件之间需要共享的数据才有必要存到vuex中,对于组件中的某些私有数据依旧存储在组件自身的data中就行了。
终端输入命令:npm install vuex --save
import Vuex from ‘vuex’
Vue.use(Vuex)
const store = new Vuex.Store({
// state 中存放的就是全局共享的数据
state: {count:0}
})
new Vue({
el:’#app’,
render: h => h(app),
router,
// 将创建的共享数据对象,挂载到vue实例中
// 所有的组件就可以直接从store中获取全局数据了
store
})
在cmd中输入vue create projectname
会出现如下选项
我这里选择的是 [vue2]
其实可以选择第三个选项手动添加
需要选择如下依赖:babel、vuex、linter、use config files
这四项,其他的根据项目需求自行添加
(博主演示如何将vuex通过自己写配置文件的方式将vuex添加进去)
然后就会进入安装页面,静待安装,出现如下界面时表示安装完成:
我们现在打开这个项目来看看它的目录结构:
这里它告诉我们需要安装依赖然后启动项目,但是我们不急,先来分析一下目录结构
我们按照前面的步骤来一步一步把vuex加入我们新建的项目中。
安装完成后输入 npm install vuex --save
(这里如果出现安装失败–报错timeout可以参考我的另一篇博客)
这里的store.js的创建目录是与main.js平级的,然后state里面是通过key-value的方法来储存全局可访问的变量的。
将store挂载到注册的vue实例对象中 就能在后面的开发过程中使用到vuex了
State提供唯一的公共数据源,所有共享的数据都要统一放到Store的State中进行储存。
示例:
const store = new.Vuex.Store({
state:{ count : 0 }
})
这里的count就是全局共享的数据
组件访问state的第一种方式:this.$store.state.全局数据名称
组件访问state中数据的第二种方式:
//从vuex中按需导入 mapState 函数
import { mapState } from 'Vuex'
通过刚才导入的mapState函数,将当前组件所需要的全局数据,映射为当前组件的computed计算属性:
// 将全局数据,映射为当前组件的计算属性
computed:{
...mapState(['count'])
}
用于变更Store中的数据
1、 在vuex中,它推荐我们使用Mutation进行数据修改,而不建议我们直接使用methods来修改State里的数据。(其实就是不可以使用methods方法来改啦)
2、 通过这种方式操作起来虽然繁琐一点,但是可以集中监控所有的数据变化,(方便后期项目的上线和维护);
// 定义mutation
const store = new Vuex.Store({
state : {
count : 0
},
mutations : {
add(state) {
// 变更状态
state.count++
}
}
})
// 触发mutation
methods : {
handle1(){
// 触发mutation 的第一种方式
this.$store.commit(‘add’)
}
}
如何在调用Mutation的时候去传递参数
可以触发mutations时传递参数:
// 定义 mutation
const store = new Vuex.Store({
state:{
count:0
},
mutations:{
addN(state, step) {
// 变更状态
state.count += step
}
},
})
// 触发mutation
methods : {
handle2() {
// 在调用commit函数,触发mutations时携带参数
this.$store.commit(‘addN’, 3)
}
}
触发mutation的第二种方式
// 从vuex中按需导入 mapMutations 函数
import { mapMutations } from ‘vuex’
通过刚刚导入的mapMutations函数,将需要的mutations函数映射为当前组件的methods方法。
methods : {
…mapMutations([‘add’,’addN’])
}
Action用于处理异步任务
如果通过异步操作变更数据,必须通过Action,而不能使用Mutation,但是在Action中还是要通过触发Mutation的方式间接变更数据。
// 定义Action
conset store = New Vuex.Store({
// 省略其他代码
mutations:{
add(state) {
state.count++
}
},
actions:{
addAsync(context) { // 这里的context 我们就可以认为是实例出来的vue对象
// 在actions中不能直接修改state里的数据
// 如果需要修改state里的数据,必须通过context.commit()触发某个mutation才行
setTimeout(()=>{
context.commit(‘add’)
}, 1000)
}
}
})
//触发Action
methods : {
handle() {
// 触发 actions的第一种方式
this.$store.dispatch(‘addAsync’)
}
}
- 在实例中的使用方法和mutations类似
方法 2
<script>
import {mapActions} from 'vuex'
// 省略一部分
methods:{
...mapActions(['addAsync']),
function_name(){
this.addAsync()
}
}
</script>
触发actions异步任务时携带参数
// 定义Action
conset store = New Vuex.Store({
// 省略其他代码
mutations:{
addN(state, step) {
state.count += step
}
},
actions:{
addAsync(context, step) { // 这里的context 我们就可以认为是实例出来的vue对象
// 在actions中不能直接修改state里的数据
// 如果需要修改state里的数据,必须通过context.commit()触发某个mutation才行
setTimeout(()=>{
context.commit('addN', step)
}, 1000)
}
}
})
//触发Action
methods : {
handle() {
// 触发 actions的第一种方式
this.$store.dispatch('addAsync', 5)
}
}
Getter 用于对store中的数据进行加工处理形成新的数据。
如何使用Getter
// 定义Getter
const store = new Vuex.Store({
state:{
count : 0
},
getters : {
showNum: state => {
return '当前count最新值为:' + state.count
}
}
})
// 使用getter的第一种方式
this.$store.getters.名称
// getter 的第二种使用方式
import { mapGetters } from 'Vuex'
computed:{
...mapGetters(['showNum']) // 就可以在代码中直接使用了
}
由于使用单一状态树,应用的所有状态会集中到一个比较大的对象。当应用变得非常复杂时,store 对象就有可能变得相当臃肿。
为了解决以上问题,Vuex 允许我们将 store 分割成模块(module)。每个模块拥有自己的 state、mutation、action、getter、甚至是嵌套子模块——从上至下进行同样方式的分割
具体的使用这里比较容易理解,可以参考官方文档.进行学习。
这个案例是用来熟悉Vuex的各项核心概念的
第一版:使用State 、 Mutations 、 Action 和 Getter
直接上代码图 + 贴代码
整体demo示意图:
demo代码汇总:
add.vue:state 和 mutation 的第一种使用方法
<template>
<div>
<p>当前最新的count值为:{{this.$store.state.count}}p>
<p>{{this.$store.getters.showNum}}p>
<button @click="add">+1button>
<button @click="addN">+3button>
<button @click="addAsync1">+1Asyncbutton>
<button @click="addAsync2">+3Asyncbutton>
div>
template>
<script>
export default {
data(){
return {}
},
methods:{
add(){
// 触发mutation 的第一种方式
this.$store.commit('add')
},
addN(){
this.$store.commit('addN', 3)
},
addAsync1(){
this.$store.dispatch('addAsync')
},
addAsync2(){
this.$store.dispatch('addNAsync', 3)
}
}
}
script>
<style scoped>
style>
subt.vue :state 和 mutation 的第二种使用方法
<template>
<div>
<p>当前最新的count值为:{{ count }}p>
<p> {{ showNum }} p>
<button @click="sub">-1button>
<button @click="subN">-3button>
<button @click="subAsync1">-1Asyncbutton>
<button @click="subAsync2">-3Asyncbutton>
div>
template>
<script>
import { mapState,mapMutations,mapActions, mapGetters } from 'vuex'
export default {
name: "subt",
data(){
return {}
},
methods:{
...mapMutations(['minus', 'minusN']),
sub(){
this.minus()
},
subN(){
this.minusN(3)
},
...mapActions(['subAsync', 'subNAsync']),
//映射过来其实就是可以直接调用的函数可以直接作为调用函数
subAsync1() {
this.subAsync()
},
subAsync2() {
this.subNAsync(3)
}
},
computed:{
...mapState(['count']),// 这三个点代表是展开计算符
...mapGetters(['showNum'])
}
}
script>
<style scoped>
style>
store.js (这里是vuex的配置文件)
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
export default new Vuex.Store({
state:{
count:0
},
mutations:{
add(state) {
// 不要再mutations 函数中执行异步操作 比如:
// setTimeout(() => {
// state.count++
// },1000)
// 变更状态
state.count++
},
addN(state, step) {
state.count += step
},
minus(state) {
state.count--
},
minusN(state, step) {
state.count -= step
}
},
actions:{
addAsync(context) {
setTimeout(()=>{
context.commit('add')
}, 1000)
},
addNAsync(context,step){
setTimeout(()=>{
context.commit('addN', step)
}, 1000)
},
subAsync(context) {
setTimeout(()=>{
context.commit('minus')
}, 1000)
},
subNAsync(context,step){
setTimeout(()=>{
context.commit('minusN', step)
}, 1000)
}
},
getters:{
showNum(state) {
return '当前count最新值为:' + state.count
}
}
})
App.vue
<template>
<div id="app">
<my-add>my-add>
<p>----------------------------p>
<my-subt>my-subt>
div>
template>
<script>
import add from './components/add.vue'
import subt from './components/subt.vue'
export default {
name: 'App',
components: {
'my-add':add,
'my-subt': subt
}
}
script>
<style>
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
style>