Vuex是什么?
Vuex是实现组件全局状态(数据)管理的一种机制,可以方便的实现组件之间的共享
不使用Vuex进行传值
父子组件传值:
父向子传值:v-bind属性綁定
子向父传值:v-on 事件綁定
<div id="root">
<counter :count='1' @inc="handleIncrease"></counter>
<counter :count='2' @inc="handleIncrease"></counter>
<div>{{total}}</div>
</div>
var counter = {
props: ['count'],
data: function (){
return {
number: this.count
}
},
template: '<div @click="handleClick">{{number}}</div>',
methods: {
handleClick: function () {
this.number=this.number+1 ;
this.$emit('inc',1)
}
}
}
var vm = new Vue({
el: '#root',
data:{
total:5
},
components: {
counter: counter
},
methods:{
handleIncrease:function(step){
this.total+=step
}
}
})
父传子:父组件用v-bind绑定count属性,子组件使用props接受父组件传过来的值,将值经过data处理后,在template上使用该值。
子传父:在template绑定了点击事件,点击后,触发子组件设置的方法,用$emit触发v-on绑定在父组件的@int事件,进而触发父组件设置的方法。
非父子之间共享数据:EventBus
$on 接收数据的那个组件
$emit 发送数据的那个组件
<div id="root">
<child content="太阳"></child>
<child content="月亮>
</div>
Vue.prototype.bus=new Vue()
Vue.component('child', {
props:{
content:String
},
// 解决单向数据流
data:function(){
return{
selfContent:this.content
}
},
template:'<div @click="handleClick">{{selfContent}}</div>',
methods:{
handleClick:function(){
this.bus.$emit('change',this.selfContent)
}
},
mounted:function(){
var this_=this
// 监听bus触发事件change
this.bus.$on('change',function(msg){
this_.selfContent=msg
})
}
})
var vm=new Vue({
el:"#root"
})
在vue的prototype上面挂载了bus属性,在后续只要创建vue实例上面都有bus属性。所以子组件可以通过this.bus.$emit事件,通过this.bus.$on监听事件,实现子组件之间传值
为什么使用Vuex?
单向数据流
Vue的官方文档是这么说的:
状态自管理应用包含以下几个部分:
- 状态,驱动应用的数据源;
- 视图,以声明方式将状态映射到视图;
- 操作,响应在视图上的用户输入导致的状态变化。 以下是一个表示“单向数据流”理念的简单示意:
单向数据流,通俗点就是父组件可以随意向子组件传递参数,子组件不能反过来修改父组件传递的内容。这就是为什么上述的代码都要通过data定义新的数据,将父组件传过来的值保存在新数据上,通过改变新数据值达到改变值得效果,但是父组件的值是没有改变的,始终展示的都是复制过来的数据值。
单向数据流缺点
官方文档中也把单向数据流的缺点描述的很清楚:
当我们的应用遇到多个组件共享状态时,单向数据流的简洁性很容易被破坏:
- 多个视图依赖于同一状态。
- 来自不同视图的行为需要变更同一状态。
对于问题一,传参的方法对于多层嵌套的组件将会非常繁琐,并且对于兄弟组件间的状态传递无能为力。对于问题二,我们经常会采用父子组件直接引用或者通过事件来变更和同步状态的多份拷贝。以上的这些模式非常脆弱,通常会导致无法维护的代码。
因此,我们为什么不把组件的共享状态抽取出来,以一个全局单例模式管理呢?在这种模式下,我们的组件树构成了一个巨大的“视图”,不管在树的哪个位置,任何组件都能获取状态或者触发行为!
所以Vuex诞生了。
Vuex组成
下图为vue官网文档Vuex图示:
Vuex由Action,Mutations,State组成
VueX的使用
使用Vuex的好处
- 能够在vuex 中集中管理共享的数据,易于开发和后期维护
- 能够高效地夹现组件之问的数据共享,提高开发效率
- 存储在 vuex 中的数据都是响应式的,能够实时保持数据与页面的同步
基本使用方法
- 安装VueX依赖
npm install vuex --save
- 导入Vuex包
import Vuex from 'vuex'
Vue.use(Vuex);
3.创建store对象
export default new Vuex.Store({
state,
mutations,
actions
4.将store对象挂载到vue实例中
new Vue({
store,
router,
render: h => h(App),
}).$mount('#app')
核心概念的使用
State
State 提供唯一的公共数据源,所有共享的数据都要统一放到 Store 的 State 中进行存储。
定义State:
export default new Vuex.Store({
state: {
username: '李四'
}
}
访问State中数据的第一种方式
this.$store.state.全局数据名字;
第二种方式
1.从vueX中按需导入mapState函数
import { mapState} from 'vuex';
通过刚才导入的mapState 函数,将当前组件需要的全局数据,映射为当前组件的computed 计算属性:
2.将全局数据,映射为当前组件的计算属性
computed:{
...mapState([''])
}
Mutation
Actions通过commit函数触发mutation
mutation 必须同步执行
Mutation 用于变更 Store中 的数据。
- 只能通过mutation 变更 Store 数据,不可以直接操作 Store 中的数据。
- 通过这种方式星然操作起来稍微繁琐一些,但是可以集中监控所有数据的变化。
定义Mutation
export default new Vuex.Store({
state: {
username: '',
},
mutations:{
saveUserName(state, username) {
state.username = username;
}
}
}
触发mutation第一种方式
this.$store.commit('saveUserName', username)
第二种方式 1.从vueX中按需导入mapMutations函数
import { mapMutations} from 'vuex';
通过刚才导入的mapMutations 函数,将需要的mutations函数,映射为当前组件的method方法:
...mapMutations([])
Actions
Vue Components通过dispatch函数触发action
action可以异步执行
定义action
export default new Vuex.Store({
state,
mutations,
actions:{
saveUserName(context,username){
context.commit('saveUserName', username);
}
}
});
触发actions第一种方式
this.$store.dispatch('saveUserName','张三');
第二种方式
import { mapActions } from 'vuex';
...mapActions(['']),
Getter
Getter 用于对 Store 中的数据进行加工处理形成新的数据。
- Getter 可以对 Store 中已有的数据加工处理之后形成新的数据,类似Vue的计算属性。
- store 中数据发生变化,Getter 的数据也会跟着变化。
定义Getter
const store = new vue.store({
state: {
count: 0
},
getters: {
showNum: state => {
return '当前最新的数量是【' + state.count + '】'
}
}
})
使用 getters 的第一种方式
this.$store. getters.名称
第二种方式
import { mapGetters } from 'vuex'
computed:{
...mapGetters (['showNum'])
}