vue中组件传值主要分为三种:父传子、子传父、兄弟组件传值、以及深层嵌套的组件之间的传值
父传子是通过props的方式传递
props可以是字符串数组和对象,用于接收来自父组件的数据
父组件中通过v-bind的方式传递数据
<title :msg="list"></title>
// 父组件中通过v-bind的方式传递数据
子组件通过props接收数据,props 可以是数组或对象,用于接收来自父组件的数据,props 可以是简单的数组,或者使用对象作为替代,对象允许配置高级选项,如类型检测、自定义验证和设置默认值。
// 数组方式
porps: ['msg']
// 对象方式可以进行数据的验证
props: {
msg: {
type: OBject, // 定义数据的类型,String、Number、Boolean、Array、Object、Date、Function、Symbol
require: true,// Boolean 定义该prop是否是必填项
default: {}, // any 为该prop定义一个默认值
validator: function() {} // Function 自定义验证函数会将porp的值作为唯一参数带入
}
}
-
props中声明的数据与组件data函数return的数据主要的区别就是props的数据来自父级,而data中的数据是组件自己的数据,作用域是组件本身。这两种数据斗可以在tempalet及计算属性computed和methods方法中使用。
-
如果在父组件中传递数据时不使用v-bind绑定传递数据,传递到子组件的数据就仅仅是一个字符串
// 父组件 <title msg="{ name: 小明 }" /> // 子组件 <template> <div>{{ msg.length }}<div> // 输出的msg长度为14(加上左右的空格), <template/> props: ['msg']
-
vue 2.x 中通过props传递的数据是单向向下的,就是说父组件中的数据变化可以影响子组件中的数据变化,但子组件却不能影响父组件。vue 1.x中提供了.sync的修饰符来支持双向绑定。
-
一般修改prop的情况有两种:一种子组件把父组件传递过来的初始值作为局部数据使用(子组件data中声明一个数据来引用父组件中传递的prop),另一种就是prop作为传入后,有子组件处理成其他数据输出(使用计算属性处理)当prop是数组和对象时,在子组件中改变是会影响父组件的
子传父使用自定义事件进行传递
v-on指令除了监听DOM事件外,还可以用于组件之间的自定义事件。vue允许在子组件用 e m i t ( ) 来 触 发 事 件 , 父 组 件 用 emit()来触发事件,父组件用 emit()来触发事件,父组件用on()来监听子组件的事件
// 子组件
<button @click="addNum">加</button>
data() {
return: {
childNum: 0
}
},
methods: {
addNum() {
this.num ++;
this.$emit('addNum', this.childNum) // 第一个参数自定义事件的名字,第二个参数是想要传递的参数
}
}
//父组件
<div @addNum="getNum">{{ parentNum }}</div>
data() {
return: {
parentNum: 0
}
}
methods: {
getNum(num) {
this.parentNum = num
}
}
vue 2.x还可以在自定义子组件上使用v-model来实现数据的传递
<div id='app'>
<p>{{ parentNum }}</p>
<child v-model="parentNum"/>
</div>
<script>
Vue.component{'child', {
template: '<button @click="addNum">加</button>',
data() {
return: {
num: 0
}
},
methods: {
addNum() {
this.num ++
this.$emit('input', this.num)
}
}
}};
var app = new Vue({
el: '#app',
data: {
parentNum
}
})
</script>
实现这样具有双向绑定的v-model组件要满足两个条件:接收一个value属性;在有新的value时触发input事件
非父子组件间传值
非父子组件一般有兄弟传值和跨多级组件。在vue 1.x中除了 e m i t ( ) 方 法 外 , 还 提 供 有 emit()方法外,还提供有 emit()方法外,还提供有dispatch()和 b r o a d d c a s t ( ) 这 两 个 方 法 。 broaddcast()这两个方法。 broaddcast()这两个方法。dispatch()用于向上级派发事件,只要是它的父级都可以用Vue实例中events选项接收,$broadcast()与其相反。这两种方法在Vue 2.x中已废除
在Vue.js 2.x中,推荐使用使用一个空的Vue实例作为中央事件总线(bus),用它来触发事件和监听事件,巧妙而轻量的实现任何组件间的通信,包括父子、兄弟 、跨级。当我们项目较大时,也可以选择更好的状态管理工具Vuex,下面主要说使用bus的实现
let eventBus = new Vue()
eventBus.$emit('事件名', 数据)
eventBus.$on('事件名', data => {})
例:
<div id="app">
<my-a></my-a>
<my-b></my-b>
<my-c></my-c>
</div>
<template id="a">
<div>
<h3>A组件:{{name}}</h3>
<button @click="send">将数据发送给C组件</button>
</div>
</template>
<template id="b">
<div>
<h3>B组件:{{age}}</h3>
<button @click="send">将数组发送给C组件</button>
</div>
</template>
<template id="c">
<div>
<h3>C组件:{{name}},{{age}}</h3>
</div>
</template>
var EventBus = new Vue();//定义一个空的Vue实例
var A = {
template: '#a',
data() {
return {
name: 'tom'
}
},
methods: {
send() {
EventBus.$emit('data-a', this.name);
}
}
}
var B = {
template: '#b',
data() {
return {
age: 20
}
},
methods: {
send() {
EventBus.$emit('data-b', this.age);
}
}
}
var C = {
template: '#c',
data() {
return {
name: '',
age: ""
}
},
mounted() {//在模板编译完成后执行
EventBus.$on('data-a',name => {
this.name = name;//箭头函数内部不会产生新的this,这边如果不用=>,this指代Event
})
Event.$on('data-b',age => {
this.age = age;
})
}
}
var vm = new Vue({
el: '#itany',
components: {
'my-a': A,
'my-b': B,
'my-c': C
}
});
</script>
除了中央事件总线bus外,还有两种方法实现组件通信:父链和组件索引
父链:在子组件中使用this. p a r e n t 可 以 直 接 访 问 该 组 件 的 父 例 或 组 件 , 父 组 件 也 可 以 通 过 t h i s . parent可以直接访问该组件的父例或组件,父组件也可以通过this. parent可以直接访问该组件的父例或组件,父组件也可以通过this.children访问它所有的子组件,而且可以递归向上或向下无限访问,直到跟实例或最内层的组件
<div id="app">
{{ message }}
<component-a></component-a>
</div>
<script>
Vue.component('component-a', {
template: '<button @click="handleEvent">通过父链直接修改数据</button>'
methods: {
handleEvent() {
// 访问父链后,可以做任何操作,比如直接修改数据
this.$parent.message = '来自组件component-a的内容'
}
}
})
var app = new Vue({
el: '#app',
data: {
message: ''
}
})
</script>
// 尽管Vue允许这样操作,但业务中,子组件应该尽可能地避免依赖父组件的数据,更不该主动修改它的数据
子组件索引
当子组件较多时,通过this.$children来一一遍历我们需要的组件实例是比较困难的,Vue提供了组件索引的方法,用特殊的属性ref来为组件指定索引名称(Vue 2.x将v-el和v-ref合并为了ref)
<div id="app">
<button @click="handleRef">通过ref获取子组件实例</button>
<component-a ref="comA"></component-a>
</div>
<script>
Vue.component('component-a', {
template: '<div>子组件</div>',
data() {
return {
message: '子组件内容'
}
})
</script>
var app = new Vue({
el: '#app',
methods: {
handleRef() {
var msg = this.$refs.comA.message
console.log(msg)
}
}
})