| <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> |