| | |
| | | <template> |
| | | <!-- #ifdef H5 --> |
| | | <th :rowspan="rowspan" :colspan="colspan" class="uni-table-th" :class="{ 'table--border': border }" :style="{ width: width + 'px', 'text-align': align }"> |
| | | <view class="uni-table-th-row"> |
| | | <view class="uni-table-th-content" :style="{ 'justify-content': contentAlign }" @click="sort"> |
| | | <slot></slot> |
| | | <view v-if="sortable" class="arrow-box"> |
| | | <text class="arrow up" :class="{ active: ascending }" @click.stop="ascendingFn"></text> |
| | | <text class="arrow down" :class="{ active: descending }" @click.stop="descendingFn"></text> |
| | | </view> |
| | | </view> |
| | | <dropdown v-if="filterType || filterData.length" :filterData="filterData" :filterType="filterType" @change="ondropdown"></dropdown> |
| | | </view> |
| | | </th> |
| | | <!-- #endif --> |
| | | <!-- #ifndef H5 --> |
| | | <view class="uni-table-th" :class="{ 'table--border': border }" :style="{ width: width + 'px', 'text-align': align }"><slot></slot></view> |
| | | <!-- #endif --> |
| | | </template> |
| | | |
| | | <script> |
| | | import dropdown from './filter-dropdown.vue' |
| | | /** |
| | | * Th 表头 |
| | | * @description 表格内的表头单元格组件 |
| | | * @tutorial https://ext.dcloud.net.cn/plugin?id=3270 |
| | | * @property {Number} width 单元格宽度 |
| | | * @property {Boolean} sortable 是否启用排序 |
| | | * @property {Number} align = [left|center|right] 单元格对齐方式 |
| | | * @value left 单元格文字左侧对齐 |
| | | * @value center 单元格文字居中 |
| | | * @value right 单元格文字右侧对齐 |
| | | * @property {Array} filterData 筛选数据 |
| | | * @property {String} filterType [search|select] 筛选类型 |
| | | * @value search 关键字搜素 |
| | | * @value select 条件选择 |
| | | * @event {Function} sort-change 排序触发事件 |
| | | */ |
| | | export default { |
| | | name: 'uniTh', |
| | | options: { |
| | | virtualHost: true |
| | | }, |
| | | components: { |
| | | dropdown |
| | | }, |
| | | emits:['sort-change','filter-change'], |
| | | props: { |
| | | width: { |
| | | type: [String, Number], |
| | | default: '' |
| | | }, |
| | | align: { |
| | | type: String, |
| | | default: 'left' |
| | | }, |
| | | rowspan: { |
| | | type: [Number, String], |
| | | default: 1 |
| | | }, |
| | | colspan: { |
| | | type: [Number, String], |
| | | default: 1 |
| | | }, |
| | | sortable: { |
| | | type: Boolean, |
| | | default: false |
| | | }, |
| | | filterType: { |
| | | type: String, |
| | | default: "" |
| | | }, |
| | | filterData: { |
| | | type: Array, |
| | | default () { |
| | | return [] |
| | | } |
| | | } |
| | | }, |
| | | data() { |
| | | return { |
| | | border: false, |
| | | ascending: false, |
| | | descending: false |
| | | } |
| | | }, |
| | | computed: { |
| | | contentAlign() { |
| | | let align = 'left' |
| | | switch (this.align) { |
| | | case 'left': |
| | | align = 'flex-start' |
| | | break |
| | | case 'center': |
| | | align = 'center' |
| | | break |
| | | case 'right': |
| | | align = 'flex-end' |
| | | break |
| | | } |
| | | return align |
| | | } |
| | | }, |
| | | created() { |
| | | this.root = this.getTable('uniTable') |
| | | this.rootTr = this.getTable('uniTr') |
| | | this.rootTr.minWidthUpdate(this.width ? this.width : 140) |
| | | this.border = this.root.border |
| | | this.root.thChildren.push(this) |
| | | }, |
| | | methods: { |
| | | sort() { |
| | | if (!this.sortable) return |
| | | this.clearOther() |
| | | if (!this.ascending && !this.descending) { |
| | | this.ascending = true |
| | | this.$emit('sort-change', { order: 'ascending' }) |
| | | return |
| | | } |
| | | if (this.ascending && !this.descending) { |
| | | this.ascending = false |
| | | this.descending = true |
| | | this.$emit('sort-change', { order: 'descending' }) |
| | | return |
| | | } |
| | | |
| | | if (!this.ascending && this.descending) { |
| | | this.ascending = false |
| | | this.descending = false |
| | | this.$emit('sort-change', { order: null }) |
| | | } |
| | | }, |
| | | ascendingFn() { |
| | | this.clearOther() |
| | | this.ascending = !this.ascending |
| | | this.descending = false |
| | | this.$emit('sort-change', { order: this.ascending ? 'ascending' : null }) |
| | | }, |
| | | descendingFn() { |
| | | this.clearOther() |
| | | this.descending = !this.descending |
| | | this.ascending = false |
| | | this.$emit('sort-change', { order: this.descending ? 'descending' : null }) |
| | | }, |
| | | clearOther() { |
| | | this.root.thChildren.map(item => { |
| | | if (item !== this) { |
| | | item.ascending = false |
| | | item.descending = false |
| | | } |
| | | return item |
| | | }) |
| | | }, |
| | | ondropdown(e) { |
| | | this.$emit("filter-change", e) |
| | | }, |
| | | /** |
| | | * 获取父元素实例 |
| | | */ |
| | | getTable(name) { |
| | | let parent = this.$parent |
| | | let parentName = parent.$options.name |
| | | while (parentName !== name) { |
| | | parent = parent.$parent |
| | | if (!parent) return false |
| | | parentName = parent.$options.name |
| | | } |
| | | return parent |
| | | } |
| | | } |
| | | } |
| | | </script> |
| | | |
| | | <style lang="scss"> |
| | | $border-color: #ebeef5; |
| | | |
| | | .uni-table-th { |
| | | padding: 12px 10px; |
| | | /* #ifndef APP-NVUE */ |
| | | display: table-cell; |
| | | box-sizing: border-box; |
| | | /* #endif */ |
| | | font-size: 14px; |
| | | font-weight: bold; |
| | | color: #909399; |
| | | border-bottom: 1px $border-color solid; |
| | | } |
| | | |
| | | .uni-table-th-row { |
| | | /* #ifndef APP-NVUE */ |
| | | display: flex; |
| | | /* #endif */ |
| | | flex-direction: row; |
| | | } |
| | | |
| | | .table--border { |
| | | border-right: 1px $border-color solid; |
| | | } |
| | | .uni-table-th-content { |
| | | display: flex; |
| | | align-items: center; |
| | | flex: 1; |
| | | } |
| | | .arrow-box { |
| | | } |
| | | .arrow { |
| | | display: block; |
| | | position: relative; |
| | | width: 10px; |
| | | height: 8px; |
| | | // border: 1px red solid; |
| | | left: 5px; |
| | | overflow: hidden; |
| | | cursor: pointer; |
| | | } |
| | | .down { |
| | | top: 3px; |
| | | ::after { |
| | | content: ''; |
| | | width: 8px; |
| | | height: 8px; |
| | | position: absolute; |
| | | left: 2px; |
| | | top: -5px; |
| | | transform: rotate(45deg); |
| | | background-color: #ccc; |
| | | } |
| | | &.active { |
| | | ::after { |
| | | background-color: #007aff; |
| | | } |
| | | } |
| | | } |
| | | .up { |
| | | ::after { |
| | | content: ''; |
| | | width: 8px; |
| | | height: 8px; |
| | | position: absolute; |
| | | left: 2px; |
| | | top: 5px; |
| | | transform: rotate(45deg); |
| | | background-color: #ccc; |
| | | } |
| | | &.active { |
| | | ::after { |
| | | background-color: #007aff; |
| | | } |
| | | } |
| | | } |
| | | </style> |
| | | <template>
|
| | | <!-- #ifdef H5 -->
|
| | | <th :rowspan="rowspan" :colspan="colspan" class="uni-table-th" :class="{ 'table--border': border }" :style="{ width: width + 'px', 'text-align': align }">
|
| | | <view class="uni-table-th-row">
|
| | | <view class="uni-table-th-content" :style="{ 'justify-content': contentAlign }" @click="sort">
|
| | | <slot></slot>
|
| | | <view v-if="sortable" class="arrow-box">
|
| | | <text class="arrow up" :class="{ active: ascending }" @click.stop="ascendingFn"></text>
|
| | | <text class="arrow down" :class="{ active: descending }" @click.stop="descendingFn"></text>
|
| | | </view>
|
| | | </view>
|
| | | <dropdown v-if="filterType || filterData.length" :filterData="filterData" :filterType="filterType" @change="ondropdown"></dropdown>
|
| | | </view>
|
| | | </th>
|
| | | <!-- #endif -->
|
| | | <!-- #ifndef H5 -->
|
| | | <view class="uni-table-th" :class="{ 'table--border': border }" :style="{ width: width + 'px', 'text-align': align }"><slot></slot></view>
|
| | | <!-- #endif -->
|
| | | </template>
|
| | |
|
| | | <script>
|
| | | import dropdown from './filter-dropdown.vue'
|
| | | /**
|
| | | * Th 表头
|
| | | * @description 表格内的表头单元格组件
|
| | | * @tutorial https://ext.dcloud.net.cn/plugin?id=3270
|
| | | * @property {Number} width 单元格宽度
|
| | | * @property {Boolean} sortable 是否启用排序
|
| | | * @property {Number} align = [left|center|right] 单元格对齐方式
|
| | | * @value left 单元格文字左侧对齐
|
| | | * @value center 单元格文字居中
|
| | | * @value right 单元格文字右侧对齐
|
| | | * @property {Array} filterData 筛选数据
|
| | | * @property {String} filterType [search|select] 筛选类型
|
| | | * @value search 关键字搜素
|
| | | * @value select 条件选择
|
| | | * @event {Function} sort-change 排序触发事件
|
| | | */
|
| | | export default {
|
| | | name: 'uniTh',
|
| | | options: {
|
| | | virtualHost: true
|
| | | },
|
| | | components: {
|
| | | dropdown
|
| | | },
|
| | | emits:['sort-change','filter-change'],
|
| | | props: {
|
| | | width: {
|
| | | type: [String, Number],
|
| | | default: ''
|
| | | },
|
| | | align: {
|
| | | type: String,
|
| | | default: 'left'
|
| | | },
|
| | | rowspan: {
|
| | | type: [Number, String],
|
| | | default: 1
|
| | | },
|
| | | colspan: {
|
| | | type: [Number, String],
|
| | | default: 1
|
| | | },
|
| | | sortable: {
|
| | | type: Boolean,
|
| | | default: false
|
| | | },
|
| | | filterType: {
|
| | | type: String,
|
| | | default: ""
|
| | | },
|
| | | filterData: {
|
| | | type: Array,
|
| | | default () {
|
| | | return []
|
| | | }
|
| | | }
|
| | | },
|
| | | data() {
|
| | | return {
|
| | | border: false,
|
| | | ascending: false,
|
| | | descending: false
|
| | | }
|
| | | },
|
| | | computed: {
|
| | | contentAlign() {
|
| | | let align = 'left'
|
| | | switch (this.align) {
|
| | | case 'left':
|
| | | align = 'flex-start'
|
| | | break
|
| | | case 'center':
|
| | | align = 'center'
|
| | | break
|
| | | case 'right':
|
| | | align = 'flex-end'
|
| | | break
|
| | | }
|
| | | return align
|
| | | }
|
| | | },
|
| | | created() {
|
| | | this.root = this.getTable('uniTable')
|
| | | this.rootTr = this.getTable('uniTr')
|
| | | this.rootTr.minWidthUpdate(this.width ? this.width : 140)
|
| | | this.border = this.root.border
|
| | | this.root.thChildren.push(this)
|
| | | },
|
| | | methods: {
|
| | | sort() {
|
| | | if (!this.sortable) return
|
| | | this.clearOther()
|
| | | if (!this.ascending && !this.descending) {
|
| | | this.ascending = true
|
| | | this.$emit('sort-change', { order: 'ascending' })
|
| | | return
|
| | | }
|
| | | if (this.ascending && !this.descending) {
|
| | | this.ascending = false
|
| | | this.descending = true
|
| | | this.$emit('sort-change', { order: 'descending' })
|
| | | return
|
| | | }
|
| | |
|
| | | if (!this.ascending && this.descending) {
|
| | | this.ascending = false
|
| | | this.descending = false
|
| | | this.$emit('sort-change', { order: null })
|
| | | }
|
| | | },
|
| | | ascendingFn() {
|
| | | this.clearOther()
|
| | | this.ascending = !this.ascending
|
| | | this.descending = false
|
| | | this.$emit('sort-change', { order: this.ascending ? 'ascending' : null })
|
| | | },
|
| | | descendingFn() {
|
| | | this.clearOther()
|
| | | this.descending = !this.descending
|
| | | this.ascending = false
|
| | | this.$emit('sort-change', { order: this.descending ? 'descending' : null })
|
| | | },
|
| | | clearOther() {
|
| | | this.root.thChildren.map(item => {
|
| | | if (item !== this) {
|
| | | item.ascending = false
|
| | | item.descending = false
|
| | | }
|
| | | return item
|
| | | })
|
| | | },
|
| | | ondropdown(e) {
|
| | | this.$emit("filter-change", e)
|
| | | },
|
| | | /**
|
| | | * 获取父元素实例
|
| | | */
|
| | | getTable(name) {
|
| | | let parent = this.$parent
|
| | | let parentName = parent.$options.name
|
| | | while (parentName !== name) {
|
| | | parent = parent.$parent
|
| | | if (!parent) return false
|
| | | parentName = parent.$options.name
|
| | | }
|
| | | return parent
|
| | | }
|
| | | }
|
| | | }
|
| | | </script>
|
| | |
|
| | | <style lang="scss">
|
| | | $border-color: #ebeef5;
|
| | |
|
| | | .uni-table-th {
|
| | | padding: 12px 10px;
|
| | | /* #ifndef APP-NVUE */
|
| | | display: table-cell;
|
| | | box-sizing: border-box;
|
| | | /* #endif */
|
| | | font-size: 14px;
|
| | | font-weight: bold;
|
| | | color: #909399;
|
| | | border-bottom: 1px $border-color solid;
|
| | | }
|
| | |
|
| | | .uni-table-th-row {
|
| | | /* #ifndef APP-NVUE */
|
| | | display: flex;
|
| | | /* #endif */
|
| | | flex-direction: row;
|
| | | }
|
| | |
|
| | | .table--border {
|
| | | border-right: 1px $border-color solid;
|
| | | }
|
| | | .uni-table-th-content {
|
| | | display: flex;
|
| | | align-items: center;
|
| | | flex: 1;
|
| | | }
|
| | | .arrow-box {
|
| | | }
|
| | | .arrow {
|
| | | display: block;
|
| | | position: relative;
|
| | | width: 10px;
|
| | | height: 8px;
|
| | | // border: 1px red solid;
|
| | | left: 5px;
|
| | | overflow: hidden;
|
| | | cursor: pointer;
|
| | | }
|
| | | .down {
|
| | | top: 3px;
|
| | | ::after {
|
| | | content: '';
|
| | | width: 8px;
|
| | | height: 8px;
|
| | | position: absolute;
|
| | | left: 2px;
|
| | | top: -5px;
|
| | | transform: rotate(45deg);
|
| | | background-color: #ccc;
|
| | | }
|
| | | &.active {
|
| | | ::after {
|
| | | background-color: #007aff;
|
| | | }
|
| | | }
|
| | | }
|
| | | .up {
|
| | | ::after {
|
| | | content: '';
|
| | | width: 8px;
|
| | | height: 8px;
|
| | | position: absolute;
|
| | | left: 2px;
|
| | | top: 5px;
|
| | | transform: rotate(45deg);
|
| | | background-color: #ccc;
|
| | | }
|
| | | &.active {
|
| | | ::after {
|
| | | background-color: #007aff;
|
| | | }
|
| | | }
|
| | | }
|
| | | </style>
|