vue组件封装

378 阅读4分钟

1.1 绪论

组件化和虚拟DOM是vue的俩大特性。组件系统是Vue中非常重要的一个特性,通过组件的封装,我们可以实现代码的复用以及功能的解耦。组件可以扩展HTML元素,封装可重用的代码。在较高层面上,组件是自定义的元素,Vue.js的编译器为它添加特殊功能。本文将以实际具体的业务组件为例,进行相关的学习总结。

1.2 组件的定义

1.3 组件的注册

1.3.1 全局注册

全局注册,当我们注册全局组件后,我们可以在任何Vue根实例的模板中使用它,全局注册组件的语法如下:

Vue.component('my-component-name', {
  // ... 选项 ...
})

全局注册组件也存在一个问题,假如我们项目中的组件都进行了全局注册,webpack打包工具会将这些注册了的组件都进行打包,即使在项目中不再使用的组件也仍旧会被打包,这就会造成代码的冗余。

1.3.2 局部注册

通过普通JavaScript对象的方式来定义组件:

var ComponentA = { /* ... */ }
var ComponentB = { /* ... */ }
var ComponentC = { /* ... */ }

然后在 components 选项中定义你想要使用的组件:

new Vue({
  el: '#app',
  components: {
    'component-a': ComponentA,
    'component-b': ComponentB
  }
})

1.4 vue组件三要素

  • props参数:数据父组件传入子组件父对子传参,就需要用到 props:
// 通常情况下,通用组件的的应用场景比较复杂,对 props 传递的参数应该添加一些验证规则,常用格式如下:
 props: {
    // 基础类型检测 (`null` 意思是任何类型都可以)
    propA: Number,
    // 多种类型
    propB: [String, Number],
    // 必传且是字符串
    propC: {
      type: String,
      required: true
    },
    // 数字,有默认值
    propD: {
      type: Number,
      default: 100
    },
    // 数组/对象的默认值应当由一个工厂函数返回
    propE: {
      type: Object,
      default: function () {
        return { message: 'hello' }
      }
    },
    // 自定义验证函数
    propF: {
      validator: function (value) {
        return value > 10
      }
    }
  }
  • slot定制插槽:slot-是可替代插槽,可以用其他节点替换,实现定制模态窗口内容的功能
  • event自定义事件

2.1 组件封装

接下来以实际业务为例,说明在实际开发中如何在使用vue-cli脚手架工具创建的项目中从零开始封装一些通用的组件,以封装一个ModalBox组件为例:

2.1.1 组件总体说明

带有标题、可自定制主体内容、按钮文本和行为的模态窗口:

ModalBox

  • 属性参数
参数 说明 类型 默认值 备注
title 窗口标题 String '' 如果为空,则标题栏不显示(不占高度)
labelConfirm 确定按钮标签 String '确定'
labelCancel 取消按钮标签 String '取消'
showConfirmButton 显示确认按钮 Boolean true
showCancelButton 显示取消按钮 Boolean true
showCloseButton 显示关闭按钮 Boolean true
enableBgCancelEvent 背景支持点击关闭事件 Boolean true
showMask 显示蒙层 Boolean true
onConfirm 确认按钮回调 Function 匿名空函数
onCancel 取消按钮回调 Function 匿名空函数
onRef 获取实例对象 Object 当前弹窗的实例对象
  • API方法
事件名称 说明 返回参数
showModal 先获取对象实例,通过实例调用该方法 -
2.1.2 项目的创建

vue-cli4.x初始化一个空的工程:

vue-cli4.x初始化一个空的工程
在vue-project/src/components/下创建ModalBox.vue文件:

// ModalBox.vue
<!-- component-name & component description -->
<template>
  <div class="modalbox">
    <div v-if="active">
      <div v-if="showMask" class="modalbox-cover" @click="onBgCancel"></div>
      <div class="contain-wrapper">
        <div class="main-context" :style="bodyBgColor">
          <div class="content-wrapper">
            <span v-show="title" class="title">{{title}}</span>
            <div class="content">{{'主题内容区域'}}</div>
          </div>
          <div v-show="showConfirmButton || showCancelButton" class="button-dock">
            <div v-if="showConfirmButton"  @click="onCancel" class="btn-cancel btn-normal">{{labelCancel}}</div>
            <div v-show="showConfirmButton && showCancelButton" class="split-line"></div>
            <div
              v-show="showCancelButton" @click="onConfirm" class="btn-confirm btn-normal">{{labelConfirm}}</div>
          </div>
        </div>
        <div v-show="showCloseButton" class="btn-close">
          <div @click="onCancel">
            <img src="https://img.baidu.com/img/close.png" class="img" />
          </div>
        </div>
      </div>
    </div>
  </div>
</template>

<script>
export default {
  name: "ModalBox",
  components: {},
  props:{},
  data() {
    return {};
  },
  mounted() {},
  methods: {}
};
</script>
<style lang='less' scoped>
.modalbox {
  .modalbox-cover {
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    z-index: 300;
    width: 100%;
    height: 100%;
    background: rgba(0, 0, 0, 0.65);
  }

  .contain-wrapper {
    position: fixed;
    z-index: 200;
    left: 50%;
    top: 50%;
    transform: translate(-50%, -50%);
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;
    z-index: 301;

    .main-context {
      width: 540px;
      background: rgba(255, 255, 255, 1);
      border-radius: 24px;
      overflow: hidden;

      .content-wrapper {
        display: flex;
        flex-direction: column;
        align-items: center;
        justify-content: start;

        .title {
          padding-top: 48px;
          font-size: 32px;
          font-weight: 500;
          color: rgba(51, 51, 51, 1);
          line-height: 44px;
        }

        .content {
          width: 100%;
          font-size: 32px;
          color: rgba(102, 102, 102, 1);
        }
      }

      .button-dock {
        display: flex;
        height: 104px;
        border-top: 2px rgba(247, 247, 247, 1) solid;

        .btn-normal {
          display: flex;
          box-sizing: border-box;
          flex: 1;
          font-size: 32px;
          font-weight: 400;
          line-height: 40px;
          justify-content: center;
          align-items: center;
        }

        .btn-cancel {
          color: rgba(111, 111, 111, 1);
        }

        .btn-confirm {
          color: rgba(255, 88, 96, 1);
        }

        .split-line {
          width: 2px;
          height: 100%;
          background-color: rgba(247, 247, 247, 1);
        }
      }
    }

    .btn-close {
      width: 90px;
      height: 90px;
      margin-top: 48px;

      .catchForm {
        width: inherit;
        height: inherit;
      }

      .img {
        width: 100%;
        height: 100%;
      }
    }
  }
}
</style>

2.2 组件使用

2.2.1 一般用法
2.2.2 其他使用方法

3.1 总结