组件间通信方式
组件内的状态管理流程
- state: 驱动应用的数据源
- view: 以声明方式将state 映射到视图
- actions: 响应在view 上的用户输入导致的状态变化
view --> actions —> state: 单项数据流
组件间通信方式
-
父组件给子组建的传值
- 父组件中给子组件通过相应的属性传值
- 子组件通过 props 接收数据
-
子组件给父组件的传值
-
自定义事件
-
this.$emit( ‘fn’ , data)
<Child @enlarge=" hS += $event "></Child> // 行间可以通过 $event 接收子组件传递的值
-
-
不相关组件间的传值
-
自定义事件 eventBus : 中央事件总线
const Bus = new Vue() // 空vue实例 bus.$emit('fn1', this.value) // 触发事件 bus.$on('fn1', () => { // 注册事件 // ... })
-
-
其他常见方式
-
$root
-
$parent
-
$children
-
$refs ——> ref 获取子组件
-
在普通HTML标签上使用 ref, 获取到的是 DOM对象
-
在组件标签上使用 ref,获取到的是组件实例
<input ref="input" type='text' v-model="value" /> //... this.$refs.input.focus() // 如果是组件,可以获取组件中的属性或方法 this.$refs.c.focus() this.$refs.c.value = 'abc'
ref 容易导致数据管理的混乱。
-
-
简易的状态管理方案
- 多视图依赖同一状态
- 来自不同视图的行为需要变更同一状态
共享数据抽取出来,放在全局唯一的对象中管理。
Vuex的基本用法
Vuex
Vuex 采用集中式的方式存储需要存储的状态。
Vuex 作用:
-
进行状态管理
- 解决复杂组件通信
- 数据共享
Vuex 集成到了 devtools 中,提供了 time-travel 时光旅行、历史回滚的功能。
非必要的情况下不要使用Vuex, 大型的单页应用程序多视图依赖同一状态时使用。
Vuex 的核心概念
- Store:包含状态的容器,全局只有一个
- State: 唯一状态树,可以拆分成模块。响应式
- Getter: Vuex中的计算属性,可以缓存计算结果
- Mutation: 状态的变换必须要通过提交Mutation 来实现,只能是同步操作
- Action: 异步操作
- Module: 拆分Store 为多个模块
vuex 基本代码结构:
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
export default new Vuex.Store({
state: {
},
getters: {
},
mutations: {
},
actions: {
},
modules: {
}
})
State 的使用:
// 组件中使用
<p>{{ $store.state.count }}</p>
// mapState 自动生成状态对应的计算属性, 简化 $store.state 的使用
import { mapState } from 'vuex'
export default {
computed: {
...mapState(['count', 'msg'])
}
}
<p>{{ count }}</p>
// 如果组件中,有相同的属性名,则可以使用别名来处理
...mapState({ num: 'count', message: 'msg'})
Getters 的使用:
// store.js
getters: {
reversMsg(state) {
return state.msg.reverse()
}
}
// 组件中使用
<p>reverseMsg: {{ $store.getters.reverseMsg }}</p>
// 使用 mapGetters 简化 $store.getters
import { mapGetters } from 'vuex'
computed: {
...mapGetters(['reverseMsg']) // 也可使用 { } 的形式重命名
}
Mutations的使用:
// 组件中使用
<button @click="$store.commit('increate', 2)">Mutions</button> // 通过commit() 提交到Mutation
// store.js
mutations: {
increate(state, payload){ // payload 是 commit() 传递的第二个参数
state.count += payload
}
}
// 使用 mapMutations 简写 $store.commit(), 放在 methods中,而不是computed中
import { mapMutations } from 'vuex'
methods: {
...mapMutations(['increate'])
}
<button @click="increate(2)">Mutions</button>
Mutations状态更改都要通过它, 只能进行同步操作,在浏览器vue-devtools插件 中,可以看到每一步的Mutations,以及历史回滚。
Action的使用:
// 异步更改数据,然后提交Mutations
// 在组件中使用
<button @click="$store.dispatch('asyncIncreate', 4)"></button> // $store.dispatch() 调用action中定义的方法
// 使用 mapActions() 简化$store.dispatch() , 放在 methods 中
import { mapActions } from 'vuex'
methods: {
...mapActions(['asyncIncreate'])
}
<button @click="asyncIncreate(4)">Mutions</button>
Modules 的使用:
$store.state.prodducts.xxx // $store.state.模块名.模块成员
// carts.js
const state = {}
const mutations = {}
const actions = {}
const modules = {}
export default{
namespaced: true, // 开启命名空间
state,
mutations,
actions,
modules
}
// 使用 mapMutations 映射模块中的mutations
... mapMutations(['increate']),
... mapMutations('cart', ['setProducts']) // 模块名,mutation中的方法
$store.commit('abc', 56) // 如果多个模块中有 abc 的mutation, 它都会被执行
Vuex 严格模式
开启严格模式后,在组件中直接修改state会报错。
不要再生产模式下开启严格模式,会严格检查状态树,影响性能。
// store.js
export default new Vuex.Store({
strict: process.env.NODE_ENV !== 'production', // true 生产环境下不开启严格模式
})
模拟vuex
// index.js
let _Vue = null
class Store(){
constructor(options){
const {
state = {}, // 解构的默认值为空{}
getters = {},
mutations = {},
actions = {},
} = options
this.state = _Vue.observable(state) // 响应式处理
this.getters = Object.create(null)
Object.keys(getters).forEach(key => { // 将参数getters处理后,放入 this.getters
Object.defineProperty(this.getters, key, {
get: () => getters[key](state)
})
})
// 私有方法
this._mutations = mutations
this._actions = actions
}
commit(type, payload){
this._mutations[type](this.state, payload) // type对应的方法
}
dispatch(type, payload){
this._actions[type](this, payload)
}
}
function install(Vue){
_Vue = Vue
_Vue.mixin({
beforeCreate(){
if(this.$options.store){
_Vue.prototype.$store = this.$options.store
}
}
})
}
export default{
Store,
install
}