组件之间共享数据的方式
- 1.父向子传值 v:bind绑定数据, props接收
- 2.子向父传值 :父组件 v-on事件绑定,子组件用this.$emit()接受
- 3.兄弟之间共享数据 全局的EventBus,挂载 vue的原型上 $emit发送数据的那个组件,$on接收数据的那个组件
- 4.祖先和后代相互传参 :祖先要使用provide方法传参,后代使用inject属性接受祖先中的参数,
- 5.vue实例属性传参(parent、children[n]、root、refs)
- +$parent 获取父元素的数据/方法 获取父元素的整个vm实例
- +$children 获取子元素的数据/方法(mounted钩子函数,要有下标)
- +$root获取根组件的数据/方法
$refs
:this的子元素中需要定义ref
属性:比如ref=
如果ref定义在DOM标签中==:
this.$refs.xxx
获取的是DOM对象如果ref定义在子组件标签中==:
this.$refs.xxx
获取的是子组件的vm实例
Vuex是什么?
Vuex是实现组件全局状态(数据)管理的一种机制,可以方便的实现组件之间的共享
Vuex 使用单一状态树——是的,用一个对象就包含了全部的应用层级状态。至此它便作为一个“唯一数据源“而存在。这也意味着,每个应用将仅仅包含一个 store 实例
使用Vuex统一管理的好处?
- 1.能够在vuex中集中管理共享数据,易于后期开发和维护
- 2.能够高高效的实现组件之间的共享,提高开发效率
- 3.存储在vuex中都是响应式的能够实时保护,数据与页面的同步
什么样的数据适合存储在vuex中?
一般情况下,只有组件之间共享数据才有必要存储到vuex中,对于组件的私有数据,依旧存储在组件自身的data中即可,
vuex的作用?
1、vuex是专为Vue.js应用程序开发的状态管理模式(集中式存储)--->公共仓库
2、缓存 keep-aliv
vuex
:不刷新,不关闭页面,就会保存以前的数据,刷新就不存在数据sessionStorage
:会话存储,刷新有数据、关闭页面没有数据localStorage
:本地存储,刷新有数据、数据永久
vuex:“单向数据流”理念
- state,驱动应用的数据源;
- view,以声明方式将 state 映射到视图;
- actions,响应在 view 上的用户输入导致的状态变化
vuex的异步函数执行的过程:
vuex的基本使用
1.安装vuex依赖包
npm install vuex --save
2.导入vuex包
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
3.创建store对象
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
//state存放全局共享数据
export default new Vuex.Store({
state: {}, //相当于vue中的data存放数据
getters: {}, //相当于vue中的compute计算属性
mutations: {},//相当于vue中的methods方法(==同步==)
actions: {}, //相当于vue中的methods方法(==异步)==
modules: {} //模块
})
4.将store挂载到vue实例中
new Vue({
//将创建的共享数据对象,挂载到vue实例中
//所有的组件,就可以直接从store中获取到全局数据了
store,
render: h => h(App)
}).$mount('#app')
vuex的五个核心属性
state
:相当于vue中的datamutations
:相当于vue中的methods(==同步==)actions
:相当于vue中的methods(==异步)==getters
:相当于vue中的computedModules
:模块
1.state 相当于vue中的data
state:提供唯一的公共数据源,所有的公共数据要统一放到Store的State中进行存储,
仓库中
const store = new Vuex.Store({
//在大仓库中存放一个count为0
state: {
count: 0
}
})
组件访问State中的数据
第一种方式:this. $store.state.具体的数据名称
<h3>当前的count值为: {{ $store.state.count }}</h3>
注意:在template模板中使用this可以省略,直接沿着原型链调用(不推荐没缓存)
//--------------
第二种方式: 辅助函数
1.//从vuex中按需导入mapState函数
import {mapState} from 'vuex';
2.通过刚才导入的mapState函数,将当前组件需要的全局数据,映射为当前组件的computed计算属性
注意:计算属性展示到页面使用插值表达式(小胡子语法)推荐,有缓存
数组形式:
computed: {
...mapState(['count']),
},
对象形式:可以自定义接收 调用的时候用自定义的名
computed: {
...mapState({
n: 'count',
}),
//-------------
第三种方式:放到computed计算属性中使用
注意:这里要加this
computed: {
count() {
return this.$store.state.count
},
},
2.Mutaion 当于vue中的methods(==同步==)
用于变更Store中的数据
- 1.只能通过mutation变更Store数据,不可以直接操作Store中的数据
- 2.mutations中的函数必须是同步的,不能放异步方法
- 3.通过这种方式,操作起来虽然稍微繁琐一些但是可以监控所有数据变化
参数
state
:【默认参数】指向当前vuex实例store的state对象payload
:载荷,用来接收组件传给函数的参数,一般情况下载荷应该是一个对象...params
:第二个及以后的参数,组件调用方法时向方法传递的参数
仓库中
//定义状态
const store = new Vuex.Store({
state: {
count: 0
},
mutations: {
//变更状态 同步
add(state,payload) {
state.count++
state.count += payload//接收组件传递过来的参数,可以是对象
}
})
组件中
//触发mutation的第一种方式
注意:使用store.commit方法可直接调用
methods: {
handlel() {
//commit的作用,就是调用某个mutation函数
this.$store.commit('add', 100)//可以携带参数
},
},
//触发mutation的第二种方式-------------------------
import {mapMutations} mapMutations from 'vuex';
2.通过刚才导入的mapMutations函数,将当前组件需要的全局数据,映射为当前组件的methods方法
数组形式:
methods: {
...mapMutations(['sub']),
},
对象形式:可以自定义事件句柄
...mapMutations({
s: 'sub',
}),
在调用时传递参数
<button @click="s(3)">-1</button>
3.Action 相当于vue中的methods(==异步)==
- Action 用于处理异步任务
- 如果通过异步操作变更数据必须通过Action ,而不能使用Mutaion ,但是Active中还是要通过触发Mutaion的方式间接变更数据
context
:【默认参数】指向vuex的实例store大仓库
仓库中
const store = new Vuex.Store({
state: {
count: 0
},
mutations: {
add(state,payload) {
state.count++
state.count += payload
}
},
actions: {
addAsync(context,payload) {
setTimeout(() => {
//在 action 中不能直接修改 state 中的数据,
//必需通过 context.commit 触发某个mutations 才行
context.commit('add',payload)
}, 1000);
}
},
})
组件中
//第一种方法-----------------
methods: {
//异步的让count自增+1
btnhandlel() {
//这里的 dispatch 函数专门触发 Action
this.$store.dispatch('addAsync',100)
},
},
//触发actions的第二种方式-------------------------
import {mapActions} mapMutations from 'vuex';
2.通过刚才导入的mapActions函数,将当前组件需要的全局数据,映射为当前组件的methods方法
数组的形式
methods: {
...mapActions(['addAsync']),
},
对象形式:可以自定义事件句柄
...mapMutations({
a: 'addAsync',
}),
在调用时传递参数
<button @click="a(3)">-1</button>
触发Action异步任务时携带参数的步骤?
- 1.组件调用时传入一个参数
- 2.actions方法里接受外界传递过来的参数
- 3.触发mutatios时把参数传到mutatios里
- 4.mutatios的方法里接收传递过来的参数,并实现对数据的修改
4.Getter 相当于vue中的computed
- Getter用于Stroe中的数据进行加工处理形成新的数据,类似vue的计算属性
- store中的数据发生改变Getteer中的数据也会跟着变化
state
:【默认参数】指向的是vuex的实例store里的stategetters
:【默认参数】指向的是vuex的实例store里的getters,可以根据它,获得getters中其他属性的信息
仓库中
//定义Getter
const store = new Vuex.Store({
state: {
arr: [10, 20, 30]
},
getters: {
showNum(state) {
return state.arr.filter(item => {
return item > 10
})
}
},
})
组件中
第一种方式:this. $store.getters.名称
{{ $store.getters.showNum }}
注意:在template模板中使用this可以省略,直接沿着原型链调用(不推荐没缓存)
//--------------
第二种方式: 辅助函数
1.//从vuex中按需导入mapGetters函数
import {mapGetters} from 'vuex';
2.通过刚才导入的mapGetters函数,将当前组件需要的全局数据,映射为当前组件的computed计算属性
注意:计算属性展示到页面使用插值表达式(小胡子语法)推荐,有缓存
数组形式:
computed: {
...mapGetters(['showNum']),
},
对象形式:可以自定义接收 调用的时候用自定义的名
computed: {
g: 'showNum',
}),
//-------------
第三种方式:放到computed计算属性中使用
注意:这里要加this
computed: {
snum() {
return this.$store.getters.showNum
},
},
5.modules 模块
- 作用:减少单一状态树的shore对象存放数据导致的臃肿,将整个sotre对象拆分为多个模块module,每个模块都存在自己局部的
state、getters、mutations、actions、namespaced
,甚至仍然将这个模块继续向下拆分 - namespaced:默认情况下,模块内部的 action、mutation 和 getter 是注册在全局命名空间的——这样使得多个模块能够对同一 mutation 或 action 作出响应。
- 如果希望你的模块具有更高的封装度和复用性,你可以通过添加
namespaced: true
的方式使其成为带命名空间的模块。当模块被注册后,它的所有 getter、action 及 mutation 都会自动根据模块注册的路径调整命名。- 我们在
...mapGetters("moduleA",["msg"])
,寻找的是moduleA
模块中的msg状态值,如果没有写moduleA
的话,它会直接去全局的store中找状态值msg
第一步:需要创建一个独立的模块:
const moduleA = {
state: {
msg: '我是moduleA',
arr: [1, 2, 3, 4, 5, 6]
},
getters: {
donearr: state => {
return state.arr.filter(item => {
return item % 2 == 0
})
}
},
mutatios: {},
actions: {},
modules: {}
}
export default moduleA
第二步:在store实例中导入并挂载:
重点: store挂载moduleA之后: moduleA中的state对象会挂载到store的state对象上
moduleA中的mutations、getters、actions对象会挂载到store的对应对象上
import moduleA from './moduleA'
const store = new Vuex.Store({
namespaced: true,//命名空间
modules: {
moduleA
},
})
第三步:在vue组件中调用vuex的modules:
//方式一:通过$store导入
$store.state.moduleA.msg //获取moduleA模块中的属性
{{ $store.getters['moduleA/donearr'] }};//获取方法或计算属性
//方式二写在computed计算属性中----------------------
----------------获取属性-----------
computed: {
msg() {
return this.$store.state.moduleA.msg
},
-----------获取方法-----------------
computed: {
donearr() {
return this.$store.getters['moduleA/donearr']
},
//方式三 辅助函数 注意加命名空间------------------
----------获取属性-------------
import { mapState } from 'vuex'
computed: {
...mapState('moduleA', ['msg']),
}
-------------获取方法和计算属性--------------
import { mapGetters } from 'vuex'
computed: {
...mapGetters({
donearr: 'moduleA/donearr',
}),
},
辅助函数第二种方法--------------
import { createNamespacedHelpers } from 'vuex'
const { mapState } = createNamespacedHelpers('moduleA')
----------------获取属性------------
computed: {
...mapState(['msg']),
}
--------------获取方法和计算属性----------------
computed: {
...mapGetters(['donearr']),
}
辅助函数
- ==mapState()获取的是大仓库state属性中的状态值==
- ==mapGetters()获取的是大仓库getters属性中的状态值==
- ==mapMutations()获取的是大仓库mutations属性中的方法==
- ==mapActions)获取的是大仓库actions属性中的方法==
vuex中的缓存
- ==问题==:没有用缓存之前,我们每次打开页面都会发送请求
- ==目标==:应用vuex实现缓存,只要页面不刷新,不关闭,数据如果是null,我就发送请求,如果不是null就从vuex的缓存中拿数据
第一步:创建异步方法获取服务器数据,并把数据赋值给状态值
import Vue from 'vue'
import Vuex from 'vuex'
import api from "@/api/index.js"
Vue.use(Vuex)
const store = new Vuex.Store({
// 第一步:list专门存放数据
state: {
list: null
},
getters: {
},
// 第二步:payload 接收传递过来的数据,修改list的值,如果请求成功就不为null了
mutations: {
setlist(state, payload) {
state.list = payload
}
},
//第三步:异步函数需要写在actions中
actions: {
async getData(context) {
let result = await api.getTaskList()
if (result.code == 0) {//返回数据成功
//异步函数想修改state状态值,必须经过mutationscommit执行setlist 传递数据
context.commit("setlist", result.list);
} else {
context.commit("setlist", []);
}
}
},
})
export default store;
第二步:在页面加载之前,先判断是否有缓存,如果有直接用
<template>
<div class="three">
{{ list }}
</div>
</template>
<script>
export default {
name: "Three",
data() {
return {};
},
computed: {
//仓库中存放的list数据
list() {
return this.$store.state.list;
},
},
//创建之后的生命函数执行仓库的异步函数getData
created() {
if (this.list == null) {
this.$store.dispatch("getData");
}
},
};
</script>
<style>
</style>