Descriptions.vue 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159
  1. /**
  2. * 详情描述组件
  3. * https://github.com/winkay/vue-descriptions-component/blob/master/src/components/Descriptions/Descriptions.vue
  4. */
  5. <template>
  6. <div>
  7. <div class="description-title">
  8. <slot name='title'>{{title}}</slot>
  9. </div>
  10. <div class="description-view">
  11. <table class="description-table">
  12. <tbody>
  13. <tr :key="key" class="description-tr" v-for="(row, key) in rows">
  14. <template v-for="(item, index) in row">
  15. <th class="description-label" :key="'label-' + key + '-' + index">
  16. {{item.label}}
  17. </th>
  18. <td class="description-content" :colSpan="item.span*2-1" :key="'content-' + key + '-' + index">
  19. <description-content :item="item"></description-content>
  20. </td>
  21. </template>
  22. </tr>
  23. </tbody>
  24. </table>
  25. </div>
  26. </div>
  27. </template>
  28. <script>
  29. export default {
  30. name: 'descriptions',
  31. components: {
  32. // 描述内容子组件渲染
  33. DescriptionContent: {
  34. props: {
  35. item: Object
  36. },
  37. render(h) {
  38. return this.item.children
  39. }
  40. }
  41. },
  42. props: {
  43. title: null, // 描述内容标题
  44. column: { // 每行显示的项目个数
  45. type: Number,
  46. default: 4
  47. }
  48. },
  49. data() {
  50. return {
  51. rows: []
  52. }
  53. },
  54. watch: {
  55. column(value) {
  56. this.generateChildrenRow(this.$slots.default || [])
  57. }
  58. },
  59. mounted() {
  60. this.generateChildrenRow(this.$slots.default || [])
  61. },
  62. beforeUpdate() {
  63. this.generateChildrenRow(this.$slots.default || [])
  64. },
  65. methods: {
  66. // 获取描述内容子项
  67. generateChildrenRow(dataSource) {
  68. const dataList = dataSource.filter(item => item.tag === 'descriptions-item')
  69. this.rows = []
  70. let leftSpan = this.column
  71. let children = []
  72. dataList.forEach((item, index) => {
  73. const itemAttrs = item.data.attrs || {}
  74. // 处理column与span之间的关系
  75. if (leftSpan <= (itemAttrs.span || 1)) { // 剩余的列数小于设置的span个数
  76. itemAttrs.span = leftSpan
  77. leftSpan = 0
  78. } else {
  79. leftSpan -= itemAttrs.span || 1
  80. }
  81. children.push({
  82. span: itemAttrs.span || 1,
  83. label: (item.data && itemAttrs.label) || '',
  84. ...item
  85. })
  86. if (leftSpan <= 0) {
  87. leftSpan = this.column
  88. this.$set(this.rows, this.rows.length, children)
  89. children = []
  90. }
  91. // 最后一行
  92. if (dataList.length % this.column < this.column && index === (dataList.length - 1)) {
  93. this.$set(this.rows, this.rows.length, children)
  94. }
  95. })
  96. }
  97. }
  98. }
  99. </script>
  100. <style scoped>
  101. .description-title {
  102. margin-bottom: 20px;
  103. color: rgba(0,0,0,.85);
  104. font-weight: 700;
  105. font-size: 16px;
  106. line-height: 1.5;
  107. }
  108. .description-view {
  109. width: 100%;
  110. border: 1px solid #e8e8e8;
  111. }
  112. .description-view .description-table {
  113. width: 100%;
  114. /* border: 1px solid #e8e8e8; */
  115. border-collapse: collapse;
  116. table-layout: fixed;
  117. }
  118. .description-view .description-tr {
  119. border-bottom: 1px solid #e8e8e8;
  120. width: 100%;
  121. }
  122. .description-view .description-tr:last-child {
  123. border-bottom: none;
  124. }
  125. .description-view .description-label {
  126. border-right: 1px solid #e8e8e8;
  127. background-color: #fafafa;
  128. color: rgba(0, 0, 0, 0.85);
  129. font-weight: 400;
  130. font-size: 14px;
  131. line-height: 22px;
  132. /* margin-right: 8px; */
  133. padding: 12px 16px;
  134. white-space: nowrap;
  135. display: table-cell;
  136. }
  137. .description-view .description-label:after {
  138. content: ""; /** content: ":" */
  139. margin: 0 8px 0 2px;
  140. position: relative;
  141. top: -0.5px;
  142. }
  143. .description-view .description-content {
  144. white-space: nowrap;
  145. overflow: hidden;
  146. text-overflow: ellipsis;
  147. border-right: 1px solid #e8e8e8;
  148. font-size: 14px;
  149. line-height: 1.5;
  150. padding: 12px 16px;
  151. color: rgba(0, 0, 0, 0.65);
  152. display: table-cell;
  153. }
  154. .description-tr .description-content:last-child {
  155. border-right: none;
  156. }
  157. </style>