一、 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.jsimport Vue from'vue'exportdefaultnewVue()
组件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
版权归原作者 King_960725 所有, 如有侵权,请联系我们删除。