目录
注册组件并使用
模板只有一个根元素
监听子组件事件
具名插槽
动态组件
组件化是vue除了声明式渲染之外另一个最重要的概念之一。
组件,本质上是一个拥有自定义选项的vue实现。如下所示,像这样定义组件:
Vue.component('todo-item', {
data:()=>({}),
props: ['todo'],
template: `<li>这是个待办项</li>`
})
这是动态注册的组件。其中todo-item是组件名称。组件名称将在消费处用作标签名。组件的使用如下所示:
<todo-item
v-for="item in groceryList"
v-bind:todo="item"
v-bind:key="item.id"
></todo-item>
通过Vue.component注册的组件都是全局注册的。一旦注册,在任何地方都可以使用。
运行效果:
鉴于组件要复用,每个组件在项目中是唯一的,所以组件的data必须是一个返回临时对象的函数。
在上面的示例中,父组件使用通过prop向子组件传递数据。todo是自定义组件todo-item的一个属性。
每个组件必须只有一个根元素。
为什么?
这是为了省略el设置,让开发变得简单简洁。初始化第一个vue实例的代码往往是这样的:
let vm = new Vue({
el:'#app'
...
})
el指定的#app
是html dom
的id:
<body>
<div id='app'></div>
</body>
每个vue
组件都是一个参数不同的vue
实例,那么为什么单页面组件或自定义组件不需要指定el呢?因为template
下默认第一个html
元素,就是el。
在html5
中,template
这个标签是没有内容的,它的innerHTML属性取到的唯一的html
标签组件的id
,就是组件的el
。
在子组件中可以通过$emit
派发事件:
Vue.component('todo-item', {
data:()=>({}),
props: ['todo'],
template: `<div>
<button @click="$emit('enlarge',1)">
Enlarge text
</button>
<li>{{todo.text}}</li>
</div>`
})
$emit
是vue
实例本身具备的方法,$emit('enlarge',1)
代表派发一个名称为enlarge
的事件,参数为1。
在父组件中,通过v-on:xxx
或@xxx
监听事件,@xxx
是v-on:xxx
的语法糖:
<todo-item :style="{fontSize:`${fontSize}px`}" @enlarge="fontSize += $event"
v-for="item in groceryList"
v-bind:todo="item"
v-bind:key="item.id"
></todo-item>
其中$event
是在模板中使用特定名称的特定写法,代表事件的第一个参数。
运行效果:
通过$event,可以实现在子组件的事件中向父组件传递参数数据。
有时候需要在父组件中指定子组件的内容,应当怎么处理呢?例如,子组件是一个弱出窗口,窗体内容只有父组件知道。
这种情况下可以使用插槽。如果子组件在布局上有多处是需要消费方定制的,还可以使用具名插槽。例如:
Vue.component('todo-item', {
data:()=>({}),
props: ['todo'],
template: `<div>
<button @click="$emit('enlarge',1)">
Enlarge text
</button>
<li>{{todo.text}}</li>
<slot></slot>
<slot name="time"></slot>
</div>`
})
其中<slot name="time"></slot>
是一个具名插槽。不带名称的<slot></slot>
是默认插槽。默认插槽也有一个名称,叫default。
在父组件中使用:
<todo-item :style="{fontSize:`${fontSize}px`}" @enlarge="fontSize += $event"
v-for="(item,index) in groceryList"
v-bind:todo="item"
v-bind:key="item.id"
>
<template v-slot:time><p style="color:gray">{{new Date().getTime()}}</p></template>
index:{{index+1}}
</todo-item>
使用template标签,当指定v-slot
为time时,填充的是名称为time的具名插槽。对于没有指定的,也没有使用template
标签包裹的,直接放在标签内的,例如index:{{index+1}}
,是直接填充默认插槽的。
运行效果:
有时候需要从菜单中选择一个名称,然后指定渲染某一个组件。除了使用if else方法之外,vue提供了一个动态组件的简便方法:通过给 <component>
元素加一个特殊的 is 特性来实现。例如,对于上面定义的todo-item组件,可以这样动态地使用:
<!-- 动态组件 -->
<component :is="`todo-item`" :todo="{ id: 0, text: '苹果' }"></component>
https://git.code.tencent.com/shiqiaomarong/vue-go-rapiddev-example/tags/v20200113