1.父组件给子组件传值
组件的定义和注册:
<script>
伪代码仅供学习:
// 定义子组件
const Son = {
template: '#sonTem',
//在子组件定义的地方,添加一个选项 props, 值为数组, 数组元素为之前自定义的属性tip,然后就可以在子组件中通过{{ tip }}的用法使用这个值
第一种:
props: ['tip'],
//如果父组件给子组件传的值是子组件不想要的 -- 子组件需要验证数据的类型,这一步是项目中常用的
第二种:
props: { // 校验的数据格式
tip: Number // 在这里期望的是number类型,实际上我们传的是string,此时浏览器就会警告,但是数据还是会拿到
},
第三种:
props: {
tip: {
type: Number,// 校验的数据格式
default: 0 // 默认值如果为数组或者对象,需要使用函数实现
// 例如:
// type: Array,
// default: function () {
// return [1, 2, 3]
// }
}
},
};
// 定义父组件
const Parent = {
template: '#parentTem',
data() { // 定义组件中的data是一个函数,要用其中的值就要return出去
return {
msg: '父组件的数据',
}
},
// 在父组件中注册子组件
components: {
'my-son': Son,
}
};
const app = new Vue({
el: '#app',
// 注册父组件
components: {
'my-parent': Parent,
}
});
</script>
抽离template选项的内容,template标签应该放到和 body以及script之间的位置:
<template id="parentTem">
<ul>
父亲的页面
<!-- 在父组件调用子组件的地方,给它添加一个自定义的属性tip, 属性的值为msg,即需要传给子组件的值 -->
<my-son :tip='msg'></my-son>
</ul>
</template>
<template id="sonTem">
<div>
<li>儿子1--{{ tip }}</li>
<li>儿子2--{{ tip }}</li>
<li>儿子3--{{ tip }}</li>
</div>
</template>
html代码:
<body>
<div id="app">
<my-parent></my-parent>
</div>
</body>
在浏览器中显示的内容
在父组件调用子组件的地方,给他添加一个自定义的属性(属性名随便定义),属性值为需要传递的值(如果传递的值为变量,则使用绑定属性);在定义子组件的地方,添加一个选项props,值为数组,数组中的元素就是父元素定义的属性名,然后就可以在子组件中通过{{ 属性名 }} 来使用这个值。
tips: props有三种写法,第一种是数组;第二种props是对象,加了一个校验格式;第三种是对象,校验格式 + 默认值(默认值如果是数组或对象,需要用函数实现)
2.子组件给父组件传值
js代码:
// 定义子组件
const Son = {
template: '#sonTem',
methods: {
sendData () {
this.$emit('hahaha','这条数据来自于子组件');
// 子组件的某一个事件内部,通过this.$emit('自定义的事件名',传递的值)传递数据
}
}
};
// 定义父组件
const Parent = {
template: '#parentTem',
data () {
return {
msg: 'Parent的数据'
}
},
methods: {
// 这里的getData函数,会带有默认的参数,参数的值就是子组件传递的值
getData(obj) {
this.msg = obj; // 将收到的数据赋值给msg
}
},
// 注册子组件
components: {
'my-son': Son,
}
}
// 实例化Vue
const app = new Vue({
el: '#app',
// 注册父组件
components: {
'my-parent': Parent,
}
});
组件:
<template id="parentTem">
<div>
{{ msg }}
<!-- 通过触发在子组件中定义的自定义事件,来触发父组件中的getData函数来接收数据 -->
<my-son @hahaha='getData'></my-son>
<!-- 父组件在调用子组件的地方,绑定了子组件自定义的事件名,这里的函数体不能加() -->
</div>
</template>
<template id="sonTem">
<div>
这里是子组件
<button @click='sendData'>点击传值给父组件</button>
</div>
</template>
html代码:
<body>
<div id="app">
<my-parent></my-parent>
</div>
</body>
父组件中就可以使用 '这条数据来自于子组件' 这条数据了。
子组件的某一个事件(a)内部,通过this.$emit('自定义的事件名',传递的值)传递数据,父组件中通过触发子组件中定义的自定义事件,来触发父组件中的事件(b),事件b会带有默认的参数,参数的值就是子组件传递的值。
3.非父子组件间传值
js代码:
// 中央事件总线(new Vue()),一方负责监听bus.$on(),一方负责触发bus.$emit()
// 1.定义中央事件总线(新定义一个实例化的vue)
const bus = new Vue();
// 定义组件1
const Index = {
template: '#indexTem',
data() {
return {
index: 1,
}
},
mounted() {
// 2.监听事件
// bus.$on('changeIndex', (index) => {
// this.index = index;
// })
let that = this;
// $on监听到changeIndex这个事件触发之后,执行自带的函数,参数即为传过来的数据
bus.$on('changeIndex', function(index) {
that.index = index;
console.log(this,that);//如果不用箭头函数,此时的this指向发生了改变
// this指的是Vue对象(即bus),that指的是VueComponent(即Index),是我们所需要的
})
}
}
// 定义组件2
const Banner = {
template: '#bannerTem',
methods: {
getIndex(index) {
// 3.触发事件(在组件2中通过click触发getIndex事件,
// 然后通过$emit触发changeIndex事件,在组件1中通过$on监听到这个事件,接收到数据)
bus.$emit('changeIndex', index);
}
}
}
// 实例化Vue
const app = new Vue({
el: '#app',
components: {
'my-index': Index,
'my-banner': Banner,
}
});
组件:
<template id="indexTem">
<div>
组件1的值:{{ index }}
</div>
</template>
<template id="bannerTem">
<div>
这里是组件2
<!-- 四个按钮的getIndex传了不同的参数 -->
<button @click='getIndex(1)'>1</button>
<button @click='getIndex(2)'>2</button>
<button @click='getIndex(3)'>3</button>
<button @click='getIndex(4)'>4</button>
</div>
</template>
html代码:
<body>
<div id="app">
<my-index></my-index>
<my-banner></my-banner>
</div>
</body>
定义一个中央事件总线(new Vue()),一方负责监听:
实例.$on()
,一方负责触发:实例.$emit()
;接收数据的组件定义一个监听事件,监听的事件名(a)自定义;在传递数据的组件内定义一个触发事件,触发的事件名(a)对应,当监听的一方监听到事件被触发,就执行内部自带的函数,参数即为传过来的数据。
tips:两个组件有两次交互,就会有四次事件,如果做三次交互就会有六次事件,其实最麻烦的不是他们之间的传值,而是定义他们之间的事件名称,如果没有一套完备定义事件名称的规则,会无端的增加项目开发的周期,降低了开发效率,代码的耦合度会增加,维护性也低了。
所以不建议使用。
4.vuex状态管理器
方法请移步至另一篇博文Vue状态管理器
网友评论