一.组件讲解
1. 注册组件书写格式
let app = Vue.createApp({...})
app.component (" my-component-name ",{( ... )}
// my-component-name 是你要注册的组件名称
组件名称风格:
- MyButton
- my-button
2.template属性
通过template属性可以定义组件的具体结构样式;
vm.component('my-button',{
template:`
<button>按钮</button>
`
})
vm.mount('#app1');
注意:vm.mount(‘#app1’)一定要在组件注册之后去使用,否则组件不生效;
3.组件如何使用
组件可以像一个普通标签一样,重复使用
<div id="app1" v-cloak>
<my-button></my-button>
<my-button></my-button>
<my-button></my-button>
</div>
组件接受与 Vue.createApp
相同的选项,例如 data、computed、watch、methods 以及生命周期钩子等
。仅有的例外是像 el 这样根实例特有的选项。(el是vue2的语法,绑定根节点)
重复使用组件时,每个组件都会维护自己的属性,因为你每用一次组件,就会有一个它的新实例被创建
二.组件的两种注册方式
1.全局注册
vm.component('my-button',{
template:`
<button>按钮</button>
`
})
vm.mount('#app1');
全局组件可以任何组件实例中使用,不管是局部组件还是全局组件;
vm.component('my-from',{
template:`
<input type='text' >
<my-button></my-button>
`
})
全局注册往往是不够理想的。比如,如果你使用一个像 webpack 这样的构建系统,全局注册所有的组件意味着即便你已经不再使用一个组件了,它仍然会被包含在你最终的构建结果中。这造成了用户下载的 JavaScript 的无谓的增加。
可以通过注册局部组件来避免此问题;
2. 局部注册
局部注册组件通过在实例中使用components属性注册:
let vm = Vue.createApp({
data(){
return {
}
},
components:{
' my-btn ' : {
template:`
<button @click=" count++ ">{{ count }}</button>
`,
data(){
return{
count:1
}
}
}
}
})
局部组件组测方式推荐:
- 第一种:
let ComponentA={
/*...*/
}
let ComponentB={
/*...*/
}
let ComponentC={
/*...*/
}
- 第二种:
let app = Vue.createApp({
components:{
'componenr-a': ComponentA,
'componenr-b': ComponentB,
}
})
局部组件在全局组件和其他局部组件中不可用;除非你把局部组件又注册到其他组件中
let conA = {
template:`
<button @click=" count++ ">{{ count }}</button>
`,
data(){
return{
count:1
}
}
}
let conB = {
component:{
'my-button':conA
},
template:`
<input typr='text'>
<my-button></my-button>
`,
}
三. 组件传值
1. 通过 Prop 向子组件传递数据:
当定义好一个组件之后,如果不能动态改变组件的一些数据,那么组件将变得十分笨重,通过prop属性,可以实现向组件传值的功能;
<div id="app">
<blog-post title="Hy journeywith Vue"></blog-post>
<blog-post title="Blogging with Vue"></blog-post>
<blog-post title="Why Vue is so fun"></blog-post></div>
const app =Vue.createApp({})
app.component('blog-post',{
props:['title'],
template:`
<h4>{{title }}</h4>
`
})
app.mount('#app')
一个组件默认可以拥有任意数量的 prop,任何值都可以传递给任何 prop。
在组件实例中访问这个值,就像访问 data 中的值一样。
当然, 可以使用 v-bind 来动态传递 prop。
<blog-post :title="Why Vue is so fun"></blog-post></div>
2. prop的使用:
1.这个 prop 用来传递一个初始值;这个子组件接下来希望将其作为一个本地的 prop 数据来使用。在这种情况下,最好定义一个本地的 data property 并将这个 prop 作为其初始值:
props:['count'],
template:`
<button @click='counter++'>{{counter}}</button>
`
data(){
return {
counter :this.count
}
}
2.这个 prop 以一种原始的值传入且需要进行转换。在这种情况下,最好使用这个 prop 的值来定义一个计算属性:
props:['size'],
computed:{
normalizedsize:function(){
return this.size.trim().toLowerCase()
}
}
注意:在 JavaScript 中对象和数组是通过引用传入的,所以对于一个数组或对象类型的 prop 来说,在子组件中改变这个对象或数组的元素将会影响到父组件的状态。
3. prop类型:
字符串数组形式:
props:['title','likes','isPublished','commentIds','author']
对象形式:
props:{
title:String,
likes:Number,
isPublished:BooLean,
commentIds:Array,
author:Object
},
4. prop验证:
通过定义prop类型,可以完成类型上的检测;当然,除了类型检测,prop还可以完成一些其他的验证:
//基本的类型检验('null' 和 'undefined' 会通过任何类型验证)
propA:Number,
// 多个可能的类型
porpB:[String,Number],
// 必填的字符串
porpC:{
type:String,
required:true
},
// 带默认值的对象
porpE:{
type:Object,
// 对象或数组默认是从一个工具函数获取
default:function(){
return { message:'hello' }
}
}
//自定义验证函数
propF:{
validator:function(value){
//这个值必须匹配下列字符串中的一个
return ['success','warning','danger'].indexof(value)!==-1
}
},
只有return的结果为true时,验证才能通过
5. 非prop的属性:
一个非 prop 的 attribute 是指传向一个组件,但是该组件并没有相应 props 或 emits 定义的属性。常见的示例包括 class、style 和 id 属性。
当组件返回单个根节点时(组件中的所有元素包含在一个根节点中),非 prop 属性将自动添加到根节点的属性中,这种现象称为属性继承;
<my-button :count='test'class='bk'></my-button>
//prop并没有接受class属性
props:['count'],
template:`
<div>
<button @click='change'>{{count()}}</button>
</div>
`
<div class='bk'>...</div>
你可以在组件的选项中设置 inheritAttrs: false
,禁用属性继承;
使用场景: 禁用属性继承的常见情况是需要将属性应用于根节点之外的其他元素; 例:对于上面的案例,比如像把bk类加到按钮上,而不是包括按钮的div;
解决办法: 通过组件的 $attrs 属性,可以获取组件 props 和 emits 属性中未包含的其他属性;
<my-button :count='test'class='bk'></my-button>
vm.component('my-button',{
inheritAttrs:false,
//prop并没有接受class属性
props:['count'],
template:`
<div>
<button @click='show()' v-bind="$attrs">按钮</button>
</div>
`,
methods:{
show(){
console.log(this.$attrs);
}
}
})
四. 组件自定义事件:
- 在组件标签上自定义一个事件:
<my-btns @change-color='changeCol'></my-btns>
如果在组件上自定义事件之后,要像prop接收属性一样,通过emits接收(声明)一下此事件;
emits:['change-color']
changeCol是父组件的函数,可以通过此函数完成业务逻辑需求;
2. 在子组件上自定义普通事件,然后通过$emit()触发自定义事件:
<button v-for='item in items'@click="$emit('change-color',item)">{{item}}</button>
$emit('自定义事件','可选性的传递第二个参数');
第二个参数会直接传递到父组件的methods方法中,所以就像接收普通参数一样使用就可以;
注意:如果自定义事件不是一个函数,而是一段js逻辑,可以通过
e
m
i
t
(
)
的第二个参数传值,但是接收时,直接通过
emit()的第二个参数传值,但是接收时,直接通过
emit()的第二个参数传值,但是接收时,直接通过event接收(只能接受一个参数);
<my-btns @change-number='count+=$event'></my-btns>{{count}}
<button v-for='item in items'@click="$emit('change-
number',2)">{{item}}</button>
如果你的函数逻辑写成内联写法,还可以在内联函数位置定义一个函数,用于接收多个参数的情况:
@father-add="(num1,num2)=>{count =num1}"