有时候有一组html结构的代码,并且这个上面可能还绑定了事件。然后这段代码可能有多个地方都被使用到了,如果都是拷贝来拷贝去,很多代码都是重复的,包括事件部分的代码都是重复的。那么这时候我们就可以把这些代码封装成一个组件,以后在使用的时候就跟使用普通的html元素一样,拿过来用就可以了。
##基本使用
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div id="app">
<div>
<button-counter></button-counter>
<button-counter></button-counter>
<button-counter></button-counter>
</div>
</div>
</body>
</html>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
Vue.component('button-counter',{
template:'<button v-on:click="count+=1">点击了{{ count }}次</button>',
data:function(){
return {
count: 0
}
}
});
new Vue({
el:"#app",
data:{
}
})
</script>
以上我们创建了一个叫做button-counter的组件,这个组件实现了能够记录点击了多少次按钮的功能。后期如果我们想要使用,就直接通过button-counter使用就可以了。然后因为组件是可复用的Vue实例,所以它们与new Vue接收相同的选项,例如data、computed、watch、methods以及生命周期钩子等。仅有的例外是像el这样根实例特有的选项。另外需要注意的是:组件中的data必须为一个函数!
##给组件添加属性 像原始的html元素都有自己的一些属性,而我们自己创建的组件,也可以通过prop来添加自己的属性。这样别人在使用你创建的组件的时候就可以传递不同的参数了.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div id="app">
<div>
<book-list v-bind:books="books"></book-list>
</div>
</div>
</body>
</html>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
Vue.component("book-list",{
props:['books'],
template:`
<table>
<tr>
<th>序号</th>
<th>标题</th>
</tr>
<tr v-for="(book,index) in books">
<td>{{index+1}}</td>
<td>{{book.title}}</td>
</tr>
</table>
`
})
new Vue({
el:"#app",
data:{
books:[
{"title":"python","id":1},
{"title":"php","id":2},
{"title":"java","id":3},
]
}
})
</script>
##单一根元素 如果自定义的组件中,会出现很多html元素,那么根元素必须只能有一个,其余的元素必须包含在这个根元素中。比如以下是一个组件中的代码,会报错:
<h3>{{ title }}</h3>
<div v-html="content"></div>
我们应该改成:
<div class="blog-post">
<h3>{{ title }}</h3>
<div v-html="content"></div>
</div>
##子组件事件和传递事件到父组件 子组件中添加事件跟之前的方式是一样的,然后如果发生某个事件后想要通知父组件,那么可以使用this.$emit函数来实现。
<div id="app">
<blog-item v-for="blog in blogs" v-bind:blog="blog" @check-changed="checks"></blog-item>
<div v-for="blog in componentblog">
{{blog.title}}
</div>
</div>
<script>
Vue.component('blog-item',{
props:['blog'],
template:`
<div>
<span>{{blog.title}}</span>
<input type="checkbox" @click="onCheck">
</div>
`,
methods:{
onCheck:function(){
// console.log(123)
this.$emit('check-changed',this.blog)
}
}
})
new Vue({
el: '#app',
data: {
blogs:[
{"title":"钢铁是怎样练成的?","id":1},
{"title":"AI会毁灭人类吗?","id":2},
{"title":"如何学好Vue!","id":3},
],
componentblog:[]
},
methods:{
checks:function(blog){
// indexOf 判断某个元素在数组中的位置,返回下标
var index = this.componentblog.indexOf(blog)
if(index >= 0){
this.componentblog.splice(index,1)
}else{
this.componentblog.push(blog)
}
console.log(blog)
}
}
})
</script>
##自定义组件v-model 一个组件上的v-model默认会利用名为value的prop(属性)和名为input的事件,但是像单选框、复选框等类型的输入控件可能会将value特性用于不同的目的。这时候我们可以在定义组件的时候,通过设置model选项可以用来实现不同的处理方式
<div id="app">
<stepper v-model:value="goods_count"></stepper>
</div>
<script>
Vue.component('stepper',{
props:['count'],
model:{
event: 'count-changed',
prop: "count"
},
template:`
<div>
<button @click="sub">-</button>
<span>{{count}}</span>
<button @click="add">+</button>
</div>
`,
methods:{
sub:function(){
this.$emit("count-changed", this.count-1)
},
add:function(){
this.$emit("count-changed", this.count+1)
}
}
});
new Vue({
el: "#app",
data:{
"goods_count":0
}
})
</script>
##插槽 我们定义完一个组件后,可能在使用的时候还需要往这个组件中插入新的元素或者文本。这时候就可以使用插槽来实现。
<div id="app">
<navigation-link url="/profile/">
个人中心
</navigation-link>
</div>
<script>
Vue.component('navigation-link', {
props: ['url'],
template: `
<a v-bind:href="url" class="nav-link">
<slot></slot>
</a>
`
})
new Vue({
el: "#app"
});
</script>
同时,可以给插槽命名