uni-th.vue 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219
  1. <template>
  2. <!-- #ifdef H5 -->
  3. <th :rowspan="rowspan" :colspan="colspan" class="uni-table-th" :class="{ 'table--border': border }" :style="{ width: width + 'px', 'text-align': align }">
  4. <view class="uni-table-th-content" :style="{ 'justify-content': contentAlign }" @click="sort">
  5. <slot></slot>
  6. <view v-if="sortable" class="arrow-box">
  7. <text class="arrow up" :class="{ active: ascending }" @click.stop="ascendingFn"></text>
  8. <text class="arrow down" :class="{ active: descending }" @click.stop="descendingFn"></text>
  9. </view>
  10. </view>
  11. </th>
  12. <!-- #endif -->
  13. <!-- #ifndef H5 -->
  14. <view class="uni-table-th" :class="{ 'table--border': border }" :style="{ width: width + 'px', 'text-align': align }"><slot></slot></view>
  15. <!-- #endif -->
  16. </template>
  17. <script>
  18. /**
  19. * Th 表头
  20. * @description 表格内的表头单元格组件
  21. * @tutorial https://ext.dcloud.net.cn/plugin?id=3270
  22. * @property {Number} width 单元格宽度
  23. * @property {Boolean} sortable 是否启用排序
  24. * @property {Number} align = [left|center|right] 单元格对齐方式
  25. * @value left 单元格文字左侧对齐
  26. * @value center 单元格文字居中
  27. * @value right 单元格文字右侧对齐
  28. * @event {Function} sort-change 排序触发事件
  29. */
  30. export default {
  31. name: 'uniTh',
  32. options: {
  33. virtualHost: true
  34. },
  35. props: {
  36. width: {
  37. type: [String, Number],
  38. default: ''
  39. },
  40. align: {
  41. type: String,
  42. default: 'left'
  43. },
  44. rowspan: {
  45. type: [Number, String],
  46. default: 1
  47. },
  48. colspan: {
  49. type: [Number, String],
  50. default: 1
  51. },
  52. sortable: {
  53. type: Boolean,
  54. default: false
  55. }
  56. },
  57. data() {
  58. return {
  59. border: false,
  60. ascending: false,
  61. descending: false
  62. }
  63. },
  64. computed: {
  65. contentAlign() {
  66. let align = 'left'
  67. switch (this.align) {
  68. case 'left':
  69. align = 'flex-start'
  70. break
  71. case 'center':
  72. align = 'center'
  73. break
  74. case 'right':
  75. align = 'flex-end'
  76. break
  77. }
  78. return align
  79. }
  80. },
  81. created() {
  82. this.root = this.getTable('uniTable')
  83. this.rootTr = this.getTable('uniTr')
  84. this.rootTr.minWidthUpdate(this.width ? this.width : 140)
  85. this.border = this.root.border
  86. this.root.thChildren.push(this)
  87. },
  88. methods: {
  89. sort() {
  90. if (!this.sortable) return
  91. this.clearOther()
  92. if (!this.ascending && !this.descending) {
  93. this.ascending = true
  94. this.$emit('sort-change', { order: 'ascending' })
  95. return
  96. }
  97. if (this.ascending && !this.descending) {
  98. this.ascending = false
  99. this.descending = true
  100. this.$emit('sort-change', { order: 'descending' })
  101. return
  102. }
  103. if (!this.ascending && this.descending) {
  104. this.ascending = false
  105. this.descending = false
  106. this.$emit('sort-change', { order: null })
  107. }
  108. },
  109. ascendingFn() {
  110. this.clearOther()
  111. this.ascending = !this.ascending
  112. this.descending = false
  113. this.$emit('sort-change', { order: this.ascending ? 'ascending' : null })
  114. },
  115. descendingFn() {
  116. this.clearOther()
  117. this.descending = !this.descending
  118. this.ascending = false
  119. this.$emit('sort-change', { order: this.descending ? 'descending' : null })
  120. },
  121. clearOther() {
  122. this.root.thChildren.map(item => {
  123. if (item !== this) {
  124. item.ascending = false
  125. item.descending = false
  126. }
  127. return item
  128. })
  129. },
  130. /**
  131. * 获取父元素实例
  132. */
  133. getTable(name) {
  134. let parent = this.$parent
  135. let parentName = parent.$options.name
  136. while (parentName !== name) {
  137. parent = parent.$parent
  138. if (!parent) return false
  139. parentName = parent.$options.name
  140. }
  141. return parent
  142. }
  143. }
  144. }
  145. </script>
  146. <style lang="scss">
  147. $border-color: #ebeef5;
  148. .uni-table-th {
  149. padding: 12px 10px;
  150. /* #ifndef APP-NVUE */
  151. display: table-cell;
  152. box-sizing: border-box;
  153. /* #endif */
  154. font-size: 14px;
  155. font-weight: bold;
  156. color: #909399;
  157. border-bottom: 1px $border-color solid;
  158. }
  159. .table--border {
  160. border-right: 1px $border-color solid;
  161. }
  162. .uni-table-th-content {
  163. display: flex;
  164. align-items: center;
  165. }
  166. .arrow-box {
  167. }
  168. .arrow {
  169. display: block;
  170. position: relative;
  171. width: 10px;
  172. height: 8px;
  173. // border: 1px red solid;
  174. left: 5px;
  175. overflow: hidden;
  176. cursor: pointer;
  177. }
  178. .down {
  179. top: 3px;
  180. ::after {
  181. content: '';
  182. width: 8px;
  183. height: 8px;
  184. position: absolute;
  185. left: 2px;
  186. top: -5px;
  187. transform: rotate(45deg);
  188. background-color: #ccc;
  189. }
  190. &.active {
  191. ::after {
  192. background-color: #007aff;
  193. }
  194. }
  195. }
  196. .up {
  197. ::after {
  198. content: '';
  199. width: 8px;
  200. height: 8px;
  201. position: absolute;
  202. left: 2px;
  203. top: 5px;
  204. transform: rotate(45deg);
  205. background-color: #ccc;
  206. }
  207. &.active {
  208. ::after {
  209. background-color: #007aff;
  210. }
  211. }
  212. }
  213. </style>