几种方式:
- props emit
- provide inject (依赖注入)
- this.$root this.$parent this.$refs(节点访问)
- eventbus 事件触发器
1、props emit
这种传值分为两种方式,父组件→子组件; 子组件→父组件; (🧔👱♂️:和我们两个有关系嗷)
💢💥这种方式的缺点:如果组件嵌套层次多的话,数据传递比较繁琐
props 为父组件向子组件传递,emit事件则是子组件向父组件传递👇
父🧔→子👱♂️
父组件给子组件传递值通过props。根节点vm>compa>compb
<div id="app">
<compa :myname="name">
<!--接收根节点的值-->
</div>
<script>
//子组件
const compb = {
props: ['hername'],//负责接收父组件的属性
template: '<h1>{{hername}}</h1>',
}
//父组件
const compa = {
props: ['myname'],//这里父组件的props是用来接收根节点的值的
template:
`<div>
<h1>{{myname}}</h1>
<compb :hername=myname></compb>
</div>
`,
components: {
compb
}
}
var vm = new Vue({
el: "#app",
data: {
name: "魅族牛逼"
},
components: {
compa
}
})
</script>
具体传值看图👇得出props就是为了获得父组件的值。
所以可以两个组件均可以打印出根节点的内容
子👱♂️→父🧔
子组件通过emit发送事件,父组件通过v-on(@)来接收事件,再进行改变。
在子组件的文本框中输入文本,可以改变根节点的属性,并显示。
<div id="app">
{{username}}
<custom-input @ischange='handlerchange'></custom-input>
<!--监听子组件的ischange事件 触发执行handlerchange回调函数-->
</div>
<script>
//子组件,文本框添加change事件,一旦文本内容被修改,则抛发 ischange 事件
Vue.component('custom-input', {
template:
`
<div>
<input type="text" @change="$emit('ischange',$event.target.value)"/>
</div>
`,
})
var vm = new Vue({
el: "#app",
data: {
username: ''
},
methods: {
handlerchange(val) {//事件处理函数,将data的值改为传来的值
this.username = val;
}
}
})
</script>
在文本框内输入则会在上方生成文本框内容,
换个写法(sync)✔
上面的 子👱♂️→父🧔 可以换个写法:
在有些情况下,我们可能需要对一个 prop 进行“双向绑定”。不幸的是,真正的双向绑定会带来维护上的问题,因为子组件可以修改父组件,且在父组件和子组件都没有明显的改动来源。
这也是为什么推荐以 update:myPropName 的模式触发事件来取而代之。为了方便起见,我们为这种模式提供一个缩写,即 .sync修饰符:
- 接收:
@ischange='handlerchange'
→:myusername.sync="username
直接跟属性名无需回调函数 - 抛发:
@change="$emit('ischange',$event.target.value)"
→@change="$emit('update:myusername',$event.target.value)"
<div id="app">
{{username}}
<custom-input-sync :myusername.sync="username"></custom-input-sync>
</div>
<script>
Vue.component('custom-input-sync', {
template:
`
<div>
<input type="text" @change="$emit('update:myusername',$event.target.value)"/>
</div>
`,
})
var vm = new Vue({
el: "#app",
data: {
username: ''
},
})
</script>
2、provide inject (依赖注入)
官网讲解:看我的也可以,可以不用点我嗷亲😁
- provide :写在祖先组件中,包含可注入其子孙的属性 provide:
Object | () => Object
- inject: 写在子孙组件中,用来接收祖先中传来的属性:inject:
Array<string> | { [key: string]: string | Symbol | Object }
,后跟一个字符串数组或者一个对象。
这对选项需要一起使用,以允许一个祖先组件向其所有子孙后代注入一个依赖,不论组件层次有多深,并在起上下游关系成立的时间里始终生效。provide 和 inject 主要在开发高阶插件/组件库时使用。并不推荐用于普通应用程序代码中。
👇该例子嵌套两层,并不影响使用,使用与嵌套层数无关
<div id="app">
<compa :myname="name">
</div>
<script>
const compb = {
inject: ['username'],//接收provide的属性
template: '<h1>!!!看看老子👉{{username}}</h1>',
}
const compa = {
template:
`<div>
<compb></compb>
</div>
`,
components: {
compb
}
}
var vm = new Vue({
el: "#app",
data: {
name: "张三"
},
components: {
compa
},
provide: function () {
return {
username: this.name//存放需要传递的属性
}
}
})
</script>
轻松获得受气包——张三同志
💢💥这种方式的缺点:provide 和 inject 绑定并不是可响应的。
$root | $parent | $children | ref
- $root : 当前组件树的根 Vue 实例。如果当前实例没有父实例,此实例将会是其自己。
- $parent: 父实例,如果当前实例有的话
- $children: 当前实例的直接子组件。需要注意 $children 并不保证顺序,也不是响应式的。如果你发现自己正在尝试使用 $children 来进行数据绑定,考虑使用一个数组配合 v-for 来生成子组件,并且使用 Array 作为真正的来源。
- ref: 被用来给元素或子组件注册引用信息。引用信息将会注册在父组件的 $refs 对象上。如果在普通的 DOM 元素上使用,引用指向的就是 DOM 元素;如果用在子组件上,引用就指向组件实例
<div id="app">
<input type="text" ref="father" :value="name">
<!-- ref设为father,方便通过$refs.father来调用 -->
<compa :myname="name">
</div>
<script>
const compb = {
template: '<h1>"看看老子"-{{$root.name}}</h1>',
//可以直接通过$root来访问根节点name属性
data() {
return {
title: "我是儿子的属性"
}
},
mounted() {
console.log("compb:" + this.$root.name)//compb:张三
//获得根节点的name属性
console.log("compb:" + this.$parent.title)//compb:我是爸爸的属性
//获得父组件的title属性
console.log("compb:" + this.$parent.starts())//compb:我是爸爸的方法
//执行父组件的starts方法
}
}
const compa = {
props: ['myname'],
template://下面子组件设置ref为son,方便通过$refs.son来调用
`<div>
<h1>{{myname}}</h1>
<compb ref="son"></compb>
</div>
`,
components: {
compb
},
data() {
return {
title: "我是爸爸的属性"
}
},
methods: {
starts() {
return '我是爸爸的方法'
}
},
mounted() {
console.log("compa:" + this.$refs.son.title)//compa:我是儿子的属性
//父组件通过$refs.son访问dom获取title属性
console.log("compa:" + this.$children[0].title)//compa:我是儿子的属性
//父组件通过$children来获取子组件属性
}
}
var vm = new Vue({
el: "#app",
data: {
name: "张三"
},
components: {
compa
},
mounted() {
console.log("root:" + this.$refs.father.value)//root:张三
//根节点通过$refs.father来访问dom获取文本框的value值
}
})
</script>
3、Eventbus 🚌
EventBus 又称为事件总线。在Vue中可以使用 EventBus 来作为沟通桥梁的概念,就像是所有组件共用相同的事件中心,可以向该中心注册发送事件或接收事件,所以组件都可以上下平行地通知其他组件,但也就是太方便所以若使用不慎,就会造成难以维护的“灾难”,因此才需要更完善的Vuex作为状态管理中心,将通知的概念上升到共享状态层次。
💢💥这种方式的缺点:不支持响应式。
案例👇:点击按钮,将根节点的属性,传递到子组件的eventbus中,并打印
<div id="app">
<compa>
<button @click="handlerclick">send</button>
</compa>
</div>
<script>
var eventbus = new Vue();//定义eventbus
const compb = {
template: '<h1>compb</h1>',
mounted() {
eventbus.$on('message', function (msg) {
//event.on用来监听
console.log(msg);
})
}
}
const compa = {
template:
`<div>
<slot></slot>
<h1>compa</h1>
<compb></compb>
</div>
`,
components: {
compb
}
}
var vm = new Vue({
el: "#app",
data: {
name: "xiaoxue"
},
components: {
compa
},
methods: {
handlerclick() {
eventbus.$emit('message', '我是数据')
//eventbus.$emit抛发事件
}
}
})
</script>
最后
其实还有个vuex,那玩意也是可以用来组件之间传递数据的,而且很香,详细请移步:😈莫挨老子😈