VUE——组件通信

组件间的通信一般有以下几种形式:
在这里插入图片描述

一、ref

ref: 给元素或组件注册引用信息

用ref访问组件实例:

//子组件component-a
export default{	
	data(){
		return{
			title: 'hello ref'
		}
	},
	methods:{
		sayHello(){
			window.alert('world');
		}
	}
}
//父组件
<template>
  <component-a ref = "comA"></component-a>
</template>

<script>
  export default{
    mounted(){
		const comA = this.$refs.comA;
		console.log(comA.title);
		comA.sayHello();
	}
 }
</script>
二、$parent/$children

1、$children 获取子组件数据和调用子组件方法

//父组件
<template>
  <component-a></component-a>
</template>

<script>
  export default{
       methods:{
            do() {
               this.$children[0].sayHello()    // 调用子组件方法   $children获取的是父组件的直接子组件数组,不获取孙组件
               this.$children[0].title= 'hello'  // 改变子组件数据
            }
        }
</script>

2、$parent 获取父组件数据和调用父组件方法

//子组件component-a
export default{	
	data(){
		return{
			title: 'hello ref'
		}
	},
	methods:{
		sayHello(){
			window.alert('world');
		},
		show(){
			this.$parent.do() //获取直属父组件
		}
	}
}
三、props

1、prop属性
prop定义了组件中可配置的属性。props最好用对象的写法,这样可以针对每个属性设置类型、默认值或自定义校验属性的值。

//子组件<i-button>
<template>
  <button :class="'i-button-size' + size" :disabled="disabled"></button>
</template>

<script>
  export default{
    props:{
    	size:{
    	  default: 'default'
		},
		disabled:{
			type: Boolean,
			default: false
		}
	}
  }
</script>
//父组件
<template>
  <i-button size="large"></i-button>
    <i-button disabled = true></i-button>
</template>

2、html特性参数
使用组件时,也可以传入一些标准的html特性,比如id、class:

<i-button id="btn" class = "btn-submit"> </i-button>

HTML特性在组件内的<button>元素上会继承,并不需要在props中定义。

注意:
组件中定义的props都是单向数据流,只能通过父组件修改。

四、插槽slot

给子组件i-button添加一些文字内容:

//子组件<i-button>
<template>
  <button :disabled="disabled">
	<slot></slot>
  </button>
</template>
//父组件
<template>
   <i-button>
		<strong>按钮</strong>
   </i-button>
</template>

当需要多个插槽时,需要用到具名slot,比如再设置一个图标组件:

//子组件<i-button>
<template>
  <button :disabled="disabled">
    <slot name="icon"></slot>
	<slot></slot>
  </button>
</template>
//父组件
<template>
   <i-button>
   		<i-icon slot="icon" type = "checkmark"></i-icon>
		<strong>按钮</strong>
   </i-button>
</template>

注意:
在slot中也可以定义一些默认的内容,当父组件没有写任何内容时就会出现:

<slot> 默认内容 </slot>

参考文章:
[1] VUE-插槽slot

五、自定义事件event

通过$emit可以在子组件中自定义事件on-click,在父组件中通过@on-click来监听。

//子组件<i-button>
<template>
  <button @click="handleClick"></button>
</template>

<script>
  export default{
   methods:{
   handleClick(event){
		this.$emit('on-click',event);
	}
   }
  }
</script>
//父组件
<i-button @on-click="handleClick"></i-button>
六、provide/inject

1、基本用法
在父组件中通过provide将变量name提供给所有的子组件。

//父组件
export default{
	provide:{
		name: 'Aresn'
	}
  }

在子组件中通过inject注入name变量,便可以直接使用this.name访问这个变量了。

//子组件
export default{
	inject: ['name'],
	mounted(){
		console.log(this.name);
	}
  }

注意:
provide和indect绑定不是可响应的,即父组件的name发生了变更,子组件中并不会变。

2、使用provide/inject代替Vuex

(1)基本用法

Vue通常会导入一个入口组件app.vue作为根组件。我们可以将app.vue用来存储所有需要的全局数据和状态,甚至是计算属性、方法等。因为项目中的所有组件的父组件都是app.vue,所以我们可以将app.vue实例,通过provide对外提供。

<template>
    <div id="app">
        <router-view/>
    </div>
</template>
<script>
    export default {
		provide(){
			return{
				app: this
			}
		}
    }
</script>

接下来,任何组件通过inject注入app.vue的app,都可以直接通过this.app.xxx来访问app.vue的data、computed、methods等内容。

注意:
app.vue是整个项目第一个被渲染的组件,而且只会渲染一次,利用这个特性可以做一次性全局的状态数据管理。

(2)进阶用法——引入混合mixins

当项目比较复杂时,app.vue中的代码就会变得结构复杂难以维护。这时可以使用Vue.js的混合mixins,将不同的逻辑分到不同的js文件中。

//user.js
 export default {
	data(){
		return{
			userInfo:null
		}
	},
	methods:{
		getUserInfo(){
			this.userInfo = 'hello';
		}
	}
    }

引入混合

//user.js
<script>
 import mixins_user from './mixins/user.js'
 export default {
 	mixins: [mixins_user],
	data(){
		return{
		}
	}
    }
</script>
七、自定义dispatch和broadcast方法

Vue.js 2.x中已经废弃的方法dispatch和broadcast方法。
dispatch: 用于向上级派发事件,它的父级(一级或多级)都可以通过$on监听到 。
broadcast: 用于从上级向下级广播事件。

示例:dispatch

//子组件
<template>
  <button @click="handleClick"></button>
</template>

<script>
  export default{
   methods:{
   handleClick(event){
		this.$dispatch('on-click','hello');
	}
   }
  }
</script>
//父组件
  export default{
   mounted(){
		this.$on('on-click',(text)=>{
			console.log(text);
		})
   }
  }

想要在Vue2.x 以上版本使用dispatch和broadcast方法需要自己实现:
在这里插入图片描述

//emitter.js
function broadcast(componentName, eventName, params) {
    this.$children.forEach(child => {
        const name = child.$options.name;

        if (name === componentName) {
            child.$emit.apply(child, [eventName].concat(params));
        } else {
            broadcast.apply(child, [componentName, eventName].concat([params]));
        }
    });
}
export default {
    methods: {
        dispatch(componentName, eventName, params) {
            let parent = this.$parent || this.$root;
            let name = parent.$options.name;

            while (parent && (!name || name !== componentName)) {
                parent = parent.$parent;

                if (parent) {
                    name = parent.$options.name;
                }
            }
            if (parent) {
                parent.$emit.apply(parent, [eventName].concat(params));
            }
        },
        broadcast(componentName, eventName, params) {
            broadcast.call(this, componentName, eventName, params);
        }
    }
};

使用:

//componentA
<template>
  <button @click="handleClick"></button>
</template>

<script>
  import Emitter from './mixins/emitter.js';
  export default{
   name: 'componentA',
   mixins: [Emitter],
   methods:{
   handleClick(){
		this.$broadcast('componentB','on-message','Hello ComB');
	}
   }
  }
</script>
//componentB
 export default{
   name: 'componentB',
   created(){
		this.$on('on-message',this.showMessage);
	}
   methods:{
     showMessage(text){
		window.alert(text);
	}
   }

参数说明:
broadcast(componentName, eventName, params)

  • componentName: 组件名
  • eventName:事件名
  • params:只能传一个参数,多参数可通过对象的形式传递。

来源:《Vue.js组件精讲》

八、找到任意组件实例
//assist.js
// 由一个组件,向上找到最近的指定组件
function findComponentUpward (context, componentName) {
    let parent = context.$parent;
    let name = parent.$options.name;

    while (parent && (!name || [componentName].indexOf(name) < 0)) {
        parent = parent.$parent;
        if (parent) name = parent.$options.name;
    }
    return parent;
}
export { findComponentUpward };

// 由一个组件,向上找到所有的指定组件
function findComponentsUpward (context, componentName) {
    let parents = [];
    const parent = context.$parent;

    if (parent) {
        if (parent.$options.name === componentName) parents.push(parent);
        return parents.concat(findComponentsUpward(parent, componentName));
    } else {
        return [];
    }
}
export { findComponentsUpward };

// 由一个组件,向下找到最近的指定组件
function findComponentDownward (context, componentName) {
    const childrens = context.$children;
    let children = null;

    if (childrens.length) {
        for (const child of childrens) {
            const name = child.$options.name;

            if (name === componentName) {
                children = child;
                break;
            } else {
                children = findComponentDownward(child, componentName);
                if (children) break;
            }
        }
    }
    return children;
}
export { findComponentDownward };

// 由一个组件,向下找到所有指定的组件
function findComponentsDownward (context, componentName) {
    return context.$children.reduce((components, child) => {
        if (child.$options.name === componentName) components.push(child);
        const foundChilds = findComponentsDownward(child, componentName);
        return components.concat(foundChilds);
    }, []);
}
export { findComponentsDownward };

// 由一个组件,找到指定组件的兄弟组件
function findBrothersComponents (context, componentName, exceptMe = true) {
    let res = context.$parent.$children.filter(item => {
        return item.$options.name === componentName;
    });
    let index = res.findIndex(item => item._uid === context._uid);
    if (exceptMe) res.splice(index, 1);
    return res;
}
export { findBrothersComponents };

function typeOf(obj) {
    const toString = Object.prototype.toString;
    const map = {
        '[object Boolean]'  : 'boolean',
        '[object Number]'   : 'number',
        '[object String]'   : 'string',
        '[object Function]' : 'function',
        '[object Array]'    : 'array',
        '[object Date]'     : 'date',
        '[object RegExp]'   : 'regExp',
        '[object Undefined]': 'undefined',
        '[object Null]'     : 'null',
        '[object Object]'   : 'object'
    };
    return map[toString.call(obj)];
}
// deepCopy
function deepCopy(data) {
    const t = typeOf(data);
    let o;

    if (t === 'array') {
        o = [];
    } else if ( t === 'object') {
        o = {};
    } else {
        return data;
    }

    if (t === 'array') {
        for (let i = 0; i < data.length; i++) {
            o.push(deepCopy(data[i]));
        }
    } else if ( t === 'object') {
        for (let i in data) {
            o[i] = deepCopy(data[i]);
        }
    }
    return o;
}

export {deepCopy};

使用:

<script>
	import {findComponentUpward} from '../utils/assist.js';

	export default{
		name: 'comPonentB';
		mounted(){
			const comA = findComponentUpward(this,'componentA');
		}
	}
</script>

参数说明:
this: 当前组件的上下文实例
‘componentA’: 要找的组件实例名

来源:《Vue.js组件精讲》

九、VUEX

Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。

链接:Vuex文档

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值