You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
254 lines
9.6 KiB
254 lines
9.6 KiB
<template>
|
|
<view class="s-table" :class="c_class" :style="c_style">
|
|
<scroll-view class="s-table__scroll-x" scroll-x>
|
|
<view class="s-table__wrap">
|
|
<view v-if="showHeader" class="s-table__header" :style="header_style">
|
|
<slot name="header" :scopeParams="scopeParams" :columnWidthStyleList="columnWidthStyleList">
|
|
<template v-for="(column, columnIndex) of columns">
|
|
<view
|
|
v-if="!column.hidden"
|
|
:key="columnIndex"
|
|
class="s-table__th"
|
|
:class="thClassList[columnIndex]"
|
|
:style="thStyleList[columnIndex]"
|
|
@click="onThClick(column, columnIndex)"
|
|
>
|
|
<slot name="th" :scopeParams="scopeParams" :column="column" :columnIndex="columnIndex">
|
|
<view>{{ column.label }}</view>
|
|
<view v-if="hasSort(column)" class="s-table__sort-wrap">
|
|
<view
|
|
v-for="order of ['asc', 'desc']"
|
|
:key="order"
|
|
class="s-table__sort-icon"
|
|
:class="{ 's-table__sort-icon--active': isActiveSort(column, order) }"
|
|
:style="{
|
|
color: isActiveSort(column, order) ? sortActiveColor : sortColor,
|
|
}"
|
|
></view>
|
|
</view>
|
|
</slot>
|
|
</view>
|
|
</template>
|
|
</slot>
|
|
</view>
|
|
<view class="s-table__body">
|
|
<scroll-view class="s-table__scroll-y" scroll-y>
|
|
<view
|
|
v-for="(row, rowIndex) of data"
|
|
:key="rowIndex"
|
|
class="s-table__tr"
|
|
:class="'' + getRowClass(row, rowIndex)"
|
|
:style="'' + getRowStyle(row, rowIndex)"
|
|
@click="onTrClick(row, rowIndex)"
|
|
>
|
|
<slot
|
|
name="tr"
|
|
:scopeParams="scopeParams"
|
|
:row="row"
|
|
:rowIndex="rowIndex"
|
|
:columnWidthStyleList="columnWidthStyleList"
|
|
>
|
|
<template v-for="(column, columnIndex) of columns">
|
|
<view
|
|
v-if="!column.hidden"
|
|
:key="columnIndex"
|
|
class="s-table__td"
|
|
:class="'' + getTdClass({ row, rowIndex, column, columnIndex })"
|
|
:style="'' + getTdStyle({ row, rowIndex, column, columnIndex })"
|
|
@click="onTdClick({ row, rowIndex, column, columnIndex })"
|
|
>
|
|
<slot
|
|
:scopeParams="scopeParams"
|
|
:row="row"
|
|
:rowIndex="rowIndex"
|
|
:column="column"
|
|
:columnIndex="columnIndex"
|
|
>
|
|
<view class="s-table__cell">
|
|
{{ row[column.prop] }}
|
|
</view>
|
|
</slot>
|
|
</view>
|
|
</template>
|
|
</slot>
|
|
</view>
|
|
</scroll-view>
|
|
</view>
|
|
</view>
|
|
</scroll-view>
|
|
</view>
|
|
</template>
|
|
|
|
<script>
|
|
import componentMixin from '../../mixins/componentMixin';
|
|
|
|
/**
|
|
* s-table 简单数据表格
|
|
* @description 简单的表格组件,可设每列宽度,内置排序功能
|
|
* @property {Array} columns 表头 [{label, prop, minWidth, width,sortBy, hidden}]
|
|
* @property {Array} data 数据列表
|
|
* @property {Number|String} height table 的高度,默认为自动高度,设此属性可固定表头
|
|
* @property {String} align = [left|center|right] 文字居中方向
|
|
* @property {Boolean} stripe 是否为斑马纹 table
|
|
* @property {Boolean} border 是否显示边框
|
|
* @property {String} borderColor 边框颜色色
|
|
* @property {Boolean} showHeader 是否显示表头
|
|
* @property {String|Object} headerStyle 表头样式
|
|
* @property {String|Object|Array|Function} rowClass 行 class 方法参数 rowClass(row, rowIndex)
|
|
* @property {String|Object|Function} rowStyle 行 style 方法参数 rowStyle(row, rowIndex)
|
|
* @property {String|Object|Array|Function} thClass 表头单元格 class 方法参数 thClass(column, columnIndex)
|
|
* @property {String|Object|Function} thStyle 表头单元格 style 方法参数 thStyle(column, columnIndex)
|
|
* @property {String|Object|Array|Function} tdClass 单元格 class 方法参数 tdClass({ row, rowIndex, column, columnIndex })
|
|
* @property {String|Object|Function} tdStyle 单元格 style 方法参数 tdStyle({ row, rowIndex, column, columnIndex })
|
|
* @property {String|Number} sortBy 排序字段,sort-by.sync双向绑定用于获取
|
|
* @property {String} sortOrder = [asc | desc] 排序顺序, sort-order.sync 双向绑定用于获取
|
|
* @property {String} sortColor 排序箭头颜色
|
|
* @property {String} sortActiveColor 排序箭头激活颜色
|
|
* @event {Function} sort ({ row, rowIndex, column, columnIndex }) 触发排序时, 需要双向绑定获取 :sort-by.sync="sortBy" :sort-order.sync="sortOrder"
|
|
* @event {Function} th-click (column, columnIndex) th点击事件
|
|
* @event {Function} tr-click (row, rowIndex) tr点击事件
|
|
* @event {Function} td-click ({ row, rowIndex, column, columnIndex }) td点击事件
|
|
* @example <s-table border align="center" :columns="table.columns" :data="table.data" />
|
|
*/
|
|
export default {
|
|
name: 'STable',
|
|
mixins: [componentMixin],
|
|
props: {
|
|
columns: {
|
|
type: Array,
|
|
default: () => [],
|
|
},
|
|
data: {
|
|
type: Array,
|
|
default: () => [],
|
|
},
|
|
height: [Number, String],
|
|
align: String,
|
|
stripe: Boolean,
|
|
border: Boolean,
|
|
borderColor: String,
|
|
showHeader: {
|
|
type: Boolean,
|
|
default: true,
|
|
},
|
|
headerStyle: [String, Object],
|
|
rowClass: [String, Object, Array, Function],
|
|
rowStyle: [String, Object, Function],
|
|
thClass: [String, Object, Array, Function],
|
|
thStyle: [String, Object, Function],
|
|
tdClass: [String, Object, Array, Function],
|
|
tdStyle: [String, Object, Function],
|
|
sortBy: [Number, String],
|
|
sortOrder: String,
|
|
sortColor: String,
|
|
sortActiveColor: String,
|
|
},
|
|
computed: {
|
|
c_class() {
|
|
return this.$mergeClass({
|
|
's-table--border': this.border,
|
|
's-table--stripe': this.stripe,
|
|
[`s-table--align-${this.align}`]: this.align,
|
|
}, this.custom_class);
|
|
},
|
|
c_style() {
|
|
return this.$mergeStyle({
|
|
height: this.$addUnit(this.height),
|
|
borderColor: this.borderColor,
|
|
}, this.custom_style);
|
|
},
|
|
header_style() {
|
|
return this.$mergeStyle(this.headerStyle);
|
|
},
|
|
columnWidthStyleList() {
|
|
return this.columns.map(item => {
|
|
const style = {};
|
|
if (this.$isDef(item.width)) {
|
|
style.width = this.$addUnit(item.width);
|
|
} else {
|
|
style['flex-grow'] = '1';
|
|
}
|
|
if (this.$isDef(item.minWidth)) {
|
|
style.minWidth = this.$addUnit(item.minWidth);
|
|
}
|
|
return style;
|
|
});
|
|
},
|
|
thClassList() {
|
|
const thClass = this.$getPropsFn('thClass');
|
|
return this.columns.map((column, columnIndex) => {
|
|
return this.$mergeClass({
|
|
[`s-table__th--align-${column.align}`]: column.align,
|
|
}, thClass ? thClass(column, columnIndex) : this.thClass);
|
|
});
|
|
},
|
|
thStyleList() {
|
|
const { columns, columnWidthStyleList, borderColor } = this;
|
|
const thStyle = this.$getPropsFn('thStyle');
|
|
return columns.map((column, columnIndex) => {
|
|
return this.$mergeStyle(columnWidthStyleList[columnIndex], {
|
|
borderColor: borderColor,
|
|
}, thStyle ? thStyle(column, columnIndex) : this.thStyle);
|
|
});
|
|
},
|
|
},
|
|
methods: {
|
|
hasSort(column) {
|
|
return this.$isDef(column.sortBy);
|
|
},
|
|
isActiveSort(column, sortOrder) {
|
|
return this.sortBy === column.sortBy && this.sortOrder === sortOrder;
|
|
},
|
|
getRowClass(row, rowIndex) {
|
|
const rowClass = this.$getPropsFn('rowClass');
|
|
return this.$mergeClass({
|
|
's-table__tr--stripe': this.stripe && rowIndex % 2,
|
|
}, rowClass ? rowClass(row, rowIndex) : this.rowClass);
|
|
},
|
|
getRowStyle(row, rowIndex) {
|
|
const rowStyle = this.$getPropsFn('rowStyle');
|
|
return this.$mergeStyle(rowStyle ? rowStyle(row, rowIndex) : this.rowStyle);
|
|
},
|
|
getTdClass(params) {
|
|
const { column } = params;
|
|
const tdClass = this.$getPropsFn('tdClass');
|
|
return this.$mergeClass({
|
|
[`s-table__td--align-${column.align}`]: column.align,
|
|
}, tdClass ? tdClass(params) : this.tdClass);
|
|
},
|
|
getTdStyle(params) {
|
|
const tdStyle = this.$getPropsFn('tdStyle');
|
|
return this.$mergeStyle(this.columnWidthStyleList[params.columnIndex], {
|
|
borderColor: this.borderColor,
|
|
}, tdStyle ? tdStyle(params) : this.tdStyle);
|
|
},
|
|
onThClick(column, columnIndex) {
|
|
this.$emit('th-click', column, columnIndex);
|
|
if (this.hasSort(column)) {
|
|
if (this.sortBy !== column.sortBy) {
|
|
this.$emit('update:sortBy', column.sortBy);
|
|
this.$emit('update:sortOrder', 'asc');
|
|
} else {
|
|
if (!this.sortOrder) {
|
|
this.$emit('update:sortOrder', 'asc');
|
|
} else if (this.sortOrder === 'asc') {
|
|
this.$emit('update:sortOrder', 'desc');
|
|
} else if (this.sortOrder === 'desc') {
|
|
this.$emit('update:sortBy', '');
|
|
this.$emit('update:sortOrder', '');
|
|
}
|
|
}
|
|
this.$emit('sort', column, columnIndex);
|
|
}
|
|
},
|
|
onTrClick(row, rowIndex) {
|
|
this.$emit('tr-click', row, rowIndex);
|
|
},
|
|
onTdClick(params) {
|
|
this.$emit('td-click', params);
|
|
},
|
|
},
|
|
};
|
|
</script>
|
|
|
|
<style lang="scss" src="./index.scss"></style>
|
|
|