打赏

前端组件化封装及npm部署

前端组件化封装及npm部署

简介

组件化思想是软件编程的一个重要思想。如汽车的生产,将轮子、灯、座椅等作为单独的组件,由各自的工厂去生产维护,各个组件都做好后再拿到组装厂统一组装使用。组件化思想就是将一个项目拆分成若干个组件,分而治之。

组件化开发好处

  • 高复用性:复用的好处可以得到 较高的生产效率以及随之而来的成本降低、较高的软件质量(错误可以更快的被纠正)以及 恰当的使用复用可以改善系统的可维护性。
  • 低耦合性:低耦合就是指各模块依赖程度,减少模块间调用。

高内聚和低耦合目的是使程序模块的可重用性、移植性大大增强。

组件封装

github地址:https://github.com/MengFangui/iview-table-page

项目中经常使用表格和分页组件,目前比较流行的element UI,iview UI和Ant Design 3个UI库都有表格和分页组件,但是没有将表格和分页组件组合;同时分页组件都有一个bug,即电梯(快速跳转到某一页)没有绑定跳转事件。本文将以iview ui的Table和Page为例,简述前端组件封装和npm打包部署。

iview-table-page 组件实现

<template>
<div>
     <Table
     :columns="columns"
     :data="data"
     :stripe='stripe'
     :border='border'
     :show-header='showHeader'
     :width='width'
     :height='height'
     :max-height='maxHeight'
     :loading='loading'
     :disabled-hover='disabledHover'
     :row-class-name='rowClassName'
     :size='size'
     :no-data-tex='noDataText'
     :no-filtered-data-text='noFilteredDataText'
     :draggable='draggable'
     :tooltip-theme='tooltipTheme'
     :row-key='rowKey'
     :highlight-row='highlightRow'

     @on-current-change='onCurrentChange'
     @on-select='onSelect'
     @on-select-cancel='onSelectCancel'
     @on-select-all='onSelectAll'
     @on-select-all-cancel='onSelectAllCancel'
     @on-selection-change='onSelectionChange'
     @on-sort-change='onSortChange'
     @on-filter-change='onFilterChange'
     @on-row-click='onRowClick'
     @on-row-dblclick='onRowDblclick'
     @on-expand='onExpand'
     @on-drag-drop='onDragDrop'>
      <template slot="header">
          <slot name='header'></slot>
      </template>
      <template slot="footer">
          <slot name='footer'></slot>
      </template>
      <template slot="loading">
          <slot name='loading'></slot>
      </template>
     </Table>
    <div :style="pageStyle" v-if="paginationShow">
        <Page
            :total="total"
            :current="current"
            :page-size='pageSize'
            :page-size-opts='pageSizeOpts'
            :placement='placement'
            :size='pageShapeSize'
            :simple='simple'
            :show-total='showTotal'
            :show-elevator='showElevator'
            :show-sizer='showSizer'
            :class-name='pageClassName'
            :styles='styles'
            :transfer='transfer'
            :prev-text='prevText'
            :next-text='nextText'

            @on-change='onChange'
            @on-page-size-change='onPageSizeChange'>
            <slot/>
            </Page>
    </div>
</div>
</template>

<script>
export default {
  name: 'iviewTablePage',
  props: {
    // 表格数据
    data: {
      type: Array,
      default: () => {
        return []
      }
    },
    // 表格列属性
    columns: {
      type: Array,
      default: () => {
        return []
      }
    },
    // 是否显示间隔斑马纹
    stripe: {
      type: Boolean,
      default: false
    },
    // 是否显示纵向边框
    border: {
      type: Boolean,
      default: false
    },
    // 是否显示表头
    showHeader: {
      type: Boolean,
      default: true
    },
    // 表格宽度,单位 px
    width: [String, Number],
    // 表格高度,单位 px,设置后,如果表格内容大于此值,会固定表头
    height: [String, Number],
    // 表格最大高度,单位 px,设置后,如果表格内容大于此值,会固定表头
    maxHeight: [String, Number],
    // 表格是否加载中
    loading: {
      type: Boolean,
      default: false
    },
    // 禁用鼠标悬停时的高亮
    disabledHover: {
      type: Boolean,
      default: false
    },
    // 是否支持高亮选中的行,即单选
    highlightRow: {
      type: Boolean,
      default: false
    },
    // 行的 className 的回调方法
    rowClassName: {
      type: Function,
      default: () => {
        return ''
      }
    },
    // 表格尺寸,可选值为 large、small、default 或者不填
    size: {
      type: String
    },
    // 数据为空时显示的提示内容
    noDataText: {
      type: String,
      default: '暂无数据'
    },
    // 筛选数据为空时显示的提示内容
    noFilteredDataText: {
      type: String,
      default: '暂无筛选结果'
    },
    // 是否开启拖拽调整行顺序,需配合 @on-drag-drop 事件使用
    draggable: {
      type: Boolean,
      default: false
    },
    // 列使用 tooltip 时,配置它的主题,可选值为 dark 或 light
    tooltipTheme: {
      type: String,
      default: 'dark'
    },
    // 是否强制使用内置的 row-key,开启后可能会影响性能
    rowKey: {
      type: Boolean,
      default: false
    },
    // 当前页码,支持 .sync 修饰符
    currentPage: {
      type: Number,
      default: 1
    },
    // 数据总数
    total: {
      type: Number,
      default: 0
    },
    // 每页条数
    pageSize: {
      type: Number,
      default: 10
    },
    // 每页条数切换的配置
    pageSizeOpts: {
      type: Array,
      default: () => {
        return [10, 20, 30, 40]
      }
    },
    // 条数切换弹窗的展开方向,可选值为 bottom 和 top
    placement: {
      type: String,
      default: 'bottom'
    },
    // 可选值为small(迷你版)或不填(默认)
    pageShapeSize: {
      type: String
    },
    // 简洁版
    simple: {
      type: Boolean,
      default: false
    },
    // 显示总数
    showTotal: {
      type: Boolean,
      default: false
    },
    // 显示电梯,可以快速切换到某一页
    showElevator: {
      type: Boolean,
      default: false
    },
    // 显示分页,用来改变page-size
    showSizer: {
      type: Boolean,
      default: false
    },
    // 自定义 class 名称
    pageClassName: {
      type: String,
      default: ''
    },
    // 自定义 style 样式
    styles: {
      type: Object,
      default: () => {
        return {}
      }
    },
    // 是否将弹层放置于 body 内,在 Tabs、带有 fixed 的 Table 列内使用时,建议添加此属性,它将不受父级样式影响,从而达到更好的效果
    transfer: {
      type: Boolean,
      default: false
    },
    // 替代图标显示的上一页文字
    prevText: {
      type: String,
      default: ''
    },
    // 替代图标显示的下一页文字
    nextText: {
      type: String,
      default: ''
    },
    // 是否显示页码
    paginationShow: {
      type: Boolean,
      default: true
    },
    paginationPosition: {
      type: String,
      default: 'right'
    }
  },
  data () {
    return {
      pageStyle: {
        'text-align': this.paginationPosition,
        margin: '16px 0'
      },
      current: 1
    }
  },
  methods: {
    // 开启 highlight-row 后有效,当表格的当前行发生变化的时候会触发
    onCurrentChange (...arg) {
      this.$emit('on-current-change', ...arg)
    },
    // 在多选模式下有效,选中某一项时触发
    onSelect (...arg) {
      this.$emit('on-select', ...arg)
    },
    // 在多选模式下有效,取消选中某一项时触发
    onSelectCancel (...arg) {
      this.$emit('on-select-cancel', ...arg)
    },
    // 在多选模式下有效,点击全选时触发
    onSelectAll (...arg) {
      this.$emit('on-select-all', ...arg)
    },
    // 在多选模式下有效,点击取消全选时触发
    onSelectAllCancel (...arg) {
      this.$emit('on-select-all-cancel', ...arg)
    },
    // 在多选模式下有效,只要选中项发生变化时就会触发
    onSelectionChange (...arg) {
      this.$emit('on-selection-change', ...arg)
    },
    // 排序时有效,当点击排序时触发
    onSortChange (...arg) {
      this.$emit('on-sort-change', ...arg)
    },
    // 筛选时有效,筛选条件发生变化时触发
    onFilterChange (...arg) {
      this.$emit('on-filter-change', ...arg)
    },
    // 单击某一行时触发
    onRowClick (...arg) {
      this.$emit('on-row-click', ...arg)
    },
    // 双击某一行时触发
    onRowDblclick (...arg) {
      this.$emit('on-row-dblclick', ...arg)
    },
    // 展开或收起某一行时触发
    onExpand (...arg) {
      this.$emit('on-expand', ...arg)
    },
    // 拖拽排序松开时触发,返回置换的两行数据索引
    onDragDrop (...arg) {
      this.$emit('on-drag-drop', ...arg)
    },
    // 页码改变的回调,返回改变后的页码
    onChange (...arg) {
      this.$emit('on-change', ...arg)
    },
    // 切换每页条数时的回调,返回切换后的每页条数
    onPageSizeChange (...arg) {
      this.$emit('on-page-size-change', ...arg)
    },
    // 表格方法
    // 清除高亮项,仅在开启 highlight-row 时可用
    clearCurrentRow (...arg) {
      this.$children[0].clearCurrentRow(...arg)
    },
    // 表格方法
    // 全选或者取消全选
    selectAll (status) {
      this.$children[0].selectAll(status)
    },
    // 表格方法
    exportCsv (...arg) {
      this.$children[0].exportCsv(...arg)
    }
  },
  mounted () {
    // 初始化页码
    this.current = this.currentPage
    let that = this
    // 获取跳转页码
    let dom = document.querySelector('.ivu-page-options-elevator input')
    if (dom) {
      // 定义事件onchange
      dom.onchange = function () {
        let pageNo = parseInt(dom.value, 10)
        if (!Number.isNaN(pageNo) && pageNo > 0 && pageNo <= that.total) {
          that.current = pageNo
        }
      }
    }
  }
}
</script>

API 说明

table 属性

属性 说明 类型 默认值
data 显示的结构化数据,其中,字段 cellClassName 用于设置任意单元格的样式名称,因此数据不能使用该字段,详见示例特定样式。 Array []
columns 表格列的配置描述,具体项见后文 Array []
stripe 是否显示间隔斑马纹 Boolean false
border 是否显示纵向边框 Boolean false
show-header 是否显示表头 Boolean false
width 表格宽度,单位 px Number, String 自动
height 表格高度,单位 px,设置后,如果表格内容大于此值,会固定表头 Number, String -
max-height 表格最大高度,单位 px,设置后,如果表格内容大于此值,会固定表头 Number, String -
loading 表格是否加载中 Boolean false
disabled-hover 禁用鼠标悬停时的高亮 Boolean false
highlight-row 是否支持高亮选中的行,即单选 Boolean false
row-class-name 行的 className 的回调方法,传入参数:row:当前行数据, index:当前行的索引 Function -
size 表格尺寸,可选值为 large、small、default 或者不填 String -
no-data-text 数据为空时显示的提示内容 String 暂无数据
no-filtered-data-text 筛选数据为空时显示的提示内容 String 暂无筛选结果
draggable 是否开启拖拽调整行顺序,需配合 @on-drag-drop 事件使用 Boolean false
tooltip-theme 列使用 tooltip 时,配置它的主题,可选值为 dark 或 light String dark
row-key 是否强制使用内置的 row-key,开启后可能会影响性能 Boolean false

table事件

事件名 说明 返回值
on-current-change 开启 highlight-row 后有效,当表格的当前行发生变化的时候会触发 currentRow:当前高亮行的数据, oldCurrentRow:上一次高亮的数据
on-select 在多选模式下有效,选中某一项时触发 selection:已选项数据, row:刚选择的项数据, 即接收的参数是(selection,row)
on-select-cancel 在多选模式下有效,取消选中某一项时触发 selection:已选项数据,row:取消选择的项数据
on-select-all 在多选模式下有效,点击全选时触发 selection:已选项数据
on-select-all-cancel 在多选模式下有效,点击取消全选时触发 selection:已选项数据
on-selection-change 在多选模式下有效,只要选中项发生变化时就会触发 selection:已选项数据
on-sort-change 排序时有效,当点击排序时触发 column:当前列数据,key:排序依据的指标,order:排序的顺序,值为 asc 或 desc
on-filter-change 筛选时有效,筛选条件发生变化时触发 当前列数据
on-row-click 单击某一行时触发 当前行的数据,index
on-row-dblclick 双击某一行时触发 当前行的数据,index
on-expand 展开或收起某一行时触发 row:当前行的数据,status:当前的状态
on-drag-drop 拖拽排序松开时触发,返回置换的两行数据索引 index1, index2

page 属性

属性 说明 类型 默认值
currentPage 当前页码 Number 1
total 数据总数 Number 0
page-size 每页条数 Number 10
page-size-opts 每页条数切换的配置 Array [10, 20, 30, 40]
placement 条数切换弹窗的展开方向,可选值为 bottom 和 top String bottom
page-shape-size 可选值为small(迷你版)或不填(默认) String -
simple 简洁版 Boolean false
show-total 显示总数 Boolean false
show-elevator 显示电梯,可以快速切换到某一页 Boolean false
show-sizer 显示分页,用来改变page-size Boolean false
page-class-name 自定义 class 名称 String -
styles 自定义 style 样式 Object -
transfer 是否将弹层放置于 body 内,在 Tabs、带有 fixed 的 Table 列内使用时,建议添加此属性,它将不受父级样式影响,从而达到更好的效果 Boolean false
prev-text 替代图标显示的上一页文字 String -
next-text 替代图标显示的下一页文字 String -

新增属性

属性 说明 类型 默认值
pagination-show 是否显示页面 Boolean true
pagination-position 页码位置 String 可选值为 left、center 和 right right

其中大多数都是ivew UI上的事件和属性,新增了pagination-show和pagination-position属性。

电梯(跳转到某一页)事件绑定实现

获取跳转页面input dom,将dom绑定onchange事件。

// 获取跳转页码dom
let dom = document.querySelector('.ivu-page-options-elevator input')
if (dom) {
  // 定义事件onchange
  dom.onchange = function () {
    let pageNo = parseInt(dom.value, 10)
    if (!Number.isNaN(pageNo) && pageNo > 0 && pageNo <= that.total) {
      that.current = pageNo
    }
  }

demo

iview-table-page 组件使用

安装组件

$ npm i --save iview-table-page
or
$ yarn add iview-table-page

组件注册

全局注册组件

main.js中:

import Vue from 'vue'
import iviewTablePage from 'iview-table-page'
Vue.use(iviewTablePage)
局部注册组件
<template>
<div>
  <iviewTablePage
  border
  :columns="columns7"
  :data="data6"
  :total='total'
  >
  </iviewTablePage>
</div>
</template>

<script>
import iviewTablePage from 'iview-table-page'
export default {
  components: { iviewTablePage },
  data () {
    return {
      columns7: [
        {
          title: 'Name',
          key: 'name',
          render: (h, params) => {
            return h('div', [
              h('Icon', {
                props: {
                  type: 'person'
                }
              }),
              h('strong', params.row.name)
            ])
          }
        },
        {
          title: 'Age',
          key: 'age'
        },
        {
          title: 'Address',
          key: 'address'
        },
        {
          title: 'Action',
          key: 'action',
          width: 150,
          align: 'center',
          render: (h, params) => {
            return h('div', [
              h(
                'Button',
                {
                  props: {
                    type: 'primary',
                    size: 'small'
                  },
                  style: {
                    marginRight: '5px'
                  },
                  on: {
                    click: () => {
                      this.show(params.index)
                    }
                  }
                },
                'View'
              ),
              h(
                'Button',
                {
                  props: {
                    type: 'error',
                    size: 'small'
                  },
                  on: {
                    click: () => {
                      this.remove(params.index)
                    }
                  }
                },
                'Delete'
              )
            ])
          }
        }
      ],
      data6: [
        {
          name: 'John Brown',
          age: 18,
          address: 'New York No. 1 Lake Park'
        },
        {
          name: 'Jim Green',
          age: 24,
          address: 'London No. 1 Lake Park'
        },
        {
          name: 'Joe Black',
          age: 30,
          address: 'Sydney No. 1 Lake Park'
        },
        {
          name: 'Jon Snow',
          age: 26,
          address: 'Ottawa No. 2 Lake Park'
        }
      ],
      total: 4
    }
  }
}
</script>

npm 打包

package.json核心配置

"build-bundle": "vue-cli-service build --target lib --name iviewTablePage ./src/components/index.js",

"main": "dist/iviewTablePage.umd.js",
  • 打包为lib。
  • 入口文件为umd规范的js。
  • keywords:便于搜索npm 包。
  • repository: 代码存放地址(一般是git地址)。
  • devDependencies: 你要发的包,所依赖的开发环境下的包。
  • dependencies:你要发的包,所依赖的线上环境下的包。

package.json的完整配置见:https://github.com/MengFangui/iview-table-page/blob/master/package.json

npm注册账号

https://www.npmjs.com/signup

发包

在你将要发包的目录下,执行

npm adduser
npm publish

到此完成前端组件化封装和npm打包部署工作。

posted @ 2020-01-15 20:32  孟繁贵  阅读(3793)  评论(0编辑  收藏  举报
TOP