vue组件间传值的6种方法总结
作者:King_960725
这篇文章主要给大家介绍了关于vue组件间传值的6种方法,组件是vue.js最强大的功能之一,而组件实例的作用域是相互独立的,这就意味着不同组件之间的数据无法相互引用,需要的朋友可以参考下
一、 vue组件间传值
1. 父组件向子组件进行传值 props
父组件代码:
<template> <div> 父组件: <input type="text" v-model="name"> <br> <br> <!-- 引入子组件 --> <child :inputName="name"></child> </div> </template> <script> import child from './child' export default { components: { child }, data () { return { name: '' } } } </script>
子组件代码:
<template> <div> 子组件: <span>{{ inputName }}</span> </div> </template> <script> export default { // 接受父组件的值 props: { inputName: String } } </script>
页面显示:
2. 子组件向父组件传值 $emit
子组件代码:
<template> <div> 子组件: <span>{{ childValue }}</span> <!-- 定义一个子组件传值的方法 --> <input type="button" value="点击触发" @click="childClick"> </div> </template> <script> export default { data () { return { childValue: '我是子组件的数据' } }, methods: { childClick () { // childByValue是在父组件on监听的方法 // 第二个参数this.childValue是需要传的值 this.$emit('childByValue', this.childValue) } } } </script>
父组件代码:
<template> <div> 父组件: <span>{{name}}</span> <br> <br> <!-- 引入子组件 定义一个on的方法(简写@)监听子组件的状态--> <child @childByValue="childByValue"></child> </div> </template> <script> import child from './child' export default { components: { child }, data () { return { name: '' } }, methods: { childByValue (childValue) { // childValue就是子组件传过来的值 this.name = childValue } } } </script>
页面显示:
父子组件传值原理:父子组件的关系可以总结为 prop 向下传递,事件向上传递。父组件通过 prop 给子组件下发数据,子组件通过事件给父组件发送消息,如下图所示:
3. $parent / $children && ref
- ref:如果在普通的 DOM 元素上使用,引用指向的就是 DOM 元素;如果用在子组件上,引用就指向组件实例
- $parent / $children:访问父 / 子实例
两种都是直接得到组件实例,使用后可以直接调用组件的方法或访问数据。
ref
使用代码:
// component-a 子组件 export default { data () { return { title: 'Vue.js' } }, methods: { sayHello () { window.alert('Hello'); } } } // 父组件 <template> <component-a ref="comA"></component-a> </template> <script> export default { mounted () { const comA = this.$refs.comA; console.log(comA.title); // Vue.js comA.sayHello(); // 弹窗 } } </script>
$parent/$children
使用代码:
// child 子组件 export default { data () { return { name: '我是子组件的数据' } }, created() { console.log(this.$parent, ''获取父组件的实例对象") }, methods: { sayName () { window.alert('我是子组件的方法'); } } } // 父组件 <template> <child /> </template> <script> export default { data() { return { parentName: '我是父组件的数据" } }, created() { console.log(this.$children, ''获取子组件的实例对象') }, methods: { parentFun() { console.log("我的父组件的方法") } } } </script>
4. 总线机制 bus
这种方法通过一个空的Vue实例作为中央事件总线(事件中心),用它来触发事件和监听事件,巧妙而轻量地实现了任何组件间的通信,包括父子、兄弟、跨级。
公共bus.js:
//bus.js import Vue from 'vue' export default new Vue()
组件A代码:
<template> <div> A组件: <span>{{elementValue}}</span> <input type="button" value="点击触发" @click="elementByValue"> </div> </template> <script> // 引入公共的bus,来做为中间传达的工具 import Bus from './bus.js' export default { data () { return { elementValue: 4 } }, methods: { elementByValue() { // 使用$emit来传递参数 Bus.$emit('sendVal', this.elementValue) } } } </script>
组件B代码:
<template> <div> B组件: <input type="button" value="点击触发" @click="getData"> <span>{{num}}</span> </div> </template> <script> import Bus from './bus.js' export default { data () { return { num: 0 } }, mounted() { var vm = this // 用$on事件来接收参数 Bus.$on('sendVal', (data) => { console.log(data) vm.num= data }) }, methods: { getData() { this.num++ } }, destroyed () { // 取消对bus事件的监听 // 事件订阅是通过Bus对象完成的 与组件无关 Bus.$off('sendVal') } } </script>
4. vuex
PMT知识库地址:vuex
5. $attrs / $listeners
- $attrs:包含了父作用域中不被 prop 所识别 (且获取) 的属性 (class 和 style 除外)。当一个组件没有声明任何 prop 时,这里会包含所有父作用域的属性 (class 和 style 除外),并且可以通过 v-bind="$attrs" 传入内部组件。通常配合 interitAttrs 选项一起使用。
- $listeners:包含了父作用域中的 (不含 .native 修饰器的) v-on 事件监听器。它可以通过 v-on="$listeners" 传入内部组件。
接下来我们看个跨级通信( $attrs
)的例子:
index.vue:
//index.vue <template> <div> <h2>浪里行舟</h2> <child-com1 :foo="foo" :boo="boo" :coo="coo" :doo="doo" title="前端工匠" ></child-com1> </div> </template> <script> import childCom1 from "./childCom1.vue"; export default { components: { childCom1 }, data() { return { foo: "javascript", boo: "Html", coo: "Css", doo: "Vue" }; }, methods: { outputMsg() { console.log('我是父组件的方法'); } } }; </script>
childCom1.vue:
//childCom1.vue <template> <div> <p>foo:{{ foo }}</p> <p>childCom1的$attrs:{{ $attrs }}</p> <child-com2 v-bind="$attrs"></child-com2> </div> </template> <script> import childCom2 from "./childCom2.vue"; export default { components: { childCom2 }, inheritAttrs: false, // 不会显示在子组件的dom元素上 props: { foo: String }, // foo作为props属性绑定 created() { console.log(this.$attrs); // { "boo": "Html", "coo": "CSS", "doo": "Vue", "title": "前端工匠" } } }; </script>
childCom2.vue:
//childCom2.vue <template> <div> <p>boo:{{ boo }}</p> <p>childCom2的$attrs:{{ $attrs }}</p> </div> </template> <script> export default { inheritAttrs: false, // 不会显示在子组件的dom元素上 props: { boo: String }, // boo作为props属性绑定 created() { console.log(this.$attrs); // { "coo": "CSS", "doo": "Vue", "title": "前端工匠" } } }; </script>
inheritAttrs为 false
的情况:不会显示在子组件的dom元素上
inheritAttrs为 true
的情况(默认):会显示在子组件的dom元素上
$listeners
例子:
// 父组件 <template> <my-input required placeholder class="theme-dark" @focue="onFocus" @input="onInput" > </my-input> </template> <script> import MyInput from './child' export default { components: { MyInput }, methods: { onFocus (e) { console.log(e.target.value) }, onInput (e) { console.log(e.target.value) } } } </script>
// 子组件 <template> <div> <input type="text" v-bind="$attrs" class="form-control" @focus="$emit('focus', $event)" @input="$emit('input', $event)" /> </div> </template> <script> export default { name: 'MyInput', inheritAttrs: false } </script>
这样绑定原生事件很麻烦,每一个原生事件都需要绑定,但用v-on="$listeners"就会省事很多。
<input type="text" v-bind="$attrs" class="form-control" + v-on="$listeners" - @focus="$emit('focus', $event)" - @input="$emit('input', $event)" />
6. provide / inject
- 成对出现:provide和inject是成对出现的;
- 作用:用于父组件向子孙组件传递数据;
- 使用方法:provide在父组件中返回要传给下级的数据,inject在需要使用这个数据的子辈组件或者孙辈等下级组件中注入数据;
- 使用场景:由于vue有$parent属性可以让子组件访问父组件。但孙组件想要访问祖先组件就比较困难。通过provide/inject可以轻松实现跨级访问父组件的数据。
父组件定义:
<script> export default { // 父组件通过provide将自己的数据以对象形式传出去 provide(){ return { parentValue:"我是父组件的值啊" // 也可以从data中拿值 } } }; </script>
子孙组件接受方式:
<script> export default { // inject:["parentValue"], // 使用一个注入的值作为数据入口: inject:{ // 使用一个默认值使其变成可选项 parentValue: { // 健名 from: 'parentValue', // 来源 default: '我是默认值' // 默认值 } } } </script>
注意:provide并不是响应式的,当子组件inject的时候已经丢失了响应式功能
要希望整个数据都是响应式的—provide提供一个函数。
函数内部返回一个响应式的数据。此时整条数据的响应式的状态并不会丢失。
//父组件传值的定义个回调函数 <template> <div> <a-input v-model="parentValue"/> </div> </template> <script> export default { data() { return { parentValue: "我是父组件的值啊" }; }, provide() { return { getParentVal: () => ({ parentValue: this.parentValue }) } } }; </script>
//子组件用计算属性取值,watch监听 export default { inject: ['getParentVal'], computed: { actConfig() { this.parentValue= this.getParentVal().parentValue // 获取初始时父组件传过来的值 return this.getParentVal(); }, }, watch: { actConfig(val) { console.log("组件监听到的值", val); this.parentValue= val.parentValue }, }, data() { return { parentValue: '' } }, }; </script>
总结
常见使用场景可以分为三类:
- 父子通信: 父向子传递数据是通过
props
,子向父是通过 events($emit
);通过父链 / 子链也可以通信($parent
/$children
);ref 也可以访问组件实例;provide
/inject
;$attrs
/$listeners
- 兄弟通信:
Bus
;Vuex
- 跨级通信:
Bus
;Vuex
;provide
/inject
、$attrs
/$listeners
到此这篇关于vue组件间传值的6种方法总结的文章就介绍到这了,更多相关vue组件间传值内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!