在Windows的应用程序开发中,我们习惯了变量(对象)声明和使用方式,就是有全局和局部之分,定义好了全局变量(对象)以后在其他窗体中就可以使用,但是窗体之间的变量(对象)无法共享,如果需要可以通过参数传递的方式进行。
在JavaScript编程中,很在意全局变量的定义使用,尽量避免全局变量的定义和使用,以防止出现可能的“变量污染”,比如其他应用随意修改全局变量。
在vue中,如果只是一般的小程序或者个人独立开发的程序,全局变量(对象)不多,也可以直接在main.js或者App.vue中定义,然后在其他组件中直接使用定义好的变量(对象:参数和方法)。
一、如果按照以往的想法,在其他组件中怎样使用main.js中或者其他组件中定义好的参数和方法?
1、全局的变量、方法和属性需要挂载到vue的原型才能为其他组件使用。全局的变量、方法和属性需要一个显式定义,以便能够在全局范围内使用。
例如,声明全局的变量或者方法:
Vue.prototype.$GlobalMethods = {
MyChangeName: function (newName) {
this.MyObj.name = newName;
}
};
Vue.prototype.$GlobalVar='2222';
这样就可以在其他组件使用定义好的变量或者方法:
//使用方法
this.$GlobalMethods.MyChangeName.call(this.$root, 'Jane123');
//使用变量
this.$GlobalVar='dddd';
上面的方法是JavaScript本身具有的方法,虽然可以使用,但是vue是响应式的,这里变量的改变却不是响应式的,对于稍微大一些的程序或者团队开发的程序,这样的做法不可行。
2、在main.js或者App.vue中定义的组件、变量、方法、属性都是局部的,除非通过如 props、$emit、Vuex 状态管理等向下与向上传递或者通过this.root来访问,否则并不能为其他组件使用。
在main.js文件中,在创建一个根 Vue 实例后启动整个 Vue 应用。在这个文件中定义的变量、函数或 Vue 实例的其他配置仅属于该 Vue 实例。虽然这个根实例挂载的组件和子组件可以通过 this.$root访问到根实例的属性和方法,但这些属性和方法并不自动变为全局可用。
在main.js中定义如下:
new Vue({
data:{
MyObj:{
name:'John1',
age:3
}
},
methods:{
changeName(name){
this.MyObj.name=name;
}
},
router,
store,
render: h => h(App)
}).$mount('#app')
在其他组件中使用:
this.$root.MyObj.name='修改后的名字';
this.$root.MyObj.age='222222';
this.$root.changeName('PSP');
3、全局组件,需要通过Vue.component('global-component01', { // 组件配置 })来进行。
4、在 Vue中的组件数据是隔离的,一个组件内部定义的data是无法被另一个组件直接访问和修改的。
在前面的学习中,知道通过下面的几种方式来访问组件数据:
⑴. 事件总线(Event Bus)
适用于小型应用,创建一个事件总线并在两个组件间通过它通信。在 Vue 2 中,你可以使用一个空的 Vue 实例作为中央事件总线。
⑵ 父子组件通信
通过props把数据传给子组件,通过自定义事件或sync修饰符让子组件通知父组件进行相应的更新。
⑶ 通过$refs引用
添加ref属性,在方法中直接调用子组件实例的方法或修改它的数据。
上面的方式方法,前面写过文章《Vue组件化编程的组件通信》、《三种简洁易行的方法解决基于Vue.js的组件通信》。
对于大型应用或者基于团队的开发,推荐使用 Vuex,Vuex提供更清晰和可维护的状态管理。
二、使用vuex
在使用vue create 项目名称创建项目时选择了VueX,就可以使用它来进行变量的共享操作。VueX 是一个用于 Vue.js 应用程序的状态管理模式和库,它可以集中管理应用程序的各种状态,包括变量、函数(方法)、组件等。
修改store目录下的index.js:
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
export default new Vuex.Store({
state: {
age:0
},
mutations: {
AddAge (state, num) {
state.age += num;
},
ReduceAge (state, num) {
state.age -= num;
}
},
actions: {
AddAge ({ commit }, num) {
commit('AddAge', num);
},
ReduceAge ({ commit }, num) {
commit('ReduceAge', num);
}
},
getters: {
age: state => state.age
}
});
修改HomeView.vue内容:
<template>
<div>
<h1>年龄:{{ age }}</h1>
<input type="number" v-model="num" />
<button @click="increment">增加年龄</button>
<button @click="decrement">减少年龄</button>
</div>
</template>
<script>
export default {
data () {
return {
num: 1
};
},
computed: {
age () {
return this.$store.getters.age;
}
},
methods: {
increment () {
this.$store.dispatch('AddAge', this.num);
},
decrement () {
this.$store.dispatch('ReduceAge', this.num);
}
}
};
</script>
结果显示:
使用VueX进行组件之间的变量、方法函数的共享操作,看起来还是挺繁琐的。具体的使用也是因人因项目而宜,不是硬性要求。
1、使用state对象来定义状态。
2、mutations对象包含用于修改状态的方法。
3、actions对象包含用于触发mutations的方法。
4、getters对象包含用于获取状态的方法。
5、组件使用时通过触发mutations定义好的方法来完成操作。
下面是对多个变量的定义与使用。
定义:
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
export default new Vuex.Store({
state:{
id:123,
name:'John',
age:1
},
mutations: {//修改
ChangeAge (state, num) {
state.age = num;
},
},
actions: {
},
getters: {
}
});
使用:
<template>
<div>
<h1>ID:{{id }}</h1>
<h1>姓名:{{ $store.state.name }}</h1>
<h1>年龄:{{ age }}</h1>
<input type="number" v-model="age">
</div>
</template>
<script>
export default {
computed: {
id(){
return this.$store.state.id;
},
age: {
get(){
return this.$store.state.age;
},
set(value){
this.$store.commit('ChangeAge',value)
}
}
}
};
</script>
对于多个变量也可以封装在一个对象中。
export default new Vuex.Store({
state(){
return {
MyObj:{
name:'John',
age:1
}
}
},
mutations: {
AddAge (state, num) {
state.MyObj.age += num;
},
ReduceAge (state, num) {
state.MyObj.age -= num;
}
},
actions: {
AddAge ({ commit }, num) {
commit('AddAge', num);
},
ReduceAge ({ commit }, num) {
commit('ReduceAge', num);
}
},
getters: {
age: state => state.MyObj.age
}
});
三、使用mapState辅助函数
mapState辅助函数是Vue.js提供的用于将store中的状态映射到组件的计算属性computed中。它简化了在组件中访问store中的状态的过程。
通过mapState辅助函数可以将store中的状态定义为组件的计算属性,而不需要显式地访问store.state。
当参数是数组时,每个元素可以是一个字符串或是一个函数。如果是字符串,它会作为映射后的计算属性名;如果是函数,函数中可以访问state,并返回一个计算属性值。
当参数是对象时,可以使用键-值形式,其中键是计算属性名,值是一个函数。这个函数接受state作为第一个参数,可以直接访问state并返回一个计算属性值。
比如上面的显示可以改写为:
<template>
<div>
<h1>ID:{{id }}</h1>
<h1>姓名:{{ $store.state.name }}</h1>
<h1>年龄:{{ age }}</h1>
<input type="number" @input="ChangeAge" :value="age">
</div>
</template>
<script>
import { mapState } from 'vuex';
export default {
computed: mapState(['id','name','age']),
methods:{
ChangeAge(e){
this.$store.commit('ChangeAge',e.target.value)
}
}
};
</script>
上面是采用数组的方式,下面是采用对象的方式:
<template>
<div>
<h1>ID:{{ MyID }}</h1>
<h1>姓名:{{ name }}</h1>
<h1>年龄:{{ ChangeAge }}</h1>
<input type="number" v-model="num">
</div>
</template>
<script>
import { mapState } from 'vuex';
export default {
data(){
return { num:1 }
},
computed:mapState({
MyID:state=>state.id,
name:'name',
ChangeAge(state){
return state.age+this.num
}
})
};
</script>
得到的效果也是一样的。
在计算属性的书写中,如果还有其他的计算方法或者属性,那么就需要使用对象展开符。
computed:{
count(){ return 1 },
...mapState({
MyID:state=>state.id,
name:'name',
ChangeAge(state){
return state.age+this.num
}
})
}