vue 组件之间的通信

vue 组件之间通信的六种方式

1、props 和 $emit(子 触发 父)、ref(父 调用 子)
  • 父组件 给 子组件 数据传递,一般使用 props 关键字。
  • 子组件 给 父组件 传递数据,一般使用 $emit 方式触发 父组件 的事件;因为 子组件 是 不能直接修改 props 中的值(即 父组件 传递的值)的,若需要修改,则要通过触发 父组件 的事件,告知父组件进行修改。
  • 父组件 直接调用 子组件 的方法,可用 $refs 获取到子组件的实例,从而调用其方法。

示例代码如下:

// Parent.vue

<template>
	<div>
		<span>我是Parent组件</span>
		<Child ref="child" :parentValue="value" @emitEdit="edit"></Child>
	</div>
</template>
<script>
import Child from "./Child.vue";
export default {
	components: { Child },
	data() {
		return {
			value: "我是父组件"
		}
	},
    methods: {
        pFn() {
            console.log("我是父组件的方法");
            // 调用子组件的方法
            this.$refs.child.cFn();
		},
        // 子组件触发,修改 value 的值
        edit(msg) {
            this.value = msg;
		}
	}
}
</script>
// Child.vue

<template>
	<div>
		<span>我是Child组件</span>
		<span>父组件传的值:{{this.parentValue}}</span>
        <button @click="editParentValue">修改 parentValue</button>
	</div>
</template>
<script>
export default {
	props: {
		parentValue: String
	},
    methods: {
        cFn() {
            console.log("我是子组件的方法");
		}
        editParentValue() {
    		this.$emit("emitEdit", "子组件修改了我");
		}
	}
}
</script>
2、Event Bus(\(on、\)emit)
  • Event Bus(事件总线)方式主要用于无父子关系的组件之间传值,比如兄弟组件之间
  • 在 组件A 中使用 $on 注册监听事件,在 组件B 中使用 $emit 触发事件

示例代码如下:

// 新建一个vue实例,作为事件总线;可将其注册到全局或者vue的propotype上
vue.propotype.eventBus = new Vue();
// CompA.vue

<template>
	<div>
		<span>我是CompA组件</span>
        <span>value的值:{{ value }}</span>
	</div>
</template>
<script>
export default {
	data() {
		return {
			value: "我是CompA组件"
		}
	},
    mounted() {
		this.eventBus.$on("edit", (msg) => {
            this.value = msg;
		})
    }
}
</script>
// CompB.vue

<template>
	<div>
		<span>我是CompB组件</span>
        <button @click="editValue">修改 CompA 的value</button>
	</div>
</template>
<script>
export default {
    methods: {
        editValue() {
    		this.eventBus.$emit("edit", "CompB 修改了我");
		}
	}
}
</script>
疑问点:为什么不能使用 this.\(emit 和 this.\)on ,而要重新 new 一个空的 vue 实例?
3、provide 和 inject
  • provide 和 inject 方式通常用于祖孙组件之间的通信,主要用于祖先组件向子组件传值
  • provide 用于在 祖先组件 中定义可向子组件注入的属性或方法
  • inject 用于在 子组件 中注入属性和方法等依赖

示例代码:

// CompA.vue

<template>
	<div>
		<span>我是CompA组件</span>
        <span>value的值:{{ value }}</span>
        <!--其中,CompA组件不一定是CompB组件的直接父级,也可以是CompB组件的祖先组件,中间可以有多层的组件引用-->
        <CompB ref="compB"></CompB>
	</div>
</template>
<script>
import CompB from "./CompB.vue";
export default {
    components: { CompB },
	data() {
		return {
			value: "我是CompA组件"
		}
	},
    provide() {
        return {
            // 向外暴露这两个变量
            aValue: this.value,
            aFn: this.fn
        }
    },
    // 使用 Vue.observable() 可使provide传递的值变成响应式,即在祖先组件中修改之后,子组件中的值也会同步变化
    provide() {
        this.aData = Vue.observable({
            value: this.value,
            aFn: this.fn
        });
        return {
            aData: this.aData
        };
    },
    methods: {	
        fn() {
            console.log("我是 CompA 的方法");
		}
	}
}
</script>
// CompB.vue

<template>
	<div>
		<span>我是CompB组件</span>
        <button @click="aFn">调用 CompA 的fn</button>
	</div>
</template>
<script>
export default {
    // 注入依赖
    inject: ["aValue", "aFn"],
    mounted() {
        console.log("CompA 组件的 value", this.aValue);
	}
}
</script>
4、$parent 和 $children
  • $parent 和 $children 用于有 直接父子关系 的 组件 之间的通信
  • $parent 用于 获取组件的父组件实例
  • $parent 用于 获取组件的子组件实例
5、$attrs 和 $listeners
  • $attrs 和 $listeners 主要用于 获取 父组件 的属性和方法
  • $attrs 用于获取父组件中 没有在子组件的props中接收的属性
  • $listeners 用于获取父组件中的自定义事件
6、Vuex

Vuex 类似于一个仓库,可存放一些数据供全局调用,但是刷新页面就会消失,若需解决此问题,可选择将数据存储到 Vuex 的同时,将其存放到 sessionStorage 或者 localStorage 中即可。

Vuex 中包括 state、mutations、actions、getters、modules 几个部分。其中

  • state:定义变量
  • getters:获取state中变量的值
  • mutations:修改 state 中的值;使用 commit 触发;只能进行同步操作
  • actions:进行各种操作,可通过 dispatch 触发;可以进行异步操作
  • modules:项目较大时,可对变量的管理进行拆分,拆分成多个js文件,每个js文件作为单个的module,然后统一注册到 index.js 中,供全局调用

示例代码:

// module.js

const state = {
    modelCreateDataJsonStr: "",
    modelSelectDataJsonStr: "",
    modelClassDataJsonStr: ""
};
const getters = {
    getModelCreateDataJsonStr: state => {
        return state.modelCreateDataJsonStr;
    },
    getModelSelectDataJsonStr: state => {
        return state.modelSelectDataJsonStr;
    },
    getModelClassDataJsonStr: state => {
        return state.modelClassDataJsonStr;
    }
};
const mutations = {
    SET_MODEL_CREATE_DATA_JSON_STR(state, modelCreateDataJsonStr) {
        state.modelCreateDataJsonStr = modelCreateDataJsonStr;
    },
    SET_MODEL_SELECT_DATA_JSON_STR(state, modelSelectDataJsonStr) {
        state.modelSelectDataJsonStr = modelSelectDataJsonStr;
    },
    SET_MODEL_CLASS_DATA_JSON_STR(state, modelClassDataJsonStr) {
        state.modelClassDataJsonStr = modelClassDataJsonStr;
    }
};
const actions = {
    setModelCreateDataJsonStr({commit}, modelCreateDataJsonStr) {
        commit("SET_MODEL_CREATE_DATA_JSON_STR", modelCreateDataJsonStr);
    },
    setModelSelectDataJsonStr({commit}, modelSelectDataJsonStr) {
        commit("SET_MODEL_SELECT_DATA_JSON_STR", modelSelectDataJsonStr);
    },
    setModelClassDataJsonStr({commit}, modelClassDataJsonStr) {
        commit("SET_MODEL_CLASS_DATA_JSON_STR", modelClassDataJsonStr);
    }
};

// 暴露仓库
export { state, getters, mutations, actions };
// index.js

import Vue from 'vue';
import Vuex from 'vuex';

Vue.use(Vuex);

/**
 * 批量导入module下的所有模块
 * 如果module下面有自己新建的文件夹  文件夹里面的JS文件不能用index命名  容易冲突
 */
const path = require('path');
const files = require.context('./module', true, /\.js$/);
const modules = {};
files.keys().forEach(key => {
    const name = path.basename(key, '.js'); // 返回key的最后一部分
    modules[name] = files(key).default || files(key);
});

Vue.use(Vuex);
const store = new Vuex.Store({
    modules: modules,
});
export default store;
posted @ 2022-01-12 16:22  Upward123  阅读(370)  评论(0编辑  收藏  举报