反向传值
-
即子代向父传值
-
语法:$emit
-
$emit的第一个参数来自定义的事件,第二个参数为要传递给父组件的值,父组件在子组件标签上绑定自定义事件来接收子组件传递的数据
-
父组件中使用子组件时,在子组件身上绑定一个自己的更新事件
<Box :data="value" @myevent="myevent1"></Box>
//补充一种语法糖写法 注意这里的v-model的底层代码对应的是input方法,在使用其他方式的不要使用该语法糖 <Box V-model="value"></Box> //这里相当于 <Box @input="input" :value="value"></Box>
-
在父组件中定义这个事件
myevent1:function(value){//这个函数被定义在父组件种,将会在子组件中被触发,其中value参数表示子组件更新后的值 this.value = value }
-
子组件中首先通过props接收父组件传过来的值
props:{ data:{ type:String, default:'' } }
-
子组件在更新这个值的函数里,同时通过this.$emit触发父组件的myevent事件
methods:{ change(){ this.$emit("父组件中的@事件类型名","新的值") } }
-
这里给出一个简单的完整示例 该示例由App.vue Box.vue两个文件组成
- App.vue代码
<template> <div id="app"> <Box :msg="msg" @mychange="change"></Box> </div> </template> <script> import Box from "./Box.vue" export default { data() { return { msg:"父组件中的msg" } }, components:{ Box }, methods: { change(arg){ this.msg = arg } } }; </script> <style lang="scss"> </style>
- Box.vue代码
<template> <div> <h1>Box----{{msg}}</h1> <button @click="change">点击修改app中的msg值</button> </div> </template> <script> export default { props:["msg"], methods: { change(){ this.$emit("mychange","Box通过反向传值修改到了app里的值") } } } </script> <style lang=""> </style>
-
-
补充一点
-
如果想给组件绑定原生事件
-
方法:给事件绑定事件修饰符 .native 拿上面完整的示例中的代码举例
<Box :msg="msg" @click.native="change"></Box>
-
-
子组件直接修改父组件中的数据
-
前面提到的子组件修改父组件的方法,都是通过函数传值到父组件,在通过父组件的函数对父组件的数据进行修改,这里给出一种子组件可以直接修改到父组件的方法
-
语法:.sync修饰符 这是一种语法糖的写法
-
同样使用前面完整的示例中的代码举例
-
App.vue中当我们加上.sync修饰符后,可以省略掉App.vue中的change方法
<Box :msg.native="msg" ></Box>
-
Box.vue中不改变
-
-
多层组件传值
-
l i s t e n e r s / listeners/ listeners/attrs
-
其中$listeners负责事件传递
-
$attrs负责属性传递,接收非props属性的值 包含了父作用域不作为prop被识别(且获取)的特性绑定(class和style除外)
-
这里简单举例 假设我们有三层传递 这里仅给出中间层代码 其中被注释的部分为不引用 l i s t e n e r s / listeners/ listeners/attrs的情况
<template> <div> <!-- <Three @twochange1="twochange1" :count="count"></Three> --> <Three v-bind="$attrs" v-on="$listeners"></Three> </div> </template> <script> import Three from "./Three.vue" export default { // props:["count"], components:{ Three }, methods:{ // twochange1(v){ // this.$emit("appchange1",v) // } } } </script> <style> </style>
-
p a r e n t / parent/ parent/root、 c h i l d r e n / children/ children/refs
-
这些功能都是有劣势或危险的场景,官方建议我们尽量避开它们
-
$root:访问根组件vm对象,所有的子组件都可以将这个实例作为一个全局 store来访问或使用,现在有更好的技术vuex来代替
- 在任何组件都可以直接利用this.$root来访问根组件
-
$parent:访问父组件对象,直接操作父组件的data数据,不需要再使用属性传值,但是容易出现渲染混乱之后只渲染一个的情况
-
$children:访问子组件对象数组,不能保证顺序,也不是响应式的
-
这里补充一下;前三者的关系可以理解为 r o o t 为 祖 先 , 然 后 root为祖先,然后 root为祖先,然后parent与 c h i l d r e n 是 父 亲 与 儿 子 的 关 系 , 且 children是父亲与儿子的关系,且 children是父亲与儿子的关系,且root的$parent为undefined
中央事件总线bus
-
通过创建一个新的vm对象,专门统一注册事件,供所有组件共同操作,达到所有组件随意隔代传值的效果
-
具体方法为新建一个js文件来引入 文件内写上如下代码即可
import Vue from "vue" let bus=new Vue({ methods:{ on(eventname,cb){ this.$on(eventname,cb) }, emit(eventname){ this.$emit(eventname,...arguments) }, off(eventname){ this.$off(eventname) } } }) export default bus;
-
然后在main.js引入该js文件,并将引用结果设置到原型上
import $bus from "./bus.js" Vue.prototype.$bus=$bus
-
Provide/Inject
-
通常情况下,父组件向孙组件传递数据,可以采用父子
props
层层传递,也可以使用bus
和Vuex
直接交互。在Vue2.2.0之后,Vue还提供了provide/inject
选项 -
但是官网不建议在应用中直接使用该方法
//父组件中 export default{ provide:{} } //后代组件中 export default{ inject: [] }