vue组件间的通信及vuex详解

2022年6月12日10:28:33

概述

组件之间的共享数据的方式

父向子传值:v-bind 属性绑定

子向父传值:v-on 事件绑定

兄弟组件之间共享数据:EvenBus

  • $on 接收数据的那个组件

  • $emit 发送数据的那个组件

父向子传值

父组件模板:

<template><child:msg="message"></child></template><script>import childfrom'./child.vue';exportdefault{
    components:{
        child},data(){return{
            message:'father data';}}}</script>

子组件模板:

<template><div>{{msg}}</div></template><script>exportdefault{
    props:{
        msg:{
            type: String,
            required:true}}}</script>

2. 子组件向父组件通信

父组件模板:

<template><child @Func="func"></child></template><script>import childfrom'./child.vue';exportdefault{
    components:{
        child},
    methods:{func(msg){
            console.log(msg);}}}</script>

子组件模板:

<template><button @click="handleClick">点我</button></template><script>exportdefault{
    props:{
        msg:{
            type: String,
            required:true}},methods(){handleClick(){this.$emit('Func');}}}

3. 兄弟组件之间通信

父子组件中可以用props和$emit()。那么怎么实现非父子组件间的通信,可以通过实例一个vue brother作为媒介,要相互通信的兄弟组件之中,都引入brother,然后通过分别调用brother事件触发和监听来实现通信和参数传递。 brother.js可以是这样写:

import Vuefrom'vue'exportdefaultnewVue()

在需要通信的组件都引入brother.js:

<template><button @click="toBrother">子组件传给兄弟组件</button></template><script>import Busfrom'../common/js/brother.js'exportdefault{
	methods:{toBrother(){
	        brother.$emit('on','来自兄弟组件')}}}</script>

另一个组件也import brother.js在mounted钩子函数中监听on事件:

import Busfrom'../common/js/brother.js'exportdefault{data(){return{
        message:''}},mounted(){
       brother.$on('on',(msg)=>{this.message= msg})}}

也可以使用v-model实现父子组件间通信

父组件

<template><div><child v-model="total"></child><button @click="increse">增加5</button></div></template><script>import Childfrom"./child.vue"exportdefault{
    components:{
        Child},data:function(){return{
            total:0};},
    methods:{increse:function(){this.total+=5;}}}</script>

子组件

第一种方式

<template><div><span>{{value}}</span><button @click="reduce">减少5</button></div></template><script>exportdefault{
    props:{
        value: Number// 注意这里是value},
    methods:{reduce:function(){this.$emit("input",this.value-5)}}}</script>

第二种方式model(2.2.0新增)
允许一个自定义组件在使用 v-model 时定制 prop 和 event。默认情况下,一个组件上的 v-model 会把 value 用作 prop 且把 input 用作 event,但是一些输入类型比如单选框和复选框按钮可能想使用 value prop 来达到不同的目的。使用 model 选项可以回避这些情况产生的冲突。

<template><div><span>{{give}}</span><button @click="reduce">减少5</button></div></template><script>exportdefault{
    props:{
        give: Number},
    model:{
    prop:'give',
    event:'reduce'},
    methods:{reduce:function(){this.$emit("reduce",this.give-5)}}}</script>
Vue.component('my-checkbox',{
  model:{
    prop:'checked',
    event:'change'},
  props:{// this allows using the `value` prop for a different purpose
    value: String,// use `checked` as the prop which take the place of `value`
    checked:{
      type: Number,default:0}},// ...})<my-checkbox v-model="foo" value="some value"></my-checkbox>//上述代码相当于:<my-checkbox:checked="foo"
  @change="val => { foo = val }"
  value="some value"></my-checkbox>

具体内容请参考:https://cn.vuejs.org/v2/api/#model

vuex详解
首先先看一下官网的图
vue组件间的通信及vuex详解
根据上图做一下简单总结

vuex中,有默认的五种基本的对象:

state:存储状态(变量)

getters:对数据获取之前的再次编译,可以理解为state的计算属性。我们在组件中使用 $ sotre.getters.fun()

mutations:修改状态,并且是同步的。在组件中使用$store.commit(’’,params)。这个和我们组件中的自定义事件类似。

actions:vuex为了解决mutations只有同步的问题 , 提出了actions(异步),专门用来解决mutations只有同步无异步的问题 . 异步操作。在组件中使用是 $ store.dispath(’’)

modules:store的子模块,为了开发大型项目,方便状态管理而使用的。这里我们就不解释了,用起来和上面的一样。

vuex中的store分模块管理,需要在store的index.js中引入各个模块,为了解决不同模块命名冲突的问题,将不同模块的namespaced:true,之后在不同页面中引入getter、actions、mutations时,需要加上所属的模块名

vuex中 传递数据的流程
当组件进行数据修改的时候我们需要调用dispatch来触发actions里面的方法。
actions里面的每个方法中都会有一个commit方法,当方法执行的时候会通过
commit来触发mutations里面的方法进行数据的修改。mutations里面的每个函数都会有一个state参数,这样就可以在mutations里面进行state的数据修改,当数据修改完毕后,会传导给页面。页面的数据也会发生改变

这里我们看一下基本使用案例

<template><div><h1>当前求和为:{{sum}}</h1><h3>我在{{school}},学习{{subject}}</h3><h3>当前求和放大10倍为:{{bigSum}}</h3><select v-model.number="n"><option value="1">1</option><option value="2">2</option><option value="3">3</option></select>//<!-- <button @click="increment">+</button>//<button @click="decrement">-</button>//<button @click="incrementOdd">当前求和为奇数再加</button>//<button @click="incrementWait">等一等再加</button> -->//使用辅助函数的时候参数必须传过去<button @click="increment(n)">+</button><button @click="decrement(n)">-</button><button @click="incrementOdd(n)">当前求和为奇数再加</button><button @click="incrementWait(n)">等一等再加</button></div></template><script>import{mapState,mapGetters,mapMutations,mapActions}from'vuex'exportdefault{
		name:'Count',data(){return{
				n:1,//用户选择的数字}},
		computed:{//借助mapState生成计算属性,从state中读取数据。(数组写法)...mapState(['sum','school','subject']),//借助mapState生成计算属性,从state中读取数据。(对象写法)// ...mapState({he:'sum',xuexiao:'school',xueke:'subject'}),//借助mapGetters生成计算属性,从getters中读取数据。(数组写法)...mapGetters(['bigSum'])},
		methods:{//同步直接调用commit mutations...mapMutations({increment:'JIA',decrement:'JIAN'}),//借助mapMutations生成对应的方法,方法中会调用commit去联系mutations(数组写法)// ...mapMutations(['JIA','JIAN']),//这是上面就可以直接使用映射使用 mutations 中的方法//increment(){//同步直接调用commit mutations//	this.$store.commit('JIA',this.n)//},decrement(){//同步直接调用commit mutationsthis.$store.commit('JIAN',this.n)},//使用dispatch 调用actions// incrementOdd(){//	this.$store.dispatch('jiaOdd',this.n)// },//借助mapActions生成对应的方法,方法中会调用dispatch去联系actions(数组写法)// ...mapActions(['jiaOdd','jiaWait'])//这是上面就可以直接使用映射使用 actions 中的方法...mapActions({incrementOdd:'jiaOdd',incrementWait:'jiaWait'})// incrementWait(){//	this.$store.dispatch('jiaWait',this.n)// },},mounted(){
			console.log('Count',this)},}</script><style lang="css">
	button{
		margin-left:5px;}</style>

store中

/*
 * @Author: yzz
 * @Date: 2021-09-24 15:05:11
 * @LastEditors: Do not edit
 * @LastEditTime: 2021-09-26 14:02:40
 * @Description: Do not edit
 * @FilePath: \vue_test\src\store\index.js
 *///该文件用于创建Vuex中最为核心的storeimport Vuefrom'vue'//引入Vueximport Vuexfrom'vuex'//应用Vuex插件
Vue.use(Vuex)//准备actions——用于响应组件中的动作(异步)const actions={//同步直接调用commit mutations/* jia(context,value){
		console.log('actions中的jia被调用了')
		context.commit('JIA',value)
	},
	jian(context,value){
		console.log('actions中的jian被调用了')
		context.commit('JIAN',value)
	}, */// context(上下文对象)是小型的store 里面commitjiaOdd(context,value){
		console.log('actions中的jiaOdd被调用了')if(context.state.sum%2){
			context.commit('JIA',value)}},jiaWait(context,value){
		console.log('actions中的jiaWait被调用了')setTimeout(()=>{
			context.commit('JIA',value)},500)}}//准备mutations——用于操作数据(state)一般建议与actions分开,建议大写(mutations为同步 异步的话用actions触发)const mutations={JIA(state,value){
		console.log('mutations中的JIA被调用了')
		state.sum+= value},JIAN(state,value){
		console.log('mutations中的JIAN被调用了')
		state.sum-= value}}//准备state——用于存储数据const state={
	sum:0,//当前的和
	school:111,
	subject:'前端'}//准备getters——用于将state中的数据进行加工const getters={bigSum(state){return state.sum*10}}//创建并暴露storeexportdefaultnewVuex.Store({
	actions,
	mutations,
	state,
	getters})

modules:
公共状态数据模块化

     每一个小的模块都是一个小型的Vuex。小模块中也会有state  getter  mutations  actions
     
      当导出子模块的时候切记加一个namespaced:true作用是可以使当时模块的数据私有化

具体使用

//count.jsexportdefault{
	namespaced:true,
	actions:{jiaOdd(context,value){
			console.log('actions中的jiaOdd被调用了')if(context.state.sum%2){
				context.commit('JIA',value)}},jiaWait(context,value){
			console.log('actions中的jiaWait被调用了')setTimeout(()=>{
				context.commit('JIA',value)},500)}},
	mutations:{JIA(state,value){
			console.log('mutations中的JIA被调用了')
			state.sum+= value},JIAN(state,value){
			console.log('mutations中的JIAN被调用了')
			state.sum-= value},},
	state:{
		sum:0,//当前的和},
	getters:{bigSum(state){return state.sum*10}},}
//person.jsimport axiosfrom'axios'import{ nanoid}from'nanoid'exportdefault{
	namespaced:true,
	actions:{addPersonWang(context,value){if(value.name.indexOf('王')===0){
				context.commit('ADD_PERSON',value)}else{alert('添加的人必须姓王!')}},addPersonServer(context){
			axios.get('xxx').then(response=>{
					context.commit('ADD_PERSON',{id:nanoid(),name:response.data})},error=>{alert(error.message)})}},
	mutations:{ADD_PERSON(state,value){
			console.log('mutations中的ADD_PERSON被调用了')
			state.personList.unshift(value)}},
	state:{
		personList:[{id:'001',name:'张三'}]},
	getters:{firstPersonName(state){return state.personList[0].name}},}
//该文件用于创建Vuex中最为核心的storeimport Vuefrom'vue'//引入Vueximport Vuexfrom'vuex'import countOptionsfrom'./count'import personOptionsfrom'./person'//应用Vuex插件
Vue.use(Vuex)//创建并暴露storeexportdefaultnewVuex.Store({
	modules:{
		countAbout:countOptions,
		personAbout:personOptions}})

具体使用时

<template><div><h1>当前求和为:{{sum}}</h1><h3>当前求和放大10倍为:{{bigSum}}</h3><h3>我在{{school}},学习{{subject}}</h3><h3 style="color:red">Person组件的总人数是:{{personList.length}}</h3><select v-model.number="n"><option value="1">1</option><option value="2">2</option><option value="3">3</option></select><button @click="increment(n)">+</button><button @click
  • 作者:Are杨
  • 原文链接:https://blog.csdn.net/Ares0412/article/details/120482436
    更新时间:2022年6月12日10:28:33 ,共 8056 字。