# 组件基础
# 基本示例
组件是可复用的,需要在Vue实例里面使用,组件除了没有el等特殊选项,其他的选项都可以使用:比如 computed、watch、methods
<div id="app">
<button-counter></button-counter>
<button-counter></button-counter>
<button-counter></button-counter>
</div>
<script>
Vue.component('button-counter', {
data: function() {
return {
count: 0
}
},
template: '<button @click="count++">点击了{{ count }}次</button>'
})
var vm = new Vue({
el: '#app',
data: {
}
})
</script>
# 组件内部的data需要用函数包裹
如果不用函数包裹,组件复用时,多个组件会共享一个data。用闭包后,每个组件的data都是一块独立的区域
data: function() {
return {
count: 0
}
},
# 通过props向组件内部传值
<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>
<script>
Vue.component('blog-post', {
props: ['title'],
template: '<h3>{{ title }}</h3>'
})
</script>
传入的属性可以是动态的值,用v-for获取博客列表
<!-- <ul><li id="t1">标题1</li><li id="t2">标题2</li><li id="t3">标题3</li></ul> -->
<div id="app">
<ul>
<blog-list
v-for="item in blogs"
:title="item.title"
:key="item.id"
:index="item.id"
></blog-list>
</ul>
</div>
<script>
Vue.component('blog-list', {
props: ['title', 'index'],
template: `<li :id="'t'+index">{{ title }}</li>`
})
var vm = new Vue({
el: '#app',
data: {
blogs: [
{ id: 1, title: '标题1' },
{ id: 2, title: '标题2' },
{ id: 3, title: '标题3' },
]
}
})
</script>
# 向组件内部传入一个对象
<blog-post
v-for="post in posts"
v-bind:key="post.id"
v-bind:post="post"
></blog-post>
<script>
Vue.component('blog-post', {
props: ['post'],
template: `
<div class="blog-post">
<h3>{{ post.title }}</h3>
<div v-html="post.content"></div>
</div>
`
})
</script>
# 使用组件时,监听组件内部的事件
在使用组件时,传入对应事件名称,以及事件处理函数。子组件内部使用$emit('事件名称'),即可触发事件处理函数,注意: 为遵循HTML规范,事件名称需要是小写。
<!-- 使用组件 -->
<blog-list @事件名称="对应事件处理函数">
<!-- 组件内部 -->
<button @click="$emit('事件名称', 参数)">将事件传到组件外部处理</button>
实例
<div id="app">
<ul>
<blog-list
v-for="item in blogs"
:title="item.title"
:key="item.id"
:index="item.id"
@sendmsg="sendMsg"
></blog-list>
<!--
如果sendmsg是内嵌js写法,可以用$event获取传过来的值
@sendmsg="count += $evnet"
-->
</ul>
</div>
<script>
Vue.component('blog-list', {
props: ['title', 'index'],
data: function() {
return {
name: '我是组件内部的变量'
}
},
template: `
<li :id="'t'+index">
{{ title }}
<button @click="greet">触发组件自己的方法</button>
<button @click="$emit('sendmsg', name)">触发组件外部的方法</button>
</li>
`,
methods: {
greet: function() {
alert('Hello')
}
}
})
var vm = new Vue({
el: '#app',
data: {
blogs: [
{ id: 1, title: '标题1' },
{ id: 2, title: '标题2' },
{ id: 3, title: '标题3' },
],
count: 0
},
methods: {
sendMsg: function(name) {
alert('接收到组件的的值:'+ name);
}
}
})
</script>
# 在组件上使用v-model
<input v-model="searchText">
<!-- 等价于 -->
<input :value="searchText" @input="searchText=$event.target.value">
<!-- v-model用在子组件上时 -->
<custom-input
v-bind:value="searchText"
v-on:input="searchText = $event"
></custom-input>
<script>
Vue.component('custom-input', {
props: ['value'],
template: `
<input
v-bind:value="value"
v-on:input="$emit('input', $event.target.value)"
>
`
})
</script>
# 通过插槽分发内容
之前一直没用到自定义组件的元素内容,其实在组件内部可以通过插槽来获取内容
<!-- 自定义组件 alert-box -->
<alert-box>这里面是自定义组件元素内容</alert-box>
<script>
Vue.component('alert-box', {
template: `
<div class="demo-alert-box">
<strong>Error!</strong>
<slot></slot>
</div>
`
})
</script>
<!-- 自定义元素内容会覆盖到组件的<slot></slot>位置
<div class="demo-alert-box">
<strong>Error!</strong>
这里面是自定义组件元素内容
</div>
-->
# 解析DOM模板时注意事项
HTML元素对于子元素有限制,比如ul的子元素只能是li,table的子元素需要是thead或tr等,如果使用了自定义组件,会被作为无效的内容提升到外部,并导致最终渲染结果出错,可以使用is来解决这个问题
<!-- 在.html里会出错 -->
<table>
<blog-post-row></blog-post-row>
</table>
<!-- 替代写法-->
<table>
<tr is="blog-post-row"></tr>
</table>
注意: 如果从以下来源使用模板的话,这条限制是不存在的:
- 字符串 (例如:template: '...')
- 单文件组件 (.vue)
- <script type="text/x-template">