Vue 作为一个轻量级的前端框架,核心两大特性就是响应式编程和组件化。

本文针对组件之间传值做详细讲解。 Vue就是由一个一个的组件构成的,组件化是它的精髓,也是最强大的功能之一。而组件实例的作用域是相互独立的,这就意味着不同组件之间的数据无法相互引用。

但在实际项目开发过程中,我们需要访问其他组件的数据,这样就就有了组件通信的问题。在 vue 中组件之间的关系有:父子,兄弟,隔代。针对不同的关系,怎么实现数据传递,下面展开说明。

如上图所示:
父子关系:A与B,A与C,B与D,C与E
兄弟关系:B与C
隔代关系(可能隔更多代):A与D,A与E
跨级关系:B与E,D与E等

一、父组件向子组件传值  props

<!--父组件页面-->
<template><div id="app"><!--子组件--><child-box :message="params"></child-box> //把params的值传给子组件</div>
</template><script>
// 引入子组件
import ChildBox from './childBox.vue'export default {// 初始化子组件components: {ChildBox},data() {return {params: 'hello' // 如果params值为 undefined 则会使用default的值}}
}
</script>
<!--子组件页面-->
<template><div class="child-box">{{ message }}</div>
</template><script>export default {/*** props功能:让组件接受外部传过来的数据* * 1.传递数据 <child-box :message="hello"></child-box>* * 2.接收数据*   第一种方式(只接收)*   props: ['message']* *   第二种方式(限制类型)*   props: { message: String }  多个 props: { message: String, name: '王新焱'}*   *   第三种方式(限制类型、限制必要性、指定默认值)  //这种方式更为严谨*   props: {*      message: {*          type: String,*          required: true,*          default: '王新焱'*      }*   }* *  备注:props是只读的,Vue底层会监测你对props的修改,如果进行了修改,就会发出警告,若业务需求确实需要修改,那么请复制props的内容到data中一份,然后去修改data中的数据*  *  如果要使用默认值 default message值设置为 undefined即可 ->示例:<child-box :message="undefined"></child-box>* */props: {message: {type: String, // 指定数据类型required: true, // 指定数据为必填项default: '王新焱' // 指定默认值,如果message绑定的值设置为 undefined 即会使用该值}}}
</script>

总结:

1.父组件中注册子组件,在子组件标签中添加子组件props中创建的属性,把需要传给子组件的值赋给该属性。

2.子组件在props中创建一个属性,用以接收父组件传过来的值。

3.父子组件的关系可以总结为prop向下传递,事件向上传递。

4.父组件通过prop给子组件下发数据,子组件通过事件给父组件发送信息,这就是单向数据流的表现形式。

二、子组件向父组件传值  $emit

<!-- 父组件页面 -->
<template><div id="app"><!-- 引入子组件,定义一个v-on的方法监听子组件的状态--><child-box :message="params" @childFnGetParent="parentFn"></child-box><P>{{ msg }}</P></div>
</template><script>
// 引入子组件
import ChildBox from './childBox.vue'export default {// 初始化子组件components: {ChildBox},data() {return {params: 'hello',msg: ''}},methods: {parentFn(val) {// val 就是子组件传过来的值this.msg = val}}
}
</script>
<!-- 子组件页面 -->
<template><div class="child"><button @click="parentFn">子组件向父组件传值</button></div>
</template><script>export default {data() {return {msg: '我是来自子组件的消息'}},methods: {parentFn() {// childFnGetParent 是在父组件v-on监听的方法,第二个参数this.msg是需要传递的值this.$emit('childFnGetParent', this.msg)}}}
</script>

总结

1.子组件中需要以某种方式例如点击事件的方法来触发一个自定义事件

2.将需要传的值作为$emit的第二个参数,该值将作为实参传给响应自定义事件的方法

3.在父组件中注册子组件并在子组件标签上绑定对自定义事件的监听

4.在通信中,无论是子组件向父组件传值还是父组件向子组件传值,他们都有一个共同点就是有中间介质,子向父的介质是自定义事件,父向子的介质是props中的属性。理解这两点对于父子通信就好理解了

子组件:通过$emit()方法发布事件广播

父组件:捕获到子组件向外触发的事件,然后可执行相应的方法

三、非父子组件传值  EventBus

非父子组件最常用的是EventBus方案进行数据传递,定义方式有三种

/*** 方法一 抽离成一个单独的 js 文件 EventBus.js ,然后在需要的地方引入* EventBus.js*/
import Vue from "vue"
export default new Vue()/*** 方法二 直接挂载到全局* main.js*/
import Vue from "vue"
Vue.prototype.$bus = new Vue()/*** 方法三 注入到 Vue 根对象上* main.js*/
import Vue from "vue"
new Vue({el:"#app",data:{Bus: new Vue()}
})

本文案例以第一种方法 新建 EventBus 展开讲述

1.新建公共文件 EventBus.js

/*** EventBus.js* * eventBus 又称为事件总线,在vue中可以使用它来作为沟通桥梁的概念, 就像是所有组件共用相同的事件中心* * 不管是父子组件,兄弟组件,跨层级组件等都可以使用它完成通信操作*/import Vue from 'vue'// 创建一个 EventBus.js 文件,暴露一个 vue 实例
export default new Vue()

2.新建一个A组件

<!--组件A-->
<template><div class="child-A"><span>年龄:{{ value }}</span><button @click="getValue">修改年龄</button></div>
</template><script>
import Bus from './EventBus.js'
export default {data() {return {value: 30}},methods: {getValue() {// 在A组件中通过$emit向外部发送自定义事件 (事件广播)Bus.$emit('getVal', this.value)}}
}
</script>

3.新建一个B组件

<!--组件B-->
<template><div class="child-B"><span>年龄:{{ age }}</span><button @click="getData">点击触发</button></div>
</template><script>
import Bus from './EventBus.js'
export default {data() {return {age: 18}},mounted() {// B组件 用$on事件来接收外部事件Bus.$on('getVal', (data)=> {this.age = data // data为广播过来值})},methods: {getData() {this.age++}}
}
</script>

使用 EventBus 有一个弊端就是事件广播,这种方式不会自动销毁,所以避免回调函数重复执行,需要在destroyed生命周期中销毁广播事件

destroyed() {
    Bus.$off('eventName')  // 对Bus取消事件监听后 内存得到了释放
}

总结

$off() 会取消所有的事件订阅

$off('事件名') 会取消指定事件名的

$off('事件名', 回调) 会取消指定事件名的,指定回调

四、多层父子组件通信 (依赖注入)  provide / inject

有时需要实现通信的两个组件不是直接的父子组件,而是祖父和孙子,或者是跨越了更多层级的父子组件,这种时候就不可能由子组件一级一级的向上传递参数,特别是在组件层级比较深,嵌套比较多的情况下,需要传递的事件和属性较多,会导致代码很混乱。

这时就需要用到 vue 提供的更高阶的方法:provide/inject

provide/inject:简单来说就是在父组件中通过provider来提供变量,然后在子组件中通过inject来注入变量,不管组件层级有多深,只要调用了inject 那么就可以注入provide中的数据。

<!--父组件页面-->
<template><div class="box"><!-- 引入子组件A--><child-a></child-a><!-- 引入子组件B--><child-b></child-b></div>
</template><script>
export default {provide: {name: '张三丰', // 将变量name提供给它的所有子组件及后代组件reload: this.reload // 也可以是一个函数},data() {return {isShow: false}},methods: {reload() {this.isShow = true}}
}
</script>
<!--组件A-->
<template><div class="child-A"><div>这是组件A</div><!-- 输出张三丰 --><div>{{ name }}</div></div>
</template><script>export default {inject: ['name'], // 注入了从父组件中提供的name变量mounted() {console.log(this.name) // 张三丰}
}
</script>
<!--组件B-->
<template><div class="child-B"><div>这是组件B</div><!-- 输出张三丰 --><div>{{ name }}</div></div>
</template><script>
export default {inject: ['name'], // 注入了从父组件中提供的name变量mounted() {console.log(this.name) // 张三丰}
}
</script>

注:provide 和 inject 绑定并不是可响应的。即父组件的name变化后,子组件不会跟着变。

五、通过访问组件实例的方式  ref

父组件通过 ref获取子组件的实例 可以直接访问子组件里面的方法和属性

<!--父组件页面-->
<template><div class="box"><!-- 引入子组件A--><child-a ref="childA"></child-a><button @click="getChildData">获取子组件的属性和方法</button></div>
</template><script>
// 引入子组件
import ChildA from './childBox.vue'export default {// 初始化子组件components: {ChildA},methods: {getChildData() {// 获取子组件的属性console.log(this.$refs.childA.txt) //我是子组件A// 获取子组件的方法console.log(this.$refs.childA.getName()) //张三丰}}
}
</script>
<!--组件A-->
<template><div class="child-A"><div>这是组件A</div></div>
</template><script>export default {data() {return {txt: '我是子组件A',name: '张三丰'}},methods: {getName () {console.log(this.name)} }
}
</script>

注:这种方式的组件通信不能跨级

六、$children / $parent

$children:获取到一个组件实例,包含所有子组件(不包含孙子组件)的 VueComponent 对象数组,可以直接拿到子组件中所有数据和方法等

$parent:获取到一个组件实例,包含父节点的 VueComponent 对象,同样包含父节点中所有数据和方法

$children 方法讲解

<!--父组件页面-->
<template><div class="box"><!-- 引入子组件A--><child-a ref="childA"></child-a><!-- 引入子组件B--><child-b></child-b><button @click="getChildData">获取子组件的属性和方法</button></div>
</template><script>
// 引入子组件
import ChildA from './childBox.vue'
import ChildB from './childBox2.vue'export default {// 初始化子组件components: {ChildA,ChildB},methods: {getChildData() {// 获取第一个组件的nameconsole.log(this.$children[0].name) //张三丰// 获取第一个组件getTitle方法console.log(this.$children[0].getTitle()) //我是子组件A// 获取第二个组件的nameconsole.log(this.$children[1].name) //张无忌}}
}
</script>
<!--组件A-->
<template><div class="child-A"><div>这是组件A</div></div>
</template><script>export default {data() {return {txt: '我是子组件A',name: '张三丰'}},methods: {getTitle () {console.log(this.txt)} }
}
</script>
<template><div class="child-B"><div>这是组件B</div></div>
</template><script>
export default {data() {return {txt: '我是子组件B',name: '张无忌'}}
}
</script>

$parent 方法讲解

<!--父组件页面-->
<template><div class="box"><!-- 引入子组件A--><child-a ref="childA"></child-a></div>
</template><script>
// 引入子组件
import ChildA from './childBox.vue'export default {// 初始化子组件components: {ChildA},data() {return {title: '这是父页面',name: '父组件',age: 20}},methods: {getAge() {console.log(this.age)}}
}
</script>
<!--组件A-->
<template><div class="child-A"><div>这是组件A</div><button @click="getParentData">A组件获取父组件的属性和方法</button></div>
</template><script>export default {methods: {getParentData() {console.log(this.$parent.title) //获取父页面title属性console.log(this.$parent.getAge()) //执行父页面getAge方法}}
}
</script>

七、slot 插槽传值

子组件的数据通过插槽的方式传给父组件使用,要显示内容由父组件决定

<!--父组件页面-->
<template><div class="box"><!--引入子组件A--><child-a ref="childA" v-slot="slotProps"><!--父组件使用slot插槽方式获取子组件数据-->  {{ slotProps.user.name }}{{ name }}</child-a></div>
</template><script>
// 引入子组件
import ChildA from './childBox.vue'export default {// 初始化子组件components: {ChildA},data() {return {name: '张三丰'}}
}
</script>
<!--组件A-->
<template><div class="child-A"><!-- <div>这是组件A</div> --><slot :user="user"></slot></div>
</template><script>export default {data() {return {user: {name: '张无忌'}}}
}
</script>

以上几种也是vue组件传值主流的方式了,根据业务的不同场景选择不同的方式,此外vuex也是组件传值最常用的方式,我计划把这个知识点单独列出来进行讲解,后续会附上链接。

友情赠送一张小图

vue组件传值方式有哪些相关推荐

  1. vue组件传值的11种方式

    不写这篇文章,我自己都不知道我知道的vue组件传值的方式竟然有11种之多,其实静下来想想,常用的也有五六种,先上一张总结图: 1.父组件传给子组件 在子组件里定义一个props,即props:['ms ...

  2. vue组件传值的十种方式

    vue组件传值的十种方式 一.props 父传子 子组件 // 第一种数组方式 props: [xxx, xxx, xxx] // 第二种对象方式 props: { xxx: Number, xxx: ...

  3. 【vue】vue组件传值的三种方式

    前言 vue的组件传值分为三种方式:父传子.子传父.非父子组件传值 引用官网的一句话:父子组件的关系可以总结为 prop 向下传递,事件向上传递 父组件通过 prop 给子组件下发数据,子组件通过事件 ...

  4. 41. Vue组件传值-父组件向子组件传值

    前言 前面写了组件的创建.切换等等篇章,主要讲述了组件自身如何在父组件app中如何渲染使用.这里存在一个问题,就是父组件的数据如何传递到子组件中. 这是一个很常见的情况,如果是jQuery那么都是直接 ...

  5. Vue组件传值的三种方法

    Vue组件传值的三种方式 1.父传子 父传子使用props: 1.父组件:即在使用的子组件标签上,自定义一个绑定数据,这里我使用的是"mymsg",将父组件的msg绑定在其上. 2 ...

  6. Vue组件传值存在的弊端-Vuex状态管理

    以下内容纯属个人理解,旨在记录和分享. 导入 使用Vue组件传值,可以实现父子组件之间的数据交换.但实际上,在应用过程中仍然存在很多不便之处: 当存在多层组件嵌套时,组件之间的传值将会变得极度麻烦和繁 ...

  7. vue 组件传值的常用5种方法

    前言 组件传值非法常用 这里简单记录下下 一. ref方式 - ref方式- 父传子:父获取子组件实例对象- 子组件标签 ref="xxx"- this.$refs.xxx==== ...

  8. vue组件传值 prop传递对象

    vue组件传值 prop传递对象 大家经常会使用组件传值,今天我用到的时候突然遇到了一些坑,想着今天来记录一下,大家做一个参考,此篇仅说一下prop传递对象. 子组件接收基本的数据类型 子组件 < ...

  9. this指向-作用域、作用域链-预解析 变量提升-Vue组件传值 父子 子父 非父子-Vue数据双向绑定原理

    目录 this指向 作用域.作用域链 预解析 变量提升 Vue组件传值 父子 子父 非父子 Vue数据双向绑定原理 1.this指向 函数的this指向 看调用.不看声明 (1)普通函数调用 ①函数名 ...

最新文章

  1. Spark2 ML 学习札记
  2. linux c 重定向流后的恢复 freopen后的恢复
  3. php ADODB使用方法
  4. leetcode mysql 排名_GitHub - nimphy/leetcode-Mysql
  5. Address already in use: JVM_Bind问题的解决
  6. javascript window alert
  7. GridView的DataKeyNames属性(转)
  8. VC编程中,判断野指针
  9. 【.Net】asp.net 把图片从CMYK印刷模式转换为RGB原色模式
  10. 电脑如设置路由器WiFi外加无线桥接一个副路由器
  11. 笛卡尔的思维法则(数学思维的规范)
  12. VMware虚拟机扩展磁盘容量【绝对简单的傻瓜式操作】
  13. 支持免费试用的香港云服务器推荐
  14. Python 编码规范 PEP8
  15. 谷歌涂鸦(goofle doodle)
  16. python使用win32com读写excel的问题
  17. 浪潮服务器功耗计算器
  18. python解析xml文件最好选用的模块_python高级编程 之解析XML文件模块
  19. BZOJ 1875[SDOI2009]HH去散步
  20. 哈佛结构和冯诺依曼结构的区别(3)

热门文章

  1. linux有没有showtrees命令,容器与云|监控 Linux 容器性能的命令行神器
  2. 这恍惚间的岁月,一个 00 后的回忆录【自述】
  3. 解锁iPhone密码的三种方法
  4. 山东建筑大学计算机考研率,山东建筑大学考研难吗?一般要什么水平才可以进入?...
  5. idea开发SSM框架游戏账号租号发布网站 (javaweb-php-asp.netC#-j2ee-springboot)功能有推荐算法功能
  6. 灵活例子彻底搞懂reduce
  7. Eclipse Android 给模拟器安装应用程序--搜狗输入法
  8. android仿小米运动,仿小米运动的运动记录界面
  9. cf进不去显示服务器,cf进不去服务器
  10. qduoj 31 帅气的HYC 切蛋糕