目录
(1)父传子:子组件实例上用v-bind绑定父组件数据,在组件上用props接收
(2) 子传父:子组件通过$emit传参数,父组件v-on绑定事件
一.父子通信(props, $emit)
(1)父传子:子组件实例上用v-bind绑定父组件数据,在组件上用props接收
<div id="app">
<!-- 实例用v-bind绑定父组件数据name -->
<cpn :name="name"></cpn>
</div>
<template id="cpn">
<div>
得到name:{{name}}
</div>
</template>
const cpn = {
template: '#cpn',
// props得到父组件传来的数据
props: {
name: {
type: String,
default() {
return ""
}
}
}
}
const app = new Vue({
el: '#app',
components: {
cpn
},
data: {
name: "kevin",
}
})
(2) 子传父:子组件通过$emit传参数,父组件v-on绑定事件
<div id="app">
<!-- 事件形式接收参数 -->
<cpn @increment="cpnClick"/>
</div>
<template id="cpn">
<div>
<button @click="increment">+</button>
</div>
</template>
const cpn = {
template: '#cpn',
data() {
return {
count: 0
}
},
methods: {
increment() {
this.count++
this.$emit('increment', this.count) // 传出自定义事件increment,参数 this.count
}
}
}
const app = new Vue({
el: '#app',
components: {
cpn
},
methods: {
//实现点击一下 父组件就能得到子组件的 count值
cpnClick(count) {
console.log(count);
}
}
})
二.$attrs 和 $listerens
这个用于跨级通信,个人感觉跟父子传参挺类似的,不过它可以让它的后代得到自己的数据,也能得到后代传过来的数据
这里我写了四个嵌套组件(father,childOne,childTwo,childThree)
(1)祖先传给后代($attrs)
像父传子那样,先传给子组件(childOne, 代码一),在子组件childOne的模板上props 想要的数据(代码二)
下面的组件想拿到父组件(father)数据的话,在它们的实例上 写一个 v-bind="$attrs" ,在props上写想要的数据
如果一个组件props拿到了想要的数据,它的后代组件就没有这个 数据了!!!
如下图: childOne 得到name后, 传给后代的数据中就没有name了
(2)后代传给祖先($listerens)
后代组件如果有数据需要传给祖先的话,跟父传子一样用 $emit (代码三,四),同样的在祖先组件用 v-on 得到数据(代码一),结果入下图
// father
<template>
<div>
<child-one :name="name"
:age="age"
:height="height"
:like="like"
@test1="test1"
@test2="test2" />
</div>
</template>
<script>
import childOne from './childOne.vue'
export default {
components: { childOne },
name: 'father',
data() {
return {
name: 'chandler',
age: 20,
height: 180,
like: 'play'
}
},
methods: {
test1(name) {
console.log(name);
},
test2(name) {
console.log(name);
}
}
}
</script>
// childOne
<template>
<div>
<h2>childOne:</h2>
<p>name: {{name}}</p>
<p>one: {{$attrs}}</p>
<child-two v-bind="$attrs"
v-on="$listeners"/>
</div>
</template>
<script>
import childTwo from './childTwo.vue'
export default {
components: { childTwo },
name: 'childOne',
props: {
name: String
},
created() {
console.log(this.$attrs);
console.log(this.$listeners);
}
}
</script>
// childTwo
<template>
<div>
<h2>childTwo:</h2>
<p>age: {{age}}</p>
<p>two: {{$attrs}}</p>
<child-three v-bind="$attrs"
v-on="$listeners"/>
</div>
</template>
<script>
import childThree from './childThree.vue'
export default {
components: { childThree },
name: 'childTwo',
props: {
age: Number
},
data() {
return {
name: "2222"
}
},
mounted() {
this.$emit("test1", this.name);
}
}
</script>
// childThree
<template>
<div>
<h2>childThree:</h2>
<p>three: {{$attrs}}</p>
</div>
</template>
<script>
export default {
name: 'childThree',
props: {
height: Number,
like: String
},
data() {
return {
name: "3333"
}
},
mounted() {
this.$emit("test2", this.name);
}
}
</script>
三.provide 和inject
这个方法主要用于祖先组件传给后代组件传值,provide 里面放的就是给后代值,后代用 inject就可以拿到(不是响应式,如果祖先改变传过来的参数的话,后代不会改变)
下面的代码会得到以下图片
点击 按钮改变名字后,可以看到祖先组件的name 改变了,但后代的name不会改变
// father
<template>
<div>
<button @click="changeName">改变名字</button>
<child-one/>
</div>
</template>
<script>
import childOne from './childOne.vue'
export default {
components: { childOne },
name: 'father',
data() {
return {
name: "chandler",
age: 20
}
},
provide() {
return {
name: this.name,
age: this.age
}
},
methods: {
changeName() {
this.name = "kevin"
}
}
}
</script>
//childOne
<template>
<div>
<h2>childOne:</h2>
<p>name: {{name}}</p>
<child-two/>
</div>
</template>
<script>
import childTwo from './childTwo.vue'
export default {
components: { childTwo },
name: 'childOne',
inject: ['name']
}
</script>
// childTwo
<template>
<div>
<h2>childTwo:</h2>
<p>age: {{age}}</p>
</div>
</template>
<script>
export default {
name: 'childTwo',
inject: ['age']
}
</script>
四.&refs ,$parent ,$children
这个方法差不多也是 父子通信
(1)$refs
就是给子组件做标记 <child-one ref="one" /> (代码一)
在父组件中 通过 this.$ref.one 就可以访问这个子组件(数据,方法都可)
(2) $children
children 是你子组件的一个集合,如果知道子组件的顺序的话,可以通过 this.$children[下标] 来访问子组件 (代码一)
(3) $parent
子组件 可以通过 this.$parent 来访问父组件 (代码二)
// father
<template>
<div>
<child-one ref="one" />
<child-two ref="two" />
<button @click='getChild'>得到子组件message</button>
</div>
</template>
<script>
import childOne from './childOne.vue'
import ChildTwo from './childTwo.vue'
export default {
components: { childOne, ChildTwo },
name: 'father',
data () {
return { message: '这是父组件中的内容' }
},
methods: {
getChild () {
//children方式访问自组件
for (let i = 0; i < this.$children.length; i++) {
console.log(this.$children[i].message);
}
console.log(this.$refs.one.message);
console.log(this.$refs.two.message);
},
},
}
</script>
// childOne
<template>
<div>
<h2>childOne:</h2>
<button @click='getParent'>得到父组件message</button>
</div>
</template>
<script>
export default {
name: 'childOne',
data () {
return { message: '这是第一个子组件' }
},
methods: {
getParent () {
console.log(this.$parent.message);
}
},
}
</script>
//childTwo
<template>
<div>
<h2>childTwo:</h2>
</div>
</template>
<script>
export default {
name: 'childTwo',
data () {
return { message: "这是第二个组件" };
}
}
</script>
得到下图:
点击第一个按钮得到 :
点击第二个按钮得到(分别用 $refs 和 $parent 各得到一次):
五. bus
这个方法不管组件之间是什么关系都可以 通信
大概思路创建一个空的vue实例作为事件总线,通过它实现组件的通信
首先创建一个bus.js 文件
import Vue from 'vue'
const Bus = new Vue()
export default Bus
传出的话 用$emit (代码一) 接收用 $on (代码三),用到bus的时候要导入!!
// father
<template>
<div>
<child-one />
<button @click="btnClick">传message</button>
</div>
</template>
<script>
import Bus from '@/bus.js' // 导入
import childOne from './childOne.vue'
export default {
components: { childOne },
name: 'father',
data () {
return { message: '这是父组件中的内容' }
},
methods: {
btnClick () {
Bus.$emit('btnClick', this.message)
}
}
}
</script>
// childOne
<template>
<div>
<h2>childOne:</h2>
<child-two />
</div>
</template>
<script>
import childTwo from './childTwo.vue';
export default {
components: { childTwo },
name: 'childOne',
data () {
return { message: '这是第一个子组件' }
},
}
</script>
// childTwo
<template>
<div>
<h2>childTwo:</h2>
</div>
</template>
<script>
import Bus from '@/bus.js' // 导入
export default {
name: 'childTwo',
data () {
return { message: "这是第二个组件" };
},
mounted () {
Bus.$on('btnClick', val => {
console.log(val);
})
}
}
</script>
六.vuex
vuex设计的东西比较多了,推荐一篇文章,讲的很详细,点击