Vue的组件component就是一个代码的封装而已,它的目的就是独立的实现某个功能。在之前的前端工程中,都是一个个的html文件组成,而vue工程则是一个个的组件文件组成。这些组件文件各自其职,共同完成整个前端系统。如何将一个大的前端系统按照组件为单位进行拆分,可能更多的是依据UI界面,这里不过多的叙述。
首先,我们创建一个“04_vue_component.html”文件,代码如下
<div id="app">
<my-component />
</div>
<script>
// 定义全局组件
Vue.component('my-component', {
template: '<p>hello, my-component</p>'
})
new Vue({ el: '#app' })
</script>
上述代码中,我们定义了一个全局组件“my-component”,然后使用“template”指定这个组件里面的内容是“<p>hello, my-component</p>”。因为前端工程主要就是完成UI界面,因此定义组件的主要内容也是UI界面。接下来,我们就想使用普通的html标签那样,使用“<my-component />”就能使用我们刚刚定义的组件了。我们这个“my-component”组件只是一个简单UI界面的封装,因此“<my-component />”标签的最终效果就是输出<p>标签。
接下来,我们在创建“04_vue_component2.html”来创建一个vue的“局部组件”。
<div id="app">
<my-component />
</div>
<script>
new Vue({
el: '#app',
components: {
'my-component': {
template: '<p>hello, my-component<p>'
}
}
})
</script>
我们发现,全局组件和局部组件的区别在于定义的位置是不一样的。
其实全局组件和局部组件在使用上也有很大区别。从名称来看,全局组件使用范围更广,它可以被其他组件使用,而局部组件只能在本页面内使用。由于我们的代码案例是单html页面结构,并不是多文件的vue工程架构,因此我们暂时不会将vue组件定义成单独文件。
接下来,我们继续创建“04_vue_component3.html”文件,代码如下
<div id="app">
<my-component />
</div>
<template id="my-component-html">
<p>hello, my-component</p>
</template>
<script>
new Vue({
el: '#app',
components: {
'my-component': {
template: '#my-component-html'
}
}
})
</script>
在上述代码中,我们仍然定义了一个局部组件,但是它的template属性并不是html代码片段了,而是一个ID选择器。我们在文件中使用<template>标签定义了这个局部组件的内容。这样的好处在于,我们就可以按照正常的书写html的方式来构建组件的内容,而不是以字符串的形式来构建了。其实vue组件中除了template来定义组件内容之外,还可以使用data和methods等来定义数据和方法,其实就如同使用vue一样来使用vue组件。
接下来,我们创建“04_vue_component4.html”,代码如下所示:
<div id="app">
<my-component />
</div>
<template id="my-component-html">
<div>
<p>{{message}}</p>
<button @click="updateMessage">updateMessage</button>
</div>
</template>
<script>
new Vue({
el: '#app',
components: {
'my-component': {
template: '#my-component-html',
data: function(){
return {
message: 'hello, my-component'
}
},
methods: {
updateMessage:function(){
this.message = 'hello, vue';
}
}
}
}
})
</script>
我们重新定义了“my-component”组件。在组件的内部,我们定义了数据message和方法updateMessage,他们使用基本和之前vue的使用是一样的。这里有两点需要注意,第一,在<template>标签中定义的组件内容的时候,必须有一个根标签(本案例的<div>);第二,组件内的data数据定义并不是json对象,而是function方法。
接下来,我们点击按钮
这样一个简单的小功能,我们将其定义在一个组件内,而不是之前的vue实例中。我们前面提到,vue组件就是一个独立的小功能,但是这种独立性只是“功能”层面上,并不是“数据”层面上。也就是说,当我们使用某个vue组件的时候,我们可能需要向其传递数据,甚至还要让它返回处理好的数据。接下来,我们演示如何向组件传递数据,我们创建“04_vue_component_props.html”文件
<div id="app">
<my-component message="hello, my-component" />
</div>
<template id="my-component-html">
<p>{{message}}</p>
</template>
<script>
// 定义一个组件类型对象
var myComponent = Vue.extend({
props: ['message'],
template: '#my-component-html'
});
// 直接使用组件类型对象
new Vue({
el: '#app',
components: {
'my-component': myComponent
}
})
</script>
在上述代码中,我们将组件定义在vue实例的外面,但他不是全局组件,仍然是局部组件。因为vue本质就是js对象,它的组件也是js对象。因此,我们只需要按照vue组件的格式定义一个js对象,那么它就是vue组件了。我们只需要在局部组件的位置使用这个js对象即可。当我们使用这个组件的时候,我们是“<my-component message="hello, my-component" />”这样用的。也就是说,我们给组件传递数据的方式,就是通过组件标签属性。当然,这个属性名称message是我们自定义的,属性值“hello, my-component”就是传递给数据的数据。那么,我们如何在组件内部显示传递过来的数据呢?首先要使用props声明传递过来的数据,也就是我们定义的属性名称message,然后就可以在<template>中直接使用了。正常情况下,我们都是在data中定义数据message,而传递过来的数据涉及到交互,所以就在props声明一下就行了。另外需要注意的是,使用data定义的时候,数据是json对象形式,而props声明的时候,数据是数组形式。
在上述代码中,我们传递给组件的数据是硬代码写的,实际上,它应该是一个数据变量。接下来,我们创建“04_vue_component_props2.html”文件,代码如下
<div id="app">
<my-component :message="msg" />
</div>
<template id="my-component-html">
<p>{{message}}</p>
</template>
<script>
// 定义一个组件类型对象
var myComponent = Vue.extend({
props: ['message'],
template: '#my-component-html'
});
// 直接使用组件类型对象
new Vue({
el: '#app',
data:{ msg:'hello, my-component' },
components: {
'my-component': myComponent
}
})
</script>
其实,我们的改动就两点。第一,就是在vue实例中增加了data数据定义,增加了一个名称为msg的字符串数据,它的值就是“hello, my-component”。第二,我们如何将这个msg传递给组件的message呢?非常简单,就是使用“v-bind”绑定指令::message="msg"
我们可以将vue实例理解为父组件,子组件的message来源于父组件的msg。那么,这个message和msg的关系是如何呢?这个问题类似于java方法的参数传递问题。这里,我们先给出结论。修改父组件msg会同步子组件message,但修改子组件message不会同步父组件msg。
我们创建“04_vue_component_sync.html”文件,代码如下
<div id="app">
<div>
<p><span>父组件:</span>{{msg}}</p>
<p><button @click="changMsg()">修改父组件msg</button></p>
</div>
<my-component :message="msg" />
</div>
<template id="my-component-html">
<div>
<p><span>子组件:</span>{{message}}</p>
<p><button @click="changMessage()">修改子组件message</button></p>
</div>
</template>
<script>
// 定义一个组件类型对象
var myComponent = Vue.extend({
props: ['message'],
template: '#my-component-html',
methods: {
changMessage: function(){
this.message = 'hello, child'
}
}
});
// 直接使用组件类型对象
new Vue({
el: '#app',
data:{ msg:'hello, my-component' },
components: {
'my-component': myComponent
},
methods: {
changMsg: function(){
this.msg = 'hello, parent!';
}
}
})
</script>
其实,我们就是在父组件和子组件增加了各自修改数据的方法。我们只需要点击各自的修改数据方法来查看是否对对方有影响。
我们首先点击“修改父组件msg”按钮
我们发现,修改父组件的msg数据,子组件的message也跟随改变。接下来,我们刷新浏览器恢复之前的初始页面,然后点击“修改子组件message”按钮
我们发现,子组件改变了,但是父组件没有改变。这样的结论比较尴尬,要么两者相互影响(类似于java方法的引用类型参数传递),要么就不要影响(类似于java方法的基本类型参数传递)。如何解决这个问题,我们下一个章节介绍。
本章节先介绍到这里。
本课程的内容可以通过CSDN免费下载:https://download.csdn.net/download/richieandndsc/89025243