一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第 6 天,点击查看活动详情。
组件含义
在 Vue 里,一个组件本质上是一个拥有预定义选项的一个 Vue 实例。
组件注册
Vue.component(name, options)可用于注册组件。
Vue.component('component-name', { /* ... */ })
-
组件命名
组件最好使用kebab-case (短横线分隔命名)的方式;
规范中:html标记和属性名称不区分大小写,XHTML标记和属性名称区分大小写,并且必须小写;
推荐遵循 W3C 规范中的自定义组件名 (字母全小写且必须包含一个连字符),避免和当前以及未来的 HTML 元素相冲突
数据传递
父子组件传递数据 -- props
```html
<!--在父组件中,自定义attribute ,将数据传递给子组件-->
<course-list :courses="courses"></course-list>
```
```js
// 在子组件中,可以用一个 props 选项将其包含在该组件可接受的 prop 列表中;
// props可以是一个数组,推荐使用对象形式,可以对prop类型验证等。
props: {
courses: {
type: Array,
default: []
}
},
```
自定义事件及其监听
当子组件需要和父级组件进行通信,可以派发并监听自定义事件。-- $emit
```html
<!--父组件中监听事件-->
<!--推荐html标签属性全小写-->
<course-add @add-course="addCourse"></course-add>
```
```js
data() {
return: {
course: ''
}
}
methods: {
// 在子组件中派发事件,通知父组件
addCourse() {
// 大小写应与html中的相匹配
this.$emit('add-course', this.course)
},
}
```
自定义组件实现双绑
使用v-model,v-model实际就是个语法糖,等价于:value➕@input
将数据值交给父组件掌控:
```html
<!--父组件使用子组件,使用v-model-->
<!--v-model="course" 就等价于 :value = "course" ➕ @input="course=$event"-->
<course-add v-model="course" @add-course="addCourse"></course-add>
```
```js
// 自定义组件支持v-model需要实现内部input的:value和@input
Vue.component('course-add', {
props:['value'],
template: `
<div>
<input type="text" :value="value" @input="handleInput" @keydown.enter="addCourse">
<button @click="addCourse">添加课程</button>
</div>
`,
methods: {
addCourse() {
this.$emit('add-course')
},
handleInput(e) {
console.log(e)
this.$emit('input', e.target.value)
}
}
})
```
插槽
将 <slot> 元素作为承载分发内容的出口
自定义的组件,可以当做html标签一样使用,标签内包含的内容,可以通过<slot>元素,将标签包含的内容与自定义组件本身合成
比如上面使用的组件都是这样的:标签内部并没有其他内容
<course-add @add-course="addCourse"></course-add>
<course-list :courses="courses"></course-list>
现在如果我们在标签内添加内容如何展示呢?
如:实现一个提示信息弹框,提示信息由父组件决定(谁用谁决定)
<!--父组件使用-->
<!-- 插槽 提示框 -->
<message :isshow="isShow" @close="isShow = $event"> 添加课程成功!
</message>
// message组件
// 提示框
Vue.component('message', {
props: ['isshow'],
template: `
<div v-show='isshow' class="message-box">
<slot/>
<span class="message-box-close" @click="close"> X </span>
</div>
`,
methods: {
close() {
this.$emit('close', false)
},
}
})
如果上面message组件中没有使用slot元素,那么使用该组件时,其开始到结束标签内的所有内容都会被抛弃。
通过.sync修饰符可以简化
<!--v-show.sync="isShow"相当于 :isshow="isShow" 加上 @update:isshow="isShow=$event"-->
<message :isshow.sync="isShow"> 添加课程成功!</message>
直接$emit规定好的update:myPropName,也就是 update:isshow
Vue.component('message', {
props: ['isshow'],
template: `
<div v-show='isshow' class="message-box">
<slot/>
<span class="message-box-close" @click="$emit('update:isshow', false)"> X </span>
</div>
`,
})
具名插槽
把指定的内容放到指定的内容
<message :isshow.sync="isShow">
<template v-slot:header>
巴啦啦小魔仙全身变
</template>
添加课程成功!
<template v-slot:footer>
不积跬步无以至千里
</template>
<div>测试其他的</div>
</message>
Vue.component('message', {
props: ['isshow'],
template: `
<div v-show='isshow' class="message-box">
<slot name='header'/>
<slot/>
<span class="message-box-close" @click="$emit('update:isshow', false)"> X </span>
<slot name='footer'/>
</div>
`,
})
指定名字的内容会在对应名字的地方显示,不带名字的默认显示在slot中,一个不带 name 的 <slot> 出口会带有隐含的名字“default”。
作用域插槽
让插槽内容能够访问子组件中才有的数据
- 使用方式
- 在
<slot>元素上绑定 attribute,这个绑定在<slot>元素上的 attribute 被称为插槽 prop
// 组件
Vue.component('message', {
props: ['isshow'],
data() {
return {
title: '提示'
}
},
template: `
<div v-show='isshow' class="message-box">
<slot :title='title'/>
</div>
`,
})
- 在父级作用域中,我们可以使用带值的
v-slot来定义我们提供的插槽prop的名字
// 父级
<message :isshow.sync="isShow">
<template v-slot:default="data">
{{ data.title }}
</template>
</message>
- 当且仅当被提供的内容只有默认插槽时,组件的标签可以被当作插槽的模板来使用,且可以直接简写成不带参数的 v-slot
<message :isshow.sync="isShow" v-slot:default="data">
{{ data.title }}
</message>
<message :isshow.sync="isShow" v-slot="data">
{{ data.title }}
</message>
- 默认插槽的缩写语法不能和具名插槽混用,它会导致作用域不明确
<message :isshow.sync="isShow" v-slot:default="data">
{{ data.title }}
<template v-slot:other="other">
slotProps is NOT available here
</template>
</message>
- 只要出现多个插槽,请始终为所有的插槽使用完整的基于
<template>的语法
<message :isshow.sync="isShow" v-slot:default="data">
<template v-slot:default="data">
{{ data.title }}
</template>
<template v-slot:other="other">
slotProps is NOT available here
</template>
</message>
动态组件
通过 Vue 的
<component>元素加一个特殊的 is attribute 来实现
vue组件化的理解
- 定义 组件是可复用的 Vue 实例,准确讲它们是VueComponent的实例,继承自Vue
- 优点 组件化可以增加代码的复用性、可维护性和可测试性。
- 使用场景
- 通用组件:实现最基本的功能,具有通用性、复用性,例如按钮组件、输入框组件、布局组件等。
- 业务组件:它们完成具体业务,具有一定的复用性,例如登录组件、轮播图组件。
- 页面组件:组织应用各部分独立内容,需要时在不同页面组件间切换,例如列表页、详情页组件
- 如何使用
- 定义:
Vue.component(),components选项,sfc - 分类:有状态组件,functional,abstract
- 通信:props,on(),provide/inject,parent/attrs/$listeners
- 内容分发:
<slot>,<template>,v-slot - 使用及优化:is,keep-alive,异步组件
- 定义:
vue中的组件经历如下过程 组件配置 => VueComponent实例 => render() => Virtual DOM=> DOM 所以组件的本质是产生虚拟DOM