VUE——组件通信
Posted 长不大的大灰狼
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了VUE——组件通信相关的知识,希望对你有一定的参考价值。
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>
五、自定义事件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(以上是关于VUE——组件通信的主要内容,如果未能解决你的问题,请参考以下文章