table-body.js 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251
  1. import { getCell, getColumnByCell, getRowIdentity } from './util';
  2. import ElCheckbox from 'element-ui/packages/checkbox';
  3. export default {
  4. components: {
  5. ElCheckbox
  6. },
  7. props: {
  8. store: {
  9. required: true
  10. },
  11. context: {},
  12. layout: {
  13. required: true
  14. },
  15. rowClassName: [String, Function],
  16. rowStyle: [Object, Function],
  17. fixed: String,
  18. highlight: Boolean
  19. },
  20. render(h) {
  21. const columnsHidden = this.columns.map((column, index) => this.isColumnHidden(index));
  22. return (
  23. <table
  24. class="el-table__body"
  25. cellspacing="0"
  26. cellpadding="0"
  27. border="0">
  28. <colgroup>
  29. {
  30. this._l(this.columns, column =>
  31. <col
  32. name={ column.id }
  33. width={ column.realWidth || column.width }
  34. />)
  35. }
  36. </colgroup>
  37. <tbody>
  38. {
  39. this._l(this.data, (row, $index) =>
  40. [<tr
  41. style={ this.rowStyle ? this.getRowStyle(row, $index) : null }
  42. key={ this.table.rowKey ? this.getKeyOfRow(row, $index) : $index }
  43. on-dblclick={ ($event) => this.handleDoubleClick($event, row) }
  44. on-click={ ($event) => this.handleClick($event, row) }
  45. on-contextmenu={ ($event) => this.handleContextMenu($event, row) }
  46. on-mouseenter={ _ => this.handleMouseEnter($index) }
  47. on-mouseleave={ _ => this.handleMouseLeave() }
  48. class={ [this.getRowClass(row, $index)] }>
  49. {
  50. this._l(this.columns, (column, cellIndex) =>
  51. <td
  52. class={ [column.id, column.align, column.className || '', columnsHidden[cellIndex] ? 'is-hidden' : '' ] }
  53. on-mouseenter={ ($event) => this.handleCellMouseEnter($event, row) }
  54. on-mouseleave={ this.handleCellMouseLeave }>
  55. {
  56. column.renderCell.call(this._renderProxy, h, { row, column, $index, store: this.store, _self: this.context || this.table.$vnode.context }, columnsHidden[cellIndex])
  57. }
  58. </td>
  59. )
  60. }
  61. {
  62. !this.fixed && this.layout.scrollY && this.layout.gutterWidth ? <td class="gutter" /> : ''
  63. }
  64. </tr>,
  65. this.store.states.expandRows.indexOf(row) > -1
  66. ? (<tr>
  67. <td colspan={ this.columns.length } class="el-table__expanded-cell">
  68. { this.table.renderExpanded ? this.table.renderExpanded(h, { row, $index, store: this.store }) : ''}
  69. </td>
  70. </tr>)
  71. : ''
  72. ]
  73. )
  74. }
  75. </tbody>
  76. </table>
  77. );
  78. },
  79. watch: {
  80. 'store.states.hoverRow'(newVal, oldVal) {
  81. if (!this.store.states.isComplex) return;
  82. const el = this.$el;
  83. if (!el) return;
  84. const rows = el.querySelectorAll('tbody > tr');
  85. const oldRow = rows[oldVal];
  86. const newRow = rows[newVal];
  87. if (oldRow) {
  88. oldRow.classList.remove('hover-row');
  89. }
  90. if (newRow) {
  91. newRow.classList.add('hover-row');
  92. }
  93. },
  94. 'store.states.currentRow'(newVal, oldVal) {
  95. if (!this.highlight) return;
  96. const el = this.$el;
  97. if (!el) return;
  98. const data = this.store.states.data;
  99. const rows = el.querySelectorAll('tbody > tr');
  100. const oldRow = rows[data.indexOf(oldVal)];
  101. const newRow = rows[data.indexOf(newVal)];
  102. if (oldRow) {
  103. oldRow.classList.remove('current-row');
  104. } else if (rows) {
  105. [].forEach.call(rows, row => row.classList.remove('current-row'));
  106. }
  107. if (newRow) {
  108. newRow.classList.add('current-row');
  109. }
  110. }
  111. },
  112. computed: {
  113. table() {
  114. return this.$parent;
  115. },
  116. data() {
  117. return this.store.states.data;
  118. },
  119. columnsCount() {
  120. return this.store.states.columns.length;
  121. },
  122. leftFixedCount() {
  123. return this.store.states.fixedColumns.length;
  124. },
  125. rightFixedCount() {
  126. return this.store.states.rightFixedColumns.length;
  127. },
  128. columns() {
  129. return this.store.states.columns;
  130. }
  131. },
  132. data() {
  133. return {
  134. tooltipDisabled: true
  135. };
  136. },
  137. methods: {
  138. getKeyOfRow(row, index) {
  139. const rowKey = this.table.rowKey;
  140. if (rowKey) {
  141. return getRowIdentity(row, rowKey);
  142. }
  143. return index;
  144. },
  145. isColumnHidden(index) {
  146. if (this.fixed === true || this.fixed === 'left') {
  147. return index >= this.leftFixedCount;
  148. } else if (this.fixed === 'right') {
  149. return index < this.columnsCount - this.rightFixedCount;
  150. } else {
  151. return (index < this.leftFixedCount) || (index >= this.columnsCount - this.rightFixedCount);
  152. }
  153. },
  154. getRowStyle(row, index) {
  155. const rowStyle = this.rowStyle;
  156. if (typeof rowStyle === 'function') {
  157. return rowStyle.call(null, row, index);
  158. }
  159. return rowStyle;
  160. },
  161. getRowClass(row, index) {
  162. const classes = [];
  163. const rowClassName = this.rowClassName;
  164. if (typeof rowClassName === 'string') {
  165. classes.push(rowClassName);
  166. } else if (typeof rowClassName === 'function') {
  167. classes.push(rowClassName.call(null, row, index) || '');
  168. }
  169. return classes.join(' ');
  170. },
  171. handleCellMouseEnter(event, row) {
  172. const table = this.table;
  173. const cell = getCell(event);
  174. if (cell) {
  175. const column = getColumnByCell(table, cell);
  176. const hoverState = table.hoverState = {cell, column, row};
  177. table.$emit('cell-mouse-enter', hoverState.row, hoverState.column, hoverState.cell, event);
  178. }
  179. // 判断是否text-overflow, 如果是就显示tooltip
  180. const cellChild = event.target.querySelector('.cell');
  181. this.tooltipDisabled = cellChild.scrollWidth <= cellChild.offsetWidth;
  182. },
  183. handleCellMouseLeave(event) {
  184. const cell = getCell(event);
  185. if (!cell) return;
  186. const oldHoverState = this.table.hoverState;
  187. this.table.$emit('cell-mouse-leave', oldHoverState.row, oldHoverState.column, oldHoverState.cell, event);
  188. },
  189. handleMouseEnter(index) {
  190. this.store.commit('setHoverRow', index);
  191. },
  192. handleMouseLeave() {
  193. this.store.commit('setHoverRow', null);
  194. },
  195. handleContextMenu(event, row) {
  196. this.handleEvent(event, row, 'contextmenu');
  197. },
  198. handleDoubleClick(event, row) {
  199. this.handleEvent(event, row, 'dblclick');
  200. },
  201. handleClick(event, row) {
  202. this.store.commit('setCurrentRow', row);
  203. this.handleEvent(event, row, 'click');
  204. },
  205. handleEvent(event, row, name) {
  206. const table = this.table;
  207. const cell = getCell(event);
  208. let column;
  209. if (cell) {
  210. column = getColumnByCell(table, cell);
  211. if (column) {
  212. table.$emit(`cell-${name}`, row, column, cell, event);
  213. }
  214. }
  215. table.$emit(`row-${name}`, row, event, column);
  216. },
  217. handleExpandClick(row) {
  218. this.store.commit('toggleRowExpanded', row);
  219. }
  220. }
  221. };