1、什么是组件
在使用 Vue 进行前端项目开发过程中,组件的使用最为广泛。然而,什么是组件呢?组件,是 Vue.js 最强大的功能之一。通过开发组件可以封装可复用的代码,将封装好的代码注册成标签,实现扩展 HTML 元素的功能。
2、注册组件
在使用组件之前需要将组件注册到应用中,Vue.js 提供了两种注册方式,局部注册组件和全局注册组件。
2.1 注册全局组件
全局组件可以在所有实例中使用,注册一个全局组件的语法格式:
Vue.component (tagName,option)
语法格式中的两个参数含义分别为:
- tagName:表示定义的组件名称。对于组件的命名,建议遵循 W3C 规范中的自定义组件命名方式,即字母全部小写并包含一个连字符“-”。
- option:该参数可以是应用 Vue.extend() 方法创建的一个组件构造器,还可以是组件的选项对象。因为组件是可复用的 Vue 实例,所有它们与一个 Vue 实例一样接收相同选项(el 选项除外),例如,data、computed、watch、methods,以及生命周期钩子等。
全局组件需要在创建的根实例之前注册,这样才能使组件在实例中调用。
在注册组件后,可以在创建的 Vue 实例中以自定义元素的形式进行使用。使用组件的方式如下:
<tagName></tagName>
1、注册一个全局组件的示例代码如下:
<div id="box">
<my-component></my-component>
</div>
<script type="text/javascript">
//创建组件构造器
var myComponent = Vue.extend({
template:'<h2>注册全局组件</h2>'
});
//注册全局组件
Vue.component('my-component',myComponent)
//创建根实例
var vm =new Vue({
el :'#box'
})
</script>
运行结果如下图所示:
2、上述代码使用了组件构造器的方式。在注册全局组件时,还可以在注册的时候直接传入选项对象而不是构造器。示例代码如下所示:
<div id="box">
<my-component></my-component>
</div>
<script type="text/javascript">
//注册全局组件
Vue.component('my-component',{
template:'<h2>注册全局组件</h2>'
})
//创建根实例
var vm =new Vue({
el :'#box'
})
</script>
运行结果如下图所示:
注意:为了使代码更简化,建议在注册组件的时候采用直接传入选项对象的方式,形如第二种创建组件的方式。
3、如果组件的模板里面有多个元素,可以将模板的内容包含在一个父元素内,示例代码如下所示:
<div id="box">
<my-component></my-component>
</div>
<script type="text/javascript">
//注册全局组件
Vue.component('my-component',{
template:'<div>\
<h2>注册全局组件</h2>\
<span>全局组件在所有实例中都可用</span>\
</div>'
})
//创建根实例
var vm =new Vue({
el :'#box'
})
</script>
运行结果如下图所示:
4、组件选项对象中的 data 和 Vue 实例对象中的 data 的赋值是不同的。一个组件的 data 选项必须是一个函数,而不是一个对象。示例代码如下:
<div id="box">
<button-count></button-count>
<button-count></button-count>
<button-count></button-count>
</div>
<script type="text/javascript">
//注册全局组件
Vue.component('button-count',{
data:function(){
return {
count :0
}
},
template:'<button v-on:click="count++">单击{{count}}次</button>'
})
//创建根实例
var vm =new Vue({
el :'#box'
})
</script>
运行结果如下图所示:
2.2 注册局部组件
1、使用 Vue 实例中的 component 选项可以注册一个局部组件。对于 component 对象中的每个属性而言,其属性名就是定义组件的名称,其属性值就是这个组件的选项对象。局部组件只能在当前实例中使用。简单示例如下:
<div id="box">
<my-component></my-component>
</div>
<script type="text/javascript">
var Child ={
template :'<h2> 注册局部组件</h2>'
}
//创建根实例
var vm =new Vue({
el :'#box',
components:{
'my-component':Child //注册局部组件
}
})
</script>
运行结果如下图所示:
2、局部注册的组件只能在其父组件中使用,而无法在其他组件中使用。例如,有两个局部组件 A 和 B,如果希望 A 在 B 中可用,则需要将 A 定义在 B 的 components 选项中。示例代码如下:
<div id="box">
<parent-component></parent-component>
</div>
<script type="text/javascript">
var Child ={
template :'<h2> 子组件</h2>'
}
var Parent ={
template :'<div>\
<h2>父组件</h2>\
<child-component></child-component>\
</div>',
components:{
'child-component' : Child
}
}
//创建根实例
var vm =new Vue({
el :'#box',
components:{
'parent-component':Parent //注册局部组件
}
})
</script>
运行结果如下图所示:
3、数据传递
3.1 Prop 是什么
由于组件实例的作用域是孤立的,所以子组件的模板无法直接引用父组件的数据。Prop 的出现便是实现父子组件之间数据的传递。
Prop 是父组件用来传递数据的一个自定义属性,该属性需要定义在组件选项对象的 props 选项中。通过 props 选项中定义的属性可以将父组件的数据传递给子组件,而子组件需要显式地用 props 选项来声明 Prop。示例代码如下所示:
<div id="box">
<my-component message="因为热爱,所以奔赴"></my-component>
</div>
<script type="text/javascript">
//注册全局组件
Vue.component('my-component',{
props:['message'],//传递Prop
template:'<p>{{message}}</p>'
})
//创建根实例
var vm =new Vue({
el :'#box',
})
</script>
运行结果如下图所示:
一个组件默认可以拥有任意数量的 Prop,任何值都可以传递给任何 Prop
3.2 传递动态 Prop
1、通过 v-bind 的方式将父组件中的 data 数据传递给子组件。每当父组件的数据发生变化时子组件也会随之发生变化。示例代码如下所示:
<div id="box">
<my-component v-bind:boxoffice="boxoffice"></my-component>
<!--可简写 -->
<!--<my-component :boxoffice="boxoffice"></my-component> -->
</div>
<script type="text/javascript">
//注册全局组件
Vue.component('my-component',{
props:['boxoffice'],//传递Prop
template:'<p>每天计划跑{{boxoffice}}公里,\
加油,未来的你一定会感谢现在努力的自己</p>'
})
//创建根实例
var vm =new Vue({
el :'#box',
data:{
boxoffice:4.5
}
})
</script>
当 根实例中的 boxoffice 值发生改变时,组件中的值也会随之改变,运行结果如下图所示:
2、使用 Prop 传递的数据可以是数值和字符串类型外,还可以是数组或对象类型。传递数组类型数据的示例代码如下所示:
<div id="box">
<my-item :list="type"></my-item>
</div>
<script type="text/javascript">
//注册全局组件
Vue.component('my-item',{
props:['list'],//传递数组类型Prop
template:'<ol>\
<li v-for="item in list">{{item}}</li> </ol>'
})
//创建根实例
var vm =new Vue({
el :'#box',
data:{
type :['演员','歌手','导演','作家']
}
})
</script>
运行结果如下图所示:
注意:如果 Prop 传递的是一个对象或数组,那么它是按引用传递的。在子组件内修改这个对象或数组本身将会影响父组件的状态。
3、在传递对象类型的数据时,如果想要将一个对象的所有属性都作为 Prop 传入,可以使用不带参数的 v-bind。示例代码如下所示:
div id="box">
<my-item v-bind="type"></my-item>
</div>
<script type="text/javascript">
//注册全局组件
Vue.component('my-item',{
props:['actor','singer','director','writer'],//传递数组类型Prop
template:'<div>\
<div>演员:{{actor}}</div>\
<div>歌手:{{singer}}</div>\
<div>导演:{{director}}</div>\
<div>作家:{{writer}}</div>\
</div>'
})
//创建根实例
var vm =new Vue({
el :'#box',
data:{
type:{
actor:'晓茗',
singer:'房东的猫',
director:'尹涛',
writer:'大冰'
}
}
})
</script>
运行结果如下图所示:
4、自定义事件
父组件通过使用 Prop 为子组件传递数据,如果子组件要把数据传递回父组件,需要定义自定义事件来实现。
4.1 自定义事件的监听与触发
1、父组件可以像处理原生 DOM 事件一样通过 v-on 监听子组件实例的自定义事件,而子组件可以通过调用内建的 $emit 方法并传入事件名称来触发自定义事件。
$emit() 方法的语法格式如下:
vm.$emit ( eventName,[...args] )
参数说明如下:
- eventName:传入事件的名称
- […args]:触发事件传递的参数,该参数是可选的。
自定义事件的监听和触发的示例代码如下:
<div id="box">
<div v-bind:style="{fontSize: fontSize+'px'}">
<my-font v-bind:text="text" v-on:enlarge="fontSize +=2"></my-font>
</div>
</div>
<script type="text/javascript">
//注册全局组件
Vue.component('my-font',{
props:['text'],
template:'<div>\
<button v-on:click="action">放大文本</button>\
<p>{{text}}</p>\
</div>',
methods:{
action:function(){
this.$emit('enlarge');//触发自定义enlarge事件
}
}
})
//创建根实例
var vm =new Vue({
el :'#box',
data:{
text:'世界那么大,我想去看看',
fontSize:17
}
})
</script>
运行结果如下图所示:
2、在父组件监听自定义事件时,如果事件处理程序是一个方法,通过 $emit() 方法传递的参数将会作为第 1 个参数传入该方法中,示例代码如下所示:
<div id="box">
<my-menu @select-item="onSelectItem" :flag="flag"></my-menu>
</div>
<script type="text/javascript">
//注册全局组件
Vue.component('my-menu',{
props:['flag'],
template :'<div class="nav">\
<span @click="select(1)" :class="{active: flag===1}">音乐</span>\
<span @click="select(2)" :class="{active: flag===2}">体育</span>\
<span @click="select(3)" :class="{active: flag===3}">影视</span>\
<span @click="select(4)" :class="{active: flag===4}">图片</span>\
</div>',
methods:{
select (value){
this.$emit('select-item',value) //触发自定义事件并传递参数
}
}
})
//创建根实例
var vm =new Vue({
el :'#box',
data:{
flag :1
},
methods:{
onSelectItem:function(value){
this.flag=value
}
}
})
</script>
运行结果如下图所示:
4.2 原生事件绑定到组件
在某个组件的根元素上监听一个原生事件,可以使用 v-on 的 .native 修饰符。例如,在组件的根元素上监听 click 事件,当单击组件时弹出“你好,晓茗”的对话框,示例代码如下所示:
<div id="box">
<my-component v-on:click.native="openDialog"></my-component>
</div>
<script type="text/javascript">
//注册全局组件
Vue.component('my-component',{
template :'<div> \
<button>单击按钮弹出对话框</button>\
</div>'
})
//创建根实例
var vm =new Vue({
el :'#box',
methods:{
openDialog : function(){
alert("你好,晓茗");
}
}
})
</script>
运行结果如下图所示: