一、自定义组件
1、局部注册
局部注册的组件,只能在当前的Vue实例中使用,并且在其子组件中不可以使用。
在components选项中定义局部组件,每个组件就是一个小型的Vue实例,它里面除了不能设置el选项,其他的它都有。
组件名称:自定义,可以使用驼峰命名的方式或者短横线的命名方式,但是需要注意的是,如果需要应用到DOM中,就只能用短横线的方式命名,否则就会报错。注意组件的名称不要和原生HTML元素重名。
template选项:定义组件的模板,模板中必须包含一个根标签。
props选项:定义组件标签上的属性。驼峰命名法需要使用等价的短横线分隔命名法命名。注意:props是只读的,不能修改。解决办法:在data中对props接收到的数据进行中转。
props的值可以是一个字符串数组,里面定义每一个标签属性名称,这是简单用法,不能对属性做严格的验证。例如:props:["count"]
props的值也可以是一个对象,里面定义的每个标签属性名称也可以是一个对象,对象里面定义该属性的完整信息。type定义类型,required非空,default默认值,props:{ label: {type: String,required: false,}}
data:定义组件的数据,注意:Vue实例的data选项可以是一个对象,也可以是一个方法。由该方法返回一个对象,但是在组件中,data选项必须是一个方法,由该方法返回一个对象,因为组件可能会使用很多次,如果data选项是对象的话,会导致多个组件使用同一个对象。
<div id="app">
<b-box v-for="(item,index) in list" :key='index' :title='item.title' :content='item.content'></b-box>
</div>
<script src='https://cdn.bootcdn.net/ajax/libs/vue/2.6.14/vue.js'></script>
<script>
Vue.config.productionTip = false
new Vue({
//指定vue实例挂载的容器
el: '#app',
//定义数据
data: {
list: [
{
title: '奔驰',
content: '作为汽车发明者,梅赛德斯-奔驰拥有134年的辉煌历史,如今三叉星徽广布中国大地。2017年,中国成为梅赛德斯-奔驰全球首个突破60万年销量大关的单一市场。面向未来,梅赛德斯-奔驰也将一如既往地为广大的中国消费者献上出众的产品、服务以及品牌体验,实现对中国市场的长期承诺。同时,梅赛德斯-奔驰将通过梅赛德斯-奔驰星愿基金持续践行企业社会责任,积极投身于诸多社会公益事业,助力中国社会的健康、可持续发展。'
},
{
title: '宝马',
content: '作为汽车发明者,梅赛德斯-奔驰拥有134年的辉煌历史,如今三叉星徽广布中国大地。2017年,中国成为梅赛德斯-奔驰全球首个突破60万年销量大关的单一市场。面向未来,梅赛德斯-奔驰也将一如既往地为广大的中国消费者献上出众的产品、服务以及品牌体验,实现对中国市场的长期承诺。同时,梅赛德斯-奔驰将通过梅赛德斯-奔驰星愿基金持续践行企业社会责任,积极投身于诸多社会公益事业,助力中国社会的健康、可持续发展。'
},
{
title: '奥迪',
content: '作为汽车发明者,梅赛德斯-奔驰拥有134年的辉煌历史,如今三叉星徽广布中国大地。2017年,中国成为梅赛德斯-奔驰全球首个突破60万年销量大关的单一市场。面向未来,梅赛德斯-奔驰也将一如既往地为广大的中国消费者献上出众的产品、服务以及品牌体验,实现对中国市场的长期承诺。同时,梅赛德斯-奔驰将通过梅赛德斯-奔驰星愿基金持续践行企业社会责任,积极投身于诸多社会公益事业,助力中国社会的健康、可持续发展。'
}
]
},
//定义组件
components: {
//每个组件就是一个小型的vue实例,她里面除了不能设置el选项,其他选项她都有
'b-box': {
//使用template选项,定义组件的模板,注意:模板中必须包含一个根标签
template: `<div class='box'>
<h2 class="title">{{title}}</h2>
<div class="content">
{{content}}
</div>
</div>`,
//定义组件的属性
props: ['title', 'content']
}
}
})
</script>
2、全局注册
全局注册的组件可以用在任何新创建的Vue根实例的模板中。
使用Vue.component来创建全局组件。Vue.component的第一个参数就是组件名。
<div id="app">
<ul>
<li v-for='(item,index) in list' :key='index'>{{item.title}}--{{item.value}}</li>
</ul>
<b-star v-for='(item,index) in list' :key='index' :title='item.title' :value='item.value' @syncvalue='syncvalue(index,$event)'></b-star>
</div>
<script src='https://cdn.bootcdn.net/ajax/libs/vue/2.6.14/vue.js'></script>
<script>
Vue.config.productionTip = false
//注册全局组件
Vue.component('b-star', {
//模板
template:`
<div class="star">
<div class="label">{{title}}</div>
<div>
<i v-for='item in 10' :key='item' class='iconfont' :class='item<=myValue?"icon-xingxing":"icon-star"'
@mouseenter='enter(item)' @mouseleave='leave(item)' @click='okValue=item'></i>
</div>
</div>
`,
//属性
props:{
title:{
type:String,
required:false
},
value:{
type:Number,
default:0
}
},
//数据
data() {
return {
//中转props传递来的value值
myValue:this.value,
okValue:this.value
}
},
//方法
methods: {
enter(val){
this.myValue=val
},
leave(val){
this.myValue=this.okValue
}
},
//监听器
watch:{
okValue(val){
this.$emit('syncvalue',val)
}
}
})
new Vue({
el:"#app",
data:{
list:[
{
title:'产品质量',
value:5
},
{
title:'物流速度',
value:3
},
{
title:'售后服务',
value:6
}
]
},
methods: {
syncvalue(index,e){
this.list[index].value=e
}
},
})
</script>
二、自定义事件$emit()
$emit()用于触发自定义事件,注意:事件名称中不能采用大写字母。
<div id="app">
<ul class="list">
<li v-for='(item,index) in list' :key='index'>{{item.label}}--{{item.count}}</li>
</ul>
<b-counter v-for='(item,index) in list' :key='index' :label='item.label' :count='item.count'
@synccount='synccount(index,$event)'></b-counter>
</div>
<script src='https://cdn.bootcdn.net/ajax/libs/vue/2.6.14/vue.js'></script>
<script>
new Vue({
el: '#app',
data: {
list: [
{
label: '衣服:',
count: 5
},
{
label: '鞋子:',
count: 6
},
{
label: '帽子:',
count: 4
},
{
label: '裤子:',
count: 8
},
]
},
methods: {
synccount(index, e) {
//更新数据
this.list[index].count = e
}
},
//定义组件
components: {
'b-counter': {
template: `
<div class="counter">
<div class="label">{{label}}</div>
<div class="btn">
<button @click='myCount--' :disabled='myCount===minCount'>-</button>
<input readonly class="txt" type="text" :value='myCount'>
<button @click='myCount++' :disabled='myCount===maxCount'>+</button>
</div>
</div>`,
//props选项,用于定义组件的属性,有两种方式,1.定义数组 2.定义对象 注意:props是只读的,不能修改
// props:['label','count']
props: {
//类别
label: {
type: String,
//可以为空
required: false,
},
//数量
count: {
type: Number,
//非空
required: true
},
//最大值
maxCount: {
type: Number,
//数量
default: 999
},
//最小值
minCount: {
type: Number,
default: 1
}
},
//定义数据
data() {
return {
//将props接收道德count,中转给mycount
myCount: this.count
}
},
//监听器
watch: {
myCount(val) {
//触发一个自定义事件,事件名称是synccount,将count的最新值作为事件对象传出去。
//注意:自定义事件名称不能使用大写
this.$emit('synccount', val)
}
}
}
}
})
</script>
三、插槽
slot用于在组件的内部定义插槽,组件标签之间的内容,会在slot所在位置显示。
<div id="app">
<b-tab :list='list' :active='activeIndex'>
<h2>全国著名小吃</h2>
<img src="https://img0.baidu.com/it/u=2237317038,4273977910&fm=26&fmt=auto" alt="">
</b-tab>
</div>
<script src='https://cdn.bootcdn.net/ajax/libs/vue/2.6.14/vue.js'></script>
<script>
//组件
Vue.component('b-tab',{
template:`
<div class="tab">
<slot></slot>
<ul class="titles">
<li @click='activeIndex=index' :class='{active:activeIndex===index}' v-for='(item,index) in list' :key='index'>{{item.title}}</li>
</ul>
<ul class="contents">
<li v-show='activeIndex===index' v-for='(item,index) in list' :key="index">{{item.content}}</li>
</ul>
</div>
`,
props:['list','active'],
data(){
return {
activeIndex:this.active
}
}
})
new Vue({
el:'#app',
data:{
activeIndex:0,
list:[
{
title:'北京',
content:'北京的糖葫芦真好吃!'
},
{
title:'南京',
content:'南京的盐水鸭真好吃!'
},
{
title:'成都',
content:'成都的串串香锅真好吃!'
},
{
title:'河南',
content:'河南的胡辣汤真好吃!'
},
]
}
})
</script>