前端组件化封装及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
- 服务端分页以及自定义序号 https://github.com/MengFangui/iview-table-page/blob/master/example/table1.vue
- 服务端分页并排序、过滤 https://github.com/MengFangui/iview-table-page/blob/master/example/table2.vue
- 可编辑单元格 https://github.com/MengFangui/iview-table-page/blob/master/example/table3.vue
- 可编辑行 https://github.com/MengFangui/iview-table-page/blob/master/example/table4.vue
- 快速切换到某一页 https://github.com/MengFangui/iview-table-page/blob/master/example/table5.vue
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注册账号
发包
在你将要发包的目录下,执行
npm adduser
npm publish
到此完成前端组件化封装和npm打包部署工作。
作者:孟繁贵 Email:meng010387@126.com 期待共同进步!