写在前面
最近在学vue,vue刚开始感觉还蛮简单。但是学到后面感觉着实有点绕,真的非常绕,研究组件这一块花了一下午。从一头雾水到逐渐明朗,决定写一篇博客加深自己理解。这篇文章就主要讲一下怎么运用组件,以及父组件向子组件传递数据,子组件向父组件传递数据这三部分。希望对大家对组件的来理解也有所帮助。
文章的开始
1.如何使用组件
组件主要是提高代码重用性,让代码可以重复利用。组件在使用之前需要注册组件,注册组件的方法有两种。一种是全局注册,一种是局部注册。
1.1组件全局注册
顾名思义,全局就是任何地方,也就是说全局注册的组件在任何Vue的实例中都可以使用。
- 例1
Vue.component('my-component',{
template:'<div>注册组件</div>'
})
其中my-component是自定义组件名,可以任意命名,推荐小写减号分割的形式。
后面的大括号里内容是组件选项,在组件选项加template可以在页面中显示出组件的内容。
其内容必须被dom元素包起来,比如说上面的“注册组件”被一组div包裹起来了。
1.2组件局部注册
局部组件只在该实例的作用域下才有效,具体代码如下
- 例2
<div id="app">
<my-component></my-component>
</div>
<script>
var child = {
template:''<div>局部注册组件</div>''
}
var app = new Vue({
el:'#app',
components: {
'my-comoponent':child
}
})
</script>
总结:template后面的内容就是组件的内容,将会在页面中显示。
2.父组件向子组件传递数据
2.1父传子的基本用法
在将数据传输之前,我们先应该知道哪个是父组件,哪个是子组件。就拿全局的来说,其中‘<my-component></my-component>’是父组件,父组件通过prop正向传递数据给Vue.component中子组件。
props的值有两种,一种是字符串数组,用于传递数据;一种是是对象,用于对props进行验证。后者比较好理解,这里主要来讲一下字符串数组这种形式。
- 例3
<div id="app">
<input type="text" v-model= "parentMessage">
<my-component :Message = "parentMessage"></my-component>
</div>
<script>
Vue.component('my-component',{
props:['message'],
template: '<div>{{ message }}</div>'
});
var app = new Vue({
el:'#app',
data:{
parentMessage: ''
}
})
</script>
上面的例子中,文本框中v-model与data中parentMessage绑定。当你在文本框输入信息的时候,输入的内容会绑定到data中parentMessage中。父组件中的Message传递到子组件中的props上,子组件于是获取到message这个属性,该属性就会通过template后显示出来。结果如下图所示。
2.2父传子应当注意的地方
在子组件中,当你想要改变其中数据的值得时候不能直接改变,应该将改变的过程写在data对象或者计算属性computed里面。
在JavaScript中对象和数组是引用类型,指向同一个内存空间。当props是对象和数字时候,在子组件里面改变值会影响父组件的值。当父组件有多个的时候很明显。子组件里面值改变一个,所有的父组件都会改变。而我们通常期望父组件之间是相互独立的。
这里可能会有人看到子组件的值改变,父组件也跟着改变可能会理解为子组件向父组件传递值。其实两者是不一样的。区别如下:
- 例4
例4实现的功能是点击add按钮,number值会加1。当点击按钮触发点击事件,执行增加函数,在函数里面直接munber++来改变值。确实可以完成,但是会报错并提示应该用data或computed来改变props。大家也可以复制下面的代码自己试一试。
<div id="app">
<!-- v-bind将对象里面的东西一并传递给子组件 -->
<my-conponent v-bind="childrenInfo"></my-conponent>
</div>
<script>
var app = new Vue({
el:'#app',
data: {
childrenInfo: {
number:0
}
},
components: {
'my-conponent':{
//子组件里校验,number类型是Number
props:{
number: {
type: Number
}
},
template:
'\
<div>\
<div>{{ number }}</div>\
<button @click="handleClick">add</button>\
</div>'
,
methods: {
handleClick() {
this.number++;
}
}
}
}
})
</script>
警告如图红色部分:
例4-2
<body>
<div id="app">
<!-- v-bind将对象里面的东西一并传递给子组件 -->
<my-conponent v-bind="childrenInfo"></my-conponent>
</div>
<script>
var app = new Vue({
el:'#app',
data: {
childrenInfo: {
number:0
}
},
components: {
'my-conponent':{
//子组件里校验,number类型是Number
props:{
number: {
type: Number
}
},
data : function() {
return {
ownNumber: this.number
}
},
template:
'\
<div>\
<div>{{ ownNumber }}</div>\
<button @click="handleClick">add</button>\
</div>'
,
methods: {
handleClick() {
this.ownNumber++;
}
}
}
}
})
</script>
</body>
例4-2与例4相比,有2个地方进行了更改。一个是添加了data对象,一个是number改成了ownNumber,之所以改ownNumber,是因为data对象中,number:this.number会报错number已经存在在props当中。
3.子组件向父组件传递数据
子组件通过$emit来触发事件,在父组件中能够监听到触发的这个事件去执行一个函数。通过第5个例子来详细讲解子传父的过程。
- 例5
<div id="app">
<p>总数:{{ total }}</p>
<my-component
@increase = 'handeleGettotal'
@reduce = 'handeleGettotal'></my-component>
</div>
<script>
Vue.component('my-component',{
template: '\
<div>\
<button @click = "handleIncrease">+1</button>\
<button @click = "handleReduce">-1</button>\
</div>',
data: function () {
return {
counter:0
}
},
methods: {
handleIncrease :function () {
this.counter++;
//通过$emit()把改变后的counter传递给父组件
this.$emit('increase',this.counter);
},
handleReduce :function () {
this.counter--;
this.$emit('reduce',this.counter);
},
}
})
var app = new Vue({
el:'#app',
data:{
total:0
},
methods: {
handeleGettotal: function (total) {
this.total = total;
}
}
})
结果如图所示,初始的时候总数为0;当玲珑点击三次-1后结果变为-3.
我们可以看到父组件的@increase="handleGetTotal"中,监听到increase事件并执行handleGetTotal函数;在里面有handleGetTotal函数,$emit('increase',this.counter)里面的第二个参数this.counter传给app中handleGetTotal函数中的total。完成了子组件向父组件传递数据的过程。
总结一下,子组件通过emit函数第一个参数就触发的事件名,后面的参数作为实参传给子组件监听到事件后要执行的函数。
文章的结束
阅读完该文章应该知道如何创建组件,以及父子组件之间是如何传递信息的。刚开始看书的玲珑都还弄不清楚哪个是父组件,哪个是子组件,就觉得特别绕,其实认真弄清楚了之后再回过头来看看并没有那么复杂。看书学习一定不要只看书还应该把例子敲一敲,细细揣摩,最后总会有所收获。