基本demo
// 定义一个名为 button-counter 的新组件
Vue.component('button-counter', {
data: function () {
return {
count: 0
}
},
template: '<button v-on:click="count++">You clicked me {{ count }} times.</button>'
})
组件是可复用的 Vue 实例,且带有一个名字:在这个例子中是 <button-counter>。我们可以在一个通过 new Vue 创建的 Vue 根实例中,把这个组件作为自定义元素来使用:
<div id="components-demo">
<button-counter></button-counter>
</div>
new Vue({ el: '#components-demo' })
因为组件是可复用的 Vue 实例,所以它们与 new Vue 接收相同的选项,例如 data、computed、watch、methods 以及生命周期钩子等。仅有的例外是像 el 这样根实例特有的选项。
组件的复用
我们可以将组件进行任意次数的复用
<div id="components-demo">
<button-counter></button-counter>
<button-counter></button-counter>
<button-counter></button-counter>
</div>
注意当点击按钮时,每个组件都会各自独立维护它的 count。因为你每用一次组件,就会有一个它的新实例被创建。
组件的组织
通常一个应用会以一个嵌套的组件树的形式来组织。
例如,你可能会有页头,页脚,侧边栏等区域。
为了能够在模板中使用,这些组件必须先调用引入,然后再进行注册来让vue识别。这里有2种组件的注册类型:全局注册和局部注册
通过props向子组件传递数据
如果创建一个博文组件。问题是如果你不能向这个组件传递某一篇博文的标题或内容之类的我们想展示的数据的话,它是没有办法使用的。这也正是 prop 的由来。
props
是你在组件上注册一些自定义的特性,当一个值传递给一个prop
特性的时候,就变成了组件实例的一个属性。
<blog-post title="My journey with Vue"></blog-post>
<blog-post title="Blogging with Vue"></blog-post>
<blog-post title="Why Vue is so fun"></blog-post>
Vue.component('blog-post', {
props: ['title'],
template: '<h3>{{ title }}</h3>'
//这里的{{title}}就获取了组件title属性穿过来到props中的值,再去props中获取
})
一个组件默认可以拥有任意数量的 prop
,任何值都可以传递给任何 prop
。在上述模板中,你会发现我们能够在组件实例中访问这个值,就像访问 data
中的值一样。
一个 prop
被注册之后,你就可以像这样把数据作为一个自定义特性传递进来。
父组件
<div id="app">
<test :msg="childmsg" @parentevent="pevent"></test>
</div>
<script>
import test from './components/test'
export default {
name: 'App',
data(){
return{
msg:'',
childmsg:'这是传递给子组件的内容'
}
},
methods:{
pevent(){
console.log('这是子组件沟通父组件调用的父组件事件')
}
},
computed:{
},
components:{
test
}
}
</script>
子组件
<template>
<div class="test">
{{msg}}
<p @click="tryclick">点击试试</p>
</div>
</template>
<script>
export default{
props:['msg'],
data(){
return{
}
},
created(){
},
methods:{
tryclick(){
this.$emit('parentevent');
}
}
}
</script>
解释:
父组件中引用,声明,并且调用子组件,
然后在test子组件上,动态绑定 msg
,msg
的值为childmsg
,childmsg
的值在data
中。
子组件中接收props
,props
中接收msg
属性,然后获得childmsg
。
单个根元素
组件必须包含一个根元素在最外层。否则会提示
通过事件向父级组件发送消息
我们开发组件的时候,可能要求组件和父级组件进行沟通。
由子组件向父组件沟通的事件为:emit
我们可以调用内建的 $emit
方法并传入事件的名字,来向父级组件触发一个事件:
还是以之前的代码的例子作解释:
子组件p标签绑定点击事件,点击事件中触发
this.$emit('parentevent','hello');
第一个参数为父组件的事件名,第二个为可选信息参数
<test :msg="childmsg" @parentevent="pevent"></test>
父组件中绑定改事件的方法名:@parentevent,然后在绑定父组件中的方法,调用pevent。
这样就实现了,子组件调用父组件方法的过程。
在组件上使用v-model
自定义事件也可以用于创建输入 v-model 自定义输入组件。
<input v-model="searchText">
等价于:
<input
v-bind:value="searchText"
v-on:input="searchText = $event.target.value"
>
当在组件上使用 v-model时
<custom-input
v-bind:value="searchText"
v-on:input="searchText = $event"
></custom-input>
通过插槽分发内容
和HTML元素一样,我经常需要向一个组件出阿尼的内容。
<alert-box>
Something bad happened.
</alert-box>
然而直接在 组件的标签中写内容并不会生效,
vue中有一个自定义的 slot
元素可以解决这个问题。
父组件
<div id="app">
<test :msg="childmsg" @parentevent="pevent">1234567</test>
</div>
子组件
<div class="test">
{{msg}}
<p @click="tryclick">点击试试</p>
<slot></slot>
</div>
父组件中在组件标签内添加了文本,我们想要在子组件中的特定的地方显示出来。
只需要在子组件中使用<slot>
标签即可。对应的内容会显示在<slot>
标签内。这就是所谓的插槽。
到目前为止,关于插槽你需要了解的大概就这些了,如果你阅读完本页内容并掌握了它的内容,我们会推荐你再回来把插槽读完。
动态组件
有的时候,在不同组件之间进行动态切换是非常有用的,比如在一个多标签的界面里:
上述内容可以通过 Vue 的 <component> 元素加一个特殊的 is 特性来实现:
<!-- 组件会在 `currentTabComponent` 改变时改变 -->
<component v-bind:is="currentTabComponent"></component>
其中绑定的变量 currentTabComponent 在通过计算属性更改就行了。
在上述示例中,currentTabComponent 可以包括
已注册组件的名字,或一个组件的选项对象
可以在这里查阅并体验完整的代码,或在这个版本了解绑定组件选项对象,而不是已注册组件名的示例。
到目前为止,关于动态组件你需要了解的大概就这些了,如果你阅读完本页内容并掌握了它的内容,我们会推荐你再回来把动态和异步组件读完。
解析dom模板时的注意事项
有些 HTML 元素,诸如<ul>
、<ol>
、<table>
和 <select>
,对于哪些元素可以出现在其内部是有严格限制的。而有些元素,诸如 <li>
、<tr>
和 <option>
,只能出现在其它某些特定的元素内部。
因为如上的规则,会导致我们使用的时候有一些约束,
例如:
<table>
<blog-post-row></blog-post-row>
</table>
这样肯定是不可行的。
这个自定义组件 <blog-post-row> 会被作为无效的内容提升到外部,并导致最终渲染结果出错。幸好这个特殊的 is 特性给了我们一个变通的办法:
<table>
<tr is="blog-post-row"></tr>
</table>
遇到这情况,我们还是按规定写tr标签,带一个 is
属性,把我们的组件名字当做值传入即可。这样也能够渲染组件的内容。