组件化基础
定义全局组件、组件数据传递
<course-list :courses="list"></course-list>
// 定义全局组件
// 组件的名称建议是羊肉串命名法。
// 如果是驼峰命名的话(vue的内部会对名称进行转换),在使用的时候需要使用羊肉串命名的写法,html的标签不区分大小写,所以驼峰写法不会被识别
Vue.component('course-list', {
// 数据传递
props: {
courses: {
type: Array, // 传入数据的类型
default: [] // 如果没有传入的默认值
}
},
data () {
return {
selectedCourse: ''
}
},
// template应该只有一个根元素
template: `
<div>
<p v-if="courses.length == 0">暂无课程数据</p>
<ul v-else>
<li v-for="item in courses" :key="item" :class="{active: item === selectedCourse}" @click="selectedCourse = item">{{item}}</li>
</ul>
</div>
`
})
自定义事件及监听
父子组件进行通信的时候,使用派发和监听自定义事件
使用$emit()
// 派发事件,通知父组件做新增课程 this.$emit('事件名称', 传递参数) 事件名称要考虑到html不区分大小写的问题,所以建议命名是羊肉串的命名
<add-course @add-course="addCourse"></add-course>
// 新增组件
Vue.component('add-course', {
data() {
return {
course: ''
}
},
methods: {
addCourse() {
// 派发事件,通知父组件做新增课程 this.$emit('事件名称', 传递参数) 事件名称要考虑到html不区分大小写的问题,所以建议命名是羊肉串的命名
this.$emit('add-course', this.course)
this.course = ''
}
},
template: `
<div>
<p>
<input type="text" v-model="course" v-on:keyup.enter="addCourse">
<button @click="addCourse">新增</button>
</p>
</div>
`
})
const app = new Vue({
el: '#app',
data: {
title: '购物车',
list: ['大数据', ' web']
},
methods: {
addCourse(course) {
this.list.push(course);
}
}
})
自定义组件实现数据双向绑定(v-model的本质)
自定义组件使用v-model
<!-- 新增组件 -->
<!-- v-model的本质 -->
<!-- v-model="course" 等同于 :value="course" @input="course = $event" $event是固定的名字, $event是传递出来的参数-->
<add-course @add-course="addCourse" :value="course" @input="course = $event"></add-course>
<add-course @add-course="addCourse" v-model="course"></add-course>
// 新增组件
// 让组件本身无状态(即没有数据对象), 会让组件更加的内聚和可复用
Vue.component('add-course', {
/*
props的值可以是数组,也可以是对象
props的值是对象的时候利于接收值的校验
*/
props: ['value'],
methods: {
addCourse (e) {
this.$emit('add-course')
},
onInput (e) {
// 派发自定义事件,并且传参,
// e.target.value 是事件的目标的值
this.$emit('input', e.target.value);
}
},
template: `
<p>
<input type="text" :value="value" @input="onInput" v-on:keyup.enter="addCourse">
<button @click="addCourse">新增</button>
</p>
`
})
插槽
默认插槽
使用<slot>
<!-- 默认插槽 -->
<message :show="show" @close="show = $event">新增成功</message>
// 提示框 --- 默认插槽
Vue.component('message', {
props: ['show'],
template: `
<div v-if="show">
<slot>默认提示</slot>
<span @click="$emit('close', false)">×</span>
</div>
`
})
具名插槽
使用v-slot:名称
和<slot name="名称">
<!-- 具名插槽 -->
<message3 :show.sync="show">
<template v-slot:title>具名插槽title设置的值</template>
<!-- default可以省略 -->
<template v-slot:default>
默认插槽设置的值
<span @click="show = false">×</span>
</template>
</message3>
// 具名插槽
Vue.component('message3', {
props: ['show'],
template: `
<div v-if="show">
<slot name="title">具名插槽名字为title的插槽的默认值</slot>
<!-- default可以省略 -->
<slot name="default">默认插槽的默认文本</slot>
</div>
`
})
作用域插槽
作用域插槽使用场景: 组件外部使用组件内部的值
<!-- 作用域插槽 -->
<message4 :show.sync="show">
<!-- slotProps是组件内部传递的值 -->
<template v-slot:title="slotProps">{{slotProps.title}} ---- message4组件的title值</template>
<template v-slot>
{{title}} --- 当前组件的title值
<span @click="show = false">×</span>
</template>
</message4>
// 作用域插槽
Vue.component('message4', {
props: ['show'],
template: `
<div v-if="show">
<slot name="title" title="message4组件title">具名插槽名字为title的插槽的默认值</slot>
<slot class="default">默认文本</slot>
</div>
`
})
修饰符 .sync
修饰符.sync的使用:show="show" @update:show="show = $event"
等同于:show.sync="show"
<!-- 修饰符sync的使用 -->
<message2 :show="show" @update:show="show = $event">新增成功</message2>
<!-- 上下等同 -->
<message2 :show.sync="show">新增成功</message2>
// 提示框 --- 默认插槽 -- 修饰符sync的使用
Vue.component('message2', {
props: ['show'],
template: `
<div v-if="show">
<slot>默认提示</slot>
<span @click="$emit('update:show', false)">×</span>
</div>
`
})
组件化探讨
vue组件化的理解
组件化是Vue的精髓,Vue应用就是由一个个组件构成的。Vue的组件化涉及到的内容非常多,当面试时被问到:谈一下你对Vue组件化的理解。这时候有可能无从下手,可以从以下几点进行阐述:
组件:高内聚,低耦合,可复用
定义:组件是可复用的Vue实例,准确的将他们是VueComponent的实例,继承自Vue
优点:组件化可以增加代码的复用性、可维护性和可测试性 (简化每个文件的代码)
使用场景:组件的分类
- 通用组件:实现最基本的功能,具有通用性和复用性,例如iview或ElementUI中封装的button等基础组件
- 业务组件:他们完成具体的业务,具有一定的复用性,例如:登录组件、轮播图组件
- 页面组件:组织各部分独立的内容,需要在不同页面组件切换,例如:列表页,详情页
如何使用组件
- 组件定义:Vue.component() -> 全局注册,components选项 -> 局部注册,sfc(single file component)-> 单文件组件
- 分类:有状态的组件(有data数据的组件),functional(无状态组件又称函数组件,即没有data的组件 例如:router-view),abstract(抽象组件, 例如:keep-alive 缓存, transition 动画)
- // functional的组件的性能会有提升
- // 抽象组件是完成一些特定的功能,他是不管视图的
- 通信: props -> 传递属性,$emit/$on -> 传递事件,通过派发事件和监听事件的方式,provide/inject -> 跨层级的组件通信使用,$children/$parent/$root/$attrs/$listeners -> 不在乎耦合性的使用(开发一般不使用,组件库的开发可能会使用)
- 内容分发:
,,v-slot - 使用及优化:is(动态组件)、keep-alive(组件缓存)、异步组件
组件本质
vue中组件经历如下过程
组件配置=>VueComponent实例=>render()=>Virtual DOM=>DOM
所以组件的本质是产生虚拟DOM