【Vue】组件传参、vuex状态管理
一、props:父组件向子组件传递数据(常用)
缺点:若组件嵌套层次多,传递数据比较麻烦
- 父组件
<template>
<child :message="message"></child>
</template>
<script>
import Child from './Child.vue'
export default {
components: {
Child
},
data() {
return {
message: '父组件'
}
}
}
</script>
- 子组件Child
<template>
<div>
<span>{{message}}</span>
</div>
</template>
<script>
export default {
props: {
message: {
type: String,
default: '子组件'
}
}
}
</script>
二、$emit:子组件向父组件传递数据(常用)
- 父组件
<template>
<child :num="num" @addCount="addCount"></child>
</template>
<script>
import Child from "./Child.vue";
export default {
components: {
Child
},
data() {
return {
num: 100
};
},
methods: {
addCount(res) {
//将子组件传来的参数复制给num
this.num = res;
}
}
};
</script>
- 子组件Child
<template>
<div>
<el-button type="primary" @click="addCount">{{ count++ }}</el-button>
</div>
</template>
<script>
export default {
props: {
num: {
type: Number,
default: 0
}
},
data() {
return {
num: 100
};
},
methods: {
addCount() {
//将num传给父组件
this.$emit("addCount", this.num + 1);
}
}
};
</script>
三、vuex:状态管理,实现多个组件进行数据共享(常用,重点)
- store.js
import Vuex from "vuex";
import createPersistedState from 'vuex-persistedstate'
Vue.use(Vuex);
const store = new Vuex.Store({
state: {
//基本数据,用来存储变量。
count: 0,
list: [
{ id: 1, is: false },
{ id: 2, is: true }
]
},
getter: {
//Getter类似于Vue的computed对象。是根据业务逻辑来处理State,使得生成业务所需的属性。
listFilter: (state, getters) => {
return state.list.filter(res => res.is);
}
},
mutations: {
//更改vuex的store中的状态的唯一方法,只能是同步操作。
increment(state, payload) {
state.count += payload;
}
},
actions: {
//Action 提交的是 mutation,而不是直接变更状态;
//Action 可以包含任意异步操作。
addCount({ commit }) {
// context ({ dispatch, commit })是一个与 store 实例具有相同方法和属性的 context 对象
setTimeout(() => {
commit("increment");
}, 1000);
}
//Action处理异步的正确使用方式
// async actionA({ commit }) {
// commit('gotData', await a())
// },
// async actionB({ dispatch, commit }) {
// await dispatch('actionA') // 等待 actionA 完成
// commit('gotOtherData', await b())
// }
},
module: {
//模块化,module可以将store 分割成模块,每个模块中拥有自己的 state、mutation、action 和 getter
},
//持久化
plugins: [createPersistedState()],
});
- 将store注入到根实例
// 注入到根实例-入口文件
new Vue({
el: '#app',
store,
template: '<App/>',
components: { App }
})
- 组件A
<template>
<div>
<el-button type="primary" @click="addCount"></el-button>
</div>
</template>
<script>
import { mapMutations, mapActions } from "vuex";
export default {
// 原始写法
// methods: {
// //改变状态count
// addCount() {
// this.$store.commit("increment", 5);
// this.$store.dispatch({
// type: "incrementAsync"
// });
// }
// }
// };
//mapMutations 辅助函数 获取
//mapActions 辅助函数 获取
methods: {
//方式1
// ...mapMutations(["increment"]),
//方式2
...mapMutations({
// userInfo 是一个重新定义的别名,本组件可以直接调用这个方法名字使用
increment1: "increment",
}),
//mapActions写法同mapMutation
...mapActions(["incrementAsync"]),
//改变状态count
addCount() {
this.increment1(5);
// 以对象形式分发Action
this.incrementAsync(5);
},
},
};
</script>
- 组件B
<template>
<div>{{ count }}{{ listFilter }}</div>
</template>
<script>
import { mapState, mapGetters } from "vuex";
export default {
// 原始写法
// computed: {
// count() {
// // 获取vuex里的count
// return this.$store.state.count;
// },
// listFilter() {
// // 获取vuex里的listFilter
// return this.$store.getters.listFilter;
// },
// }
//mapState 辅助函数 获取
//mapGetters 辅助函数 获取
computed: {
// 注意:这种写法用mapstate等这种辅助函数的时候,前面的方法名和获取的属性名是一致的
...mapState(["count"]),
...mapGetters(["listFilter"]),
},
};
</script>
- 模块化:将 store 分割为模块(module),每个模块拥有自己的 state 、 getters 、mutations 、actions 。(开发常用)
四、eventBus:常用于多层嵌套组件场景下兄弟组件或任意两个组件之间通讯(事件总线)
缺点:不支持响应式, $on事件不会自动清楚销毁的,需要手动来销毁,可在beforeDestroy中解绑监听,避免重复触发。
- 入口文件添加事件总线
import Vue from 'vue';
// 添加事件总线
Vue.prototype.$eventBus = new Vue();
- 组件A
<template>
<div>
{{ a }}
</div>
</template>
<script>
export default {
data() {
return {
a: "",
};
},
create() {
this.$eventBus.$on("message", (res) => {
//组件b传过来的参数
this.a = res;
console.log("收到消息!");
});
},
// 组件销毁时需要解绑监听
beforeDestroy() {
eventBus.$off("message");
},
};
</script>
- 组件B
<template>
<div>
<span>{{a}}<span>
</div>
</template>
<script>
export default {
data() {
return {
a: '兄弟组件'
};
},
create() {
this.eventBus.$emit('message',a)
}
};
</script>
五、ref:通过$refs可以拿到子组件的实例,从而调用实例里的方法来实现父子组件通信
- 父组件
<template>
<el-button type="primary" @click="get">通过ref获取子组件实例</el-button>
哦那个子组件获取的: {{ num }}
<child ref="child"></child>
</template>
<script>
import Child from "./Child.vue";
export default {
components: {
Child
},
data() {
return {
num: 100
};
},
methods: {
get() {
this.num = this.$refs.child.num;
}
}
};
</script>
- 子组件Child
<template>
<div>
<el-button type="primary" @click="addCount">{{ num }}</el-button>
</div>
</template>
<script>
export default {
data() {
return {
num: 100
};
},
methods: {
addCount() {
this.num++;
}
}
};
</script>
待补充
六、provide / inject:通过依赖注入(inject / provide)的方式,向其所有子孙后代传递数据
缺点:无法监听数据修改的来源,不支持响应式。
- 父组件
<template>
<el-button type="primary" @click="get">通过ref获取子组件实例</el-button>
哦那个子组件获取的: {{ num }}
<child ref="child"></child>
</template>
<script>
import Child from "./Child.vue";
export default {
components: {
Child
},
// 提示:provide 和 inject 绑定不支持响应式。
provide() {
return {
// 传过去的必须是可监听的对象,注意,是对象,其他类型都不行
user: this.userInfo
};
},
data() {
return {
userInfo: {
id: "1"
}
};
},
methods: {
get() {
this.userInfo.name= "小明";
}
}
};
</script>
- 子组件Child
<template>
<div>
{{ user.name}}
</div>
</template>
<script>
export default {
inject: ["foo"]
};
</script>
七、attrs/listeners
自行查阅资料
八、$children / $parent
自行查阅资料