1、背景
2017年底了,總結了這一年多來的前端之路,Vue從入門到放棄,再二進宮,從 Vue1.0 持續跟蹤到 Vue2.5。結合公司的一些實際專案,也封裝了一些比較實用的元件。
由於現在公司管理平臺主要運用Element UI,索性就結合元件Table 和 Pagination 封裝了一個支援頁面切換的Table元件,不囉嗦,直接上程式碼。(在之前釋出的版本之上,已經優化了一波)
2、實現思路
2.1、Element UI 引入(整體引入)
main.js
// Element UI
import Element from 'element-ui'
// 預設樣式
import 'element-ui/lib/theme-chalk/index.css'
複製程式碼
2.2、開始封裝 iTable.vue 元件 (骨架)
由於公司專案都是以 i 開頭,所以,為了區分元件和頁面,習慣於元件命名也以 i 開頭。 首先把 Table、Pagination 元件加進來
<template>
<div class="table">
<!--region 表格-->
<el-table id="iTable"></el-table>
<!--endregion-->
<!--region 分頁-->
<el-pagination></el-pagination>
<!--endregion-->
</div>
<template>
複製程式碼
養成寫註釋的好習慣,個人專案的註釋量基本上不會低於 30%
2.3、在頁面中引用 iTable 元件,並且給 iTable 元件傳值
<template>
<div class="table-page">
<!--region table 表格-->
<i-table
:list="list"
:total="total"
:otherHeight="otherHeight"
:options="options"
:pagination="pagination"
:columns="columns"
:operates="operates"
@handleSizeChange="handleSizeChange"
@handleIndexChange="handleIndexChange"
@handleSelectionChange="handleSelectionChange"
@handleFilter="handleFilter"
@handelAction="handelAction">
</i-table>
<!--endregion-->
</div>
</template>
<script>
import iTable from '../../components/Table/Index'
export default {
components: {iTable},
data () {
return {
total: 0,
list: [],
otherHeight: 208,
columns: [
{
prop: 'id',
label: '編號',
align: 'center',
width: 60
},
{
prop: 'title',
label: '標題',
align: 'center',
width: 400,
formatter: (row, column, cellValue) => {
return `<span style="white-space: nowrap;color: dodgerblue;">${row.title}</span>`
}
},
{
prop: 'state',
label: '狀態',
align: 'center',
width: '160',
render: (h, params) => {
return h('el-tag', {
props: {type: params.row.state === 0 ? 'success' : params.row.state === 1 ? 'info' : 'danger'} // 元件的props
}, params.row.state === 0 ? '上架' : params.row.state === 1 ? '下架' : '稽核中')
}
},
{
prop: 'author',
label: '作者',
align: 'center',
width: 120
},
{
prop: 'phone',
label: '聯絡方式',
align: 'center',
width: 160
},
{
prop: 'email',
label: '郵箱',
align: 'center',
width: 240
},
{
prop: 'createDate',
label: '釋出時間',
align: 'center',
width: 180,
formatter: (row, column, cellValue) => {
return this.$utils.Common.dateFormat(row.createDate, 'YYYY年MM月DD日 hh:mm')
}
}
], // 需要展示的列
operates: {
width: 200,
fixed: 'right',
list: [
{
label: '編輯',
type: 'warning',
show: : (index, row) => {
retuen true
},
icon: 'el-icon-edit',
plain: true,
disabled: false,
method: (index, row) => {
this.handleEdit(index, row)
}
},
{
label: '刪除',
type: 'danger',
icon: 'el-icon-delete',
show: true,
plain: false,
disabled: (index, row) => {
retuen false
},
method: (index, row) => {
this.handleDel(index, row)
}
}
]
}, // 操作按鈕組
pagination: {
pageIndex: 1,
pageSize: 20
}, // 分頁引數
options: {
stripe: true, // 是否為斑馬紋 table
loading: false, // 是否新增表格loading載入動畫
highlightCurrentRow: true, // 是否支援當前行高亮顯示
mutiSelect: true // 是否支援列表項選中功能
} // table 的引數
}
},
components: {
expandDom: {
props: {
column: {
required: true
},
row: {
required: true
}
},
render (h) {
return h('div', {}, ([this.column.render(this.row, this.column)]))
}
}
},
mounted () {
},
methods: {
// 切換每頁顯示的數量
handleSizeChange (pagination) {
this.pagination = pagination
},
// 切換頁碼
handleIndexChange (pagination) {
this.pagination = pagination
},
// 選中行
handleSelectionChange (val) {
console.log('val:', val)
},
// 編輯
handleEdit (index, row) {
console.log(' index:', index)
console.log(' row:', row)
},
// 刪除
handleDel (index, row) {
console.log(' index:', index)
console.log(' row:', row)
}
}
}
</script>
複製程式碼
除了 columns 引數和 operates 引數 之外,其它的引數應該還好理解,好的。那我們就詳細的解釋下這兩個引數,那麼我們就需要結合元件iTable.vue 來講解了,接下來就給 iTable.vue 新增肌肉和血管,程式碼都貼了。 比較難理解的就是columns裡面的 render 引數,使用了Vue的虛擬標籤,為了就是能夠在 table 表格的列中隨心所欲的使用各種html標籤 和 element UI 的其他元件。(你也可以直接寫,看看 table 元件是否能識別,呵呵噠!)這個估計對於剛入門的小夥伴是一個比較難理解的地方,詳細的大家可以先看下vue 的 render,解釋的更清楚,如果有的小夥伴不理解,可以直接私信我~~~
<!--region 封裝的分頁 table-->
<!--region 封裝的分頁 table-->
<template>
<div class="table">
<el-table
id="iTable"
v-loading.iTable="options.loading"
:data="list"
:max-height="height"
:stripe="options.stripe"
ref="mutipleTable"
@selection-change="handleSelectionChange">
<!--region 選擇框-->
<el-table-column v-if="options.mutiSelect" type="selection" style="width: 55px;">
</el-table-column>
<!--endregion-->
<!--region 資料列-->
<template v-for="(column, index) in columns">
<el-table-column :prop="column.prop"
:label="column.label"
:align="column.align"
:width="column.width">
<template slot-scope="scope">
<template v-if="!column.render">
<template v-if="column.formatter">
<span v-html="column.formatter(scope.row, column)"></span>
</template>
<template v-else>
<span>{{scope.row[column.prop]}}</span>
</template>
</template>
<template v-else>
<expand-dom :column="column" :row="scope.row" :render="column.render" :index="index"></expand-dom>
</template>
</template>
</el-table-column>
</template>
<!--endregion-->
<!--region 按鈕操作組-->
<el-table-column ref="fixedColumn" label="操作" align="center" :width="operates.width" :fixed="operates.fixed"
v-if="operates.list.length > 0">
<template slot-scope="scope">
<div class="operate-group">
<template v-for="(btn, key) in operates.list">
<div class="item" v-if="!btn.show||&&btn.show(scope.$index,scope.row)">
<el-button :type="btn.type" size="mini" :icon="btn.icon" :disabled="btn.disabled||&&btn.disabled(scope.$index,scope.row)"
:plain="btn.plain" @click.native.prevent="btn.method(key,scope.row)">{{ btn.label }}
</el-button>
</div>
</template>
</div>
</template>
</el-table-column>
<!--endregion-->
</el-table>
<div style="height:12px"></div>
<!--region 分頁-->
<el-pagination v-if="pagination" @size-change="handleSizeChange"
@current-change="handleIndexChange"
:page-size="tableCurrentPagination.pageSize"
:page-sizes="this.tableCurrentPagination.pageArray" :current-page="tableCurrentPagination.pageIndex"
layout="total,sizes, prev, pager, next,jumper"
:total="total"></el-pagination>
<!--endregion-->
</div>
</template>
<!--endregion-->
<script>
const _pageArray = [20, 50, 100] // 每頁展示條數的控制集合
export default {
props: {
list: {
type: Array,
default: [] // prop:表頭繫結的地段,label:表頭名稱,align:每列資料展示形式(left, center, right),width:列寬
}, // 資料列表
columns: {
type: Array,
default: [] // 需要展示的列 === prop:列資料對應的屬性,label:列名,align:對齊方式,width:列寬
},
operates: {
type: Object,
default: {} // width:按鈕列寬,fixed:是否固定(left,right),按鈕集合 === label: 文字,type :型別(primary / success / warning / danger / info / text),show:是否顯示,icon:按鈕圖示,plain:是否樸素按鈕,disabled:是否禁用,method:回撥方法
},
total: {
type: Number,
default: 0
}, // 總數
pagination: {
type: Object,
default: null // 分頁引數 === pageSize:每頁展示的條數,pageIndex:當前頁,pageArray: 每頁展示條數的控制集合,預設 _page_array
},
otherHeight: {
type: Number,
default: 160
}, // 計算表格的高度
options: {
type: Object,
default: {
stripe: false, // 是否為斑馬紋 table
loading: false, // 是否新增表格loading載入動畫
highlightCurrentRow: false, // 是否支援當前行高亮顯示
mutiSelect: false // 是否支援列表項選中功能
}
} // table 表格的控制引數
},
components: {
expandDom: {
functional: true,
props: {
row: Object,
render: Function,
index: Number,
column: {
type: Object,
default: null
}
},
render: (h, ctx) => {
const params = {
row: ctx.props.row,
index: ctx.props.index
}
if (ctx.props.column) params.column = ctx.props.column
return ctx.props.render(h, params)
}
}
},
data () {
return {
pageIndex: 1,
tableCurrentPagination: {},
multipleSelection: [] // 多行選中
}
},
created () {},
mounted () {
if (this.pagination && !this.pagination.pageSizes) {
this.pagination.pageArray = _pageArray // 每頁展示條數控制
}
this.tableCurrentPagination = this.pagination || {
pageSize: this.total,
pageIndex: 1
} // 判斷是否需要分頁
},
computed: {
// 計算table高度
height () {
return this.$utils.Common.getWidthHeight().height - this.otherHeight
}
},
methods: {
// 切換每頁顯示的數量
handleSizeChange (size) {
if (this.pagination) {
this.tableCurrentPagination = {
pageIndex: 1,
pageSize: size
}
this.$emit('handleSizeChange', this.tableCurrentPagination)
}
},
// 切換頁碼
handleIndexChange (currnet) {
if (this.pagination) {
this.tableCurrentPagination.pageIndex = currnet
this.$emit('handleIndexChange', this.tableCurrentPagination)
}
},
// 多行選中
handleSelectionChange (val) {
this.multipleSelection = val
this.$emit('handleSelectionChange', val)
},
// 顯示 篩選彈窗
showfilterDataDialog () {
this.$emit('handleFilter')
},
// 顯示 表格操作彈窗
showActionTableDialog () {
this.$emit('handelAction')
}
}
}
</script>
<style lang="less" rel="stylesheet/less">
@import "../../assets/styles/mixins";
.table {
height: 100%;
.el-pagination {
float: right;
margin: 20px;
}
.el-table__header-wrapper, .el-table__fixed-header-wrapper {
thead {
tr {
th {
color: #333333;
}
}
}
}
.el-table-column--selection .cell {
padding: 0;
text-align: center;
}
.el-table__fixed-right {
bottom: 0 !important;
right: 6px !important;
z-index: 1004;
}
.operate-group {
display: flex;
flex-wrap: wrap;
.item {
margin-top: 4px;
margin-bottom: 4px;
display: block;
flex: 0 0 50%;
}
}
.filter-data {
top: e("calc((100% - 100px) / 3)");
background-color: rgba(0, 0, 0, 0.7);
}
.table-action {
top: e("calc((100% - 100px) / 2)");
background-color: rgba(0, 0, 0, 0.7);
}
.fix-right {
position: absolute;
right: 0;
height: 100px;
color: #ffffff;
width: 30px;
display: block;
z-index: 1005;
writing-mode: vertical-rl;
text-align: center;
line-height: 28px;
border-bottom-left-radius: 6px;
border-top-left-radius: 6px;
cursor: pointer;
}
}
</style>
複製程式碼
這就是全部 的程式碼了,原諒我的表達能力有限,如果能對你有點幫助,那就太好了!如果那裡描述的不夠詳細或者有問題的地方,提出來,反正我也不改~~~,哈哈哈
完整的專案還是等我再優化下發粗來! 歡迎大家指點