Vue预习课06:组件化实践.pdf

组件化基础

定义全局组件、组件数据传递

  1. <course-list :courses="list"></course-list>
  2. // 定义全局组件
  3. // 组件的名称建议是羊肉串命名法。
  4. // 如果是驼峰命名的话(vue的内部会对名称进行转换),在使用的时候需要使用羊肉串命名的写法,html的标签不区分大小写,所以驼峰写法不会被识别
  5. Vue.component('course-list', {
  6. // 数据传递
  7. props: {
  8. courses: {
  9. type: Array, // 传入数据的类型
  10. default: [] // 如果没有传入的默认值
  11. }
  12. },
  13. data () {
  14. return {
  15. selectedCourse: ''
  16. }
  17. },
  18. // template应该只有一个根元素
  19. template: `
  20. <div>
  21. <p v-if="courses.length == 0">暂无课程数据</p>
  22. <ul v-else>
  23. <li v-for="item in courses" :key="item" :class="{active: item === selectedCourse}" @click="selectedCourse = item">{{item}}</li>
  24. </ul>
  25. </div>
  26. `
  27. })

自定义事件及监听

父子组件进行通信的时候,使用派发和监听自定义事件
使用$emit()

  1. // 派发事件,通知父组件做新增课程 this.$emit('事件名称', 传递参数) 事件名称要考虑到html不区分大小写的问题,所以建议命名是羊肉串的命名
  2. <add-course @add-course="addCourse"></add-course>
  3. // 新增组件
  4. Vue.component('add-course', {
  5. data() {
  6. return {
  7. course: ''
  8. }
  9. },
  10. methods: {
  11. addCourse() {
  12. // 派发事件,通知父组件做新增课程 this.$emit('事件名称', 传递参数) 事件名称要考虑到html不区分大小写的问题,所以建议命名是羊肉串的命名
  13. this.$emit('add-course', this.course)
  14. this.course = ''
  15. }
  16. },
  17. template: `
  18. <div>
  19. <p>
  20. <input type="text" v-model="course" v-on:keyup.enter="addCourse">
  21. <button @click="addCourse">新增</button>
  22. </p>
  23. </div>
  24. `
  25. })
  26. const app = new Vue({
  27. el: '#app',
  28. data: {
  29. title: '购物车',
  30. list: ['大数据', ' web']
  31. },
  32. methods: {
  33. addCourse(course) {
  34. this.list.push(course);
  35. }
  36. }
  37. })

自定义组件实现数据双向绑定(v-model的本质)

自定义组件使用v-model

  1. <!-- 新增组件 -->
  2. <!-- v-model的本质 -->
  3. <!-- v-model="course" 等同于 :value="course" @input="course = $event" $event是固定的名字, $event是传递出来的参数-->
  4. <add-course @add-course="addCourse" :value="course" @input="course = $event"></add-course>
  5. <add-course @add-course="addCourse" v-model="course"></add-course>
  6. // 新增组件
  7. // 让组件本身无状态(即没有数据对象), 会让组件更加的内聚和可复用
  8. Vue.component('add-course', {
  9. /*
  10. props的值可以是数组,也可以是对象
  11. props的值是对象的时候利于接收值的校验
  12. */
  13. props: ['value'],
  14. methods: {
  15. addCourse (e) {
  16. this.$emit('add-course')
  17. },
  18. onInput (e) {
  19. // 派发自定义事件,并且传参,
  20. // e.target.value 是事件的目标的值
  21. this.$emit('input', e.target.value);
  22. }
  23. },
  24. template: `
  25. <p>
  26. <input type="text" :value="value" @input="onInput" v-on:keyup.enter="addCourse">
  27. <button @click="addCourse">新增</button>
  28. </p>
  29. `
  30. })

插槽

默认插槽

使用<slot>

  1. <!-- 默认插槽 -->
  2. <message :show="show" @close="show = $event">新增成功</message>
  3. // 提示框 --- 默认插槽
  4. Vue.component('message', {
  5. props: ['show'],
  6. template: `
  7. <div v-if="show">
  8. <slot>默认提示</slot>
  9. <span @click="$emit('close', false)">×</span>
  10. </div>
  11. `
  12. })

具名插槽

使用v-slot:名称<slot name="名称">

  1. <!-- 具名插槽 -->
  2. <message3 :show.sync="show">
  3. <template v-slot:title>具名插槽title设置的值</template>
  4. <!-- default可以省略 -->
  5. <template v-slot:default>
  6. 默认插槽设置的值
  7. <span @click="show = false">×</span>
  8. </template>
  9. </message3>
  10. // 具名插槽
  11. Vue.component('message3', {
  12. props: ['show'],
  13. template: `
  14. <div v-if="show">
  15. <slot name="title">具名插槽名字为title的插槽的默认值</slot>
  16. <!-- default可以省略 -->
  17. <slot name="default">默认插槽的默认文本</slot>
  18. </div>
  19. `
  20. })

作用域插槽

作用域插槽使用场景: 组件外部使用组件内部的值

  1. <!-- 作用域插槽 -->
  2. <message4 :show.sync="show">
  3. <!-- slotProps是组件内部传递的值 -->
  4. <template v-slot:title="slotProps">{{slotProps.title}} ---- message4组件的title值</template>
  5. <template v-slot>
  6. {{title}} --- 当前组件的title值
  7. <span @click="show = false">×</span>
  8. </template>
  9. </message4>
  10. // 作用域插槽
  11. Vue.component('message4', {
  12. props: ['show'],
  13. template: `
  14. <div v-if="show">
  15. <slot name="title" title="message4组件title">具名插槽名字为title的插槽的默认值</slot>
  16. <slot class="default">默认文本</slot>
  17. </div>
  18. `
  19. })

修饰符 .sync

修饰符.sync的使用
:show="show" @update:show="show = $event"等同于:show.sync="show"

  1. <!-- 修饰符sync的使用 -->
  2. <message2 :show="show" @update:show="show = $event">新增成功</message2>
  3. <!-- 上下等同 -->
  4. <message2 :show.sync="show">新增成功</message2>
  5. // 提示框 --- 默认插槽 -- 修饰符sync的使用
  6. Vue.component('message2', {
  7. props: ['show'],
  8. template: `
  9. <div v-if="show">
  10. <slot>默认提示</slot>
  11. <span @click="$emit('update:show', false)">×</span>
  12. </div>
  13. `
  14. })

组件化探讨

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 -> 不在乎耦合性的使用(开发一般不使用,组件库的开发可能会使用)
  • 内容分发