table.js 39 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249
  1. import XEUtils from 'xe-utils/ctor'
  2. import GlobalConfig from '../../conf'
  3. import VXETable from '../../v-x-e-table'
  4. import VxeTableBody from '../../body'
  5. import { UtilTools, DomTools, GlobalEvent, ResizeEvent } from '../../tools'
  6. import methods from './methods'
  7. /**
  8. * 渲染浮固定列
  9. * 分别渲染左边固定列和右边固定列
  10. * 如果宽度足够情况下,则不需要渲染固定列
  11. * @param {Function} h 创建 VNode 函数
  12. * @param {Object} $xetable 表格实例
  13. * @param {String} fixedType 固定列类型
  14. */
  15. function renderFixed (h, $xetable, fixedType) {
  16. const { tableData, tableColumn, visibleColumn, tableGroupColumn, isGroup, vSize, showHeader, showFooter, columnStore, footerTableData } = $xetable
  17. const fixedColumn = columnStore[`${fixedType}List`]
  18. return h('div', {
  19. class: `vxe-table--fixed-${fixedType}-wrapper`,
  20. ref: `${fixedType}Container`
  21. }, [
  22. showHeader ? h('vxe-table-header', {
  23. props: {
  24. fixedType,
  25. tableData,
  26. tableColumn,
  27. visibleColumn,
  28. tableGroupColumn,
  29. size: vSize,
  30. fixedColumn,
  31. isGroup
  32. },
  33. ref: `${fixedType}Header`
  34. }) : null,
  35. h('vxe-table-body', {
  36. props: {
  37. fixedType,
  38. tableData,
  39. tableColumn,
  40. visibleColumn,
  41. fixedColumn,
  42. size: vSize,
  43. isGroup
  44. },
  45. ref: `${fixedType}Body`
  46. }),
  47. showFooter && footerTableData ? h('vxe-table-footer', {
  48. props: {
  49. footerTableData,
  50. tableColumn,
  51. visibleColumn,
  52. fixedColumn,
  53. fixedType,
  54. size: vSize
  55. },
  56. ref: `${fixedType}Footer`
  57. }) : null
  58. ])
  59. }
  60. export default {
  61. name: 'VxeTable',
  62. props: {
  63. /** 基本属性 */
  64. id: String,
  65. // 数据
  66. data: Array,
  67. // (v3.0 废弃)
  68. customs: Array,
  69. // 表格的高度
  70. height: [Number, String],
  71. // 表格的最大高度
  72. maxHeight: [Number, String],
  73. // 所有列是否允许拖动列宽调整大小
  74. resizable: { type: Boolean, default: () => GlobalConfig.table.resizable },
  75. // 是否带有斑马纹
  76. stripe: { type: Boolean, default: () => GlobalConfig.table.stripe },
  77. // 是否带有边框
  78. border: { type: [Boolean, String], default: () => GlobalConfig.table.border },
  79. // 是否圆角边框
  80. round: { type: Boolean, default: () => GlobalConfig.table.round },
  81. // 表格的尺寸
  82. size: { type: String, default: () => GlobalConfig.table.size || GlobalConfig.size },
  83. // 列的宽度是否自撑开(可能会被废弃的参数,不要使用)
  84. fit: { type: Boolean, default: () => GlobalConfig.table.fit },
  85. // 表格是否加载中
  86. loading: Boolean,
  87. // 所有的列对其方式
  88. align: { type: String, default: () => GlobalConfig.table.align },
  89. // 所有的表头列的对齐方式
  90. headerAlign: { type: String, default: () => GlobalConfig.table.headerAlign },
  91. // 所有的表尾列的对齐方式
  92. footerAlign: { type: String, default: () => GlobalConfig.table.footerAlign },
  93. // 是否显示表头
  94. showHeader: { type: Boolean, default: () => GlobalConfig.table.showHeader },
  95. // (v3.0 废弃)
  96. startIndex: { type: Number, default: 0 },
  97. // 是否要高亮当前选中行
  98. highlightCurrentRow: { type: Boolean, default: () => GlobalConfig.table.highlightCurrentRow },
  99. // 鼠标移到行是否要高亮显示
  100. highlightHoverRow: { type: Boolean, default: () => GlobalConfig.table.highlightHoverRow },
  101. // 是否要高亮当前选中列
  102. highlightCurrentColumn: { type: Boolean, default: () => GlobalConfig.table.highlightCurrentColumn },
  103. // 鼠标移到列是否要高亮显示
  104. highlightHoverColumn: { type: Boolean, default: () => GlobalConfig.table.highlightHoverColumn },
  105. // 激活单元格编辑时是否高亮显示
  106. highlightCell: Boolean,
  107. // 是否显示表尾合计
  108. showFooter: Boolean,
  109. // 表尾合计的计算方法
  110. footerMethod: { type: Function, default: GlobalConfig.table.footerMethod },
  111. // 给行附加 className
  112. rowClassName: [String, Function],
  113. // 给单元格附加 className
  114. cellClassName: [String, Function],
  115. // 给表头的行附加 className
  116. headerRowClassName: [String, Function],
  117. // 给表头的单元格附加 className
  118. headerCellClassName: [String, Function],
  119. // 给表尾的行附加 className
  120. footerRowClassName: [String, Function],
  121. // 给表尾的单元格附加 className
  122. footerCellClassName: [String, Function],
  123. // 给单元格附加样式
  124. cellStyle: [Object, Function],
  125. // 给表头单元格附加样式
  126. headerCellStyle: [Object, Function],
  127. // 给表尾单元格附加样式
  128. footerCellStyle: [Object, Function],
  129. // 给行附加样式
  130. rowStyle: [Object, Function],
  131. // 给表头行附加样式
  132. headerRowStyle: [Object, Function],
  133. // 给表尾行附加样式
  134. footerRowStyle: [Object, Function],
  135. // 合并指定单元格
  136. mergeCells: Array,
  137. // 合并指定的表尾数据
  138. mergeFooterItems: Array,
  139. // 自定义合并行或列的方法
  140. spanMethod: Function,
  141. // 表尾合并行或列
  142. footerSpanMethod: Function,
  143. // 设置所有内容过长时显示为省略号
  144. showOverflow: { type: [Boolean, String], default: () => GlobalConfig.table.showOverflow },
  145. // 设置表头所有内容过长时显示为省略号
  146. showHeaderOverflow: { type: [Boolean, String], default: () => GlobalConfig.table.showHeaderOverflow },
  147. // 设置表尾所有内容过长时显示为省略号
  148. showFooterOverflow: { type: [Boolean, String], default: () => GlobalConfig.table.showFooterOverflow },
  149. // 是否所有服务端筛选
  150. remoteFilter: Boolean,
  151. // 是否所有服务端排序
  152. remoteSort: Boolean,
  153. // 自定义所有列的排序方法
  154. sortMethod: Function,
  155. // 所有列宽度
  156. columnWidth: [Number, String],
  157. // 所有列最小宽度,把剩余宽度按比例分配
  158. columnMinWidth: [Number, String],
  159. /** 高级属性 */
  160. // 主键配置
  161. columnKey: Boolean,
  162. rowKey: Boolean,
  163. rowId: { type: String, default: () => GlobalConfig.table.rowId },
  164. zIndex: Number,
  165. emptyText: { type: String, default: () => GlobalConfig.table.emptyText },
  166. keepSource: { type: Boolean, default: () => GlobalConfig.table.keepSource },
  167. // 是否自动监听父容器变化去更新响应式表格宽高
  168. autoResize: { type: Boolean, default: () => GlobalConfig.table.autoResize },
  169. // 是否自动根据状态属性去更新响应式表格宽高
  170. syncResize: [Boolean, String, Number],
  171. // 设置列的默认参数,仅对部分支持的属性有效
  172. columnConfig: Object,
  173. resizableConfig: Object,
  174. // 序号配置项
  175. seqConfig: Object,
  176. // 排序配置项
  177. sortConfig: Object,
  178. // 筛选配置项
  179. filterConfig: Object,
  180. // 单选框配置
  181. radioConfig: Object,
  182. // (v3.0 废弃)
  183. selectConfig: Object,
  184. // 复选框配置项
  185. checkboxConfig: Object,
  186. // tooltip 配置项
  187. tooltipConfig: Object,
  188. // 导出配置项
  189. exportConfig: [Boolean, Object],
  190. // 导入配置项
  191. importConfig: [Boolean, Object],
  192. // 打印配置项
  193. printConfig: Object,
  194. // 展开行配置项
  195. expandConfig: Object,
  196. // 树形结构配置项
  197. treeConfig: [Boolean, Object],
  198. // 快捷菜单配置项
  199. menuConfig: [Boolean, Object],
  200. // 在 v3 中废弃
  201. contextMenu: [Boolean, Object],
  202. // 鼠标配置项
  203. mouseConfig: Object,
  204. // 区域配置项
  205. areaConfig: Object,
  206. // 按键配置项
  207. keyboardConfig: Object,
  208. // 复制/粘贴配置项
  209. clipConfig: Object,
  210. // 查找/替换配置项
  211. fnrConfig: Object,
  212. // 编辑配置项
  213. editConfig: [Boolean, Object],
  214. // 校验配置项
  215. validConfig: Object,
  216. // 校验规则配置项
  217. editRules: Object,
  218. // 空内容渲染配置项
  219. emptyRender: [Boolean, Object],
  220. // 自定义列配置项
  221. customConfig: [Boolean, Object],
  222. // 横向虚拟滚动配置项
  223. scrollX: Object,
  224. // 纵向虚拟滚动配置项
  225. scrollY: Object,
  226. // 优化相关
  227. cloak: { type: Boolean, default: () => GlobalConfig.table.cloak },
  228. animat: { type: Boolean, default: () => GlobalConfig.table.animat },
  229. delayHover: { type: Number, default: () => GlobalConfig.table.delayHover },
  230. // 优化配置项
  231. optimization: Object,
  232. // 额外的参数
  233. params: Object
  234. },
  235. components: {
  236. VxeTableBody
  237. },
  238. provide () {
  239. return {
  240. $xetable: this,
  241. xecolgroup: null
  242. }
  243. },
  244. inject: {
  245. $xegrid: {
  246. default: null
  247. }
  248. },
  249. mixins: [],
  250. data () {
  251. return {
  252. tId: `${XEUtils.uniqueId()}`,
  253. isCloak: false,
  254. // 列分组配置
  255. collectColumn: [],
  256. // 渲染的列分组
  257. tableGroupColumn: [],
  258. // 完整所有列
  259. tableFullColumn: [],
  260. // 渲染所有列
  261. visibleColumn: [],
  262. // 可视区渲染的列
  263. tableColumn: [],
  264. // 渲染中的数据
  265. tableData: [],
  266. // 是否启用了横向 X 可视渲染方式加载
  267. scrollXLoad: false,
  268. // 是否启用了纵向 Y 可视渲染方式加载
  269. scrollYLoad: false,
  270. // 是否存在纵向滚动条
  271. overflowY: true,
  272. // 是否存在横向滚动条
  273. overflowX: false,
  274. // 纵向滚动条的宽度
  275. scrollbarWidth: 0,
  276. // 横向滚动条的高度
  277. scrollbarHeight: 0,
  278. // 行高
  279. rowHeight: 0,
  280. // 表格父容器的高度
  281. parentHeight: 0,
  282. // 复选框属性,是否全选
  283. isAllSelected: false,
  284. // 复选框属性,有选中且非全选状态
  285. isIndeterminate: false,
  286. // 复选框属性,已选中的行
  287. selection: [],
  288. // 当前行
  289. currentRow: null,
  290. // 单选框属性,选中列
  291. currentColumn: null,
  292. // 单选框属性,选中行
  293. selectRow: null,
  294. // 表尾合计数据
  295. footerTableData: [],
  296. // 展开列信息
  297. expandColumn: null,
  298. // 树节点列信息
  299. treeNodeColumn: null,
  300. // 已展开的行
  301. rowExpandeds: [],
  302. // 懒加载中的展开行的列表
  303. expandLazyLoadeds: [],
  304. // 已展开树节点
  305. treeExpandeds: [],
  306. // 懒加载中的树节点的列表
  307. treeLazyLoadeds: [],
  308. // 树节点不确定状态的列表
  309. treeIndeterminates: [],
  310. // 合并单元格的对象集
  311. mergeList: [],
  312. // 合并表尾数据的对象集
  313. mergeFooterList: [],
  314. // 是否已经加载了筛选
  315. hasFilterPanel: false,
  316. // 当前选中的筛选列
  317. filterStore: {
  318. isAllSelected: false,
  319. isIndeterminate: false,
  320. style: null,
  321. options: [],
  322. column: null,
  323. multiple: false,
  324. visible: false
  325. },
  326. // 存放列相关的信息
  327. columnStore: {
  328. leftList: [],
  329. centerList: [],
  330. rightList: [],
  331. resizeList: [],
  332. pxList: [],
  333. pxMinList: [],
  334. scaleList: [],
  335. scaleMinList: [],
  336. autoList: []
  337. },
  338. // 存放快捷菜单的信息
  339. ctxMenuStore: {
  340. selected: null,
  341. visible: false,
  342. showChild: false,
  343. selectChild: null,
  344. list: [],
  345. style: null
  346. },
  347. // 存放可编辑相关信息
  348. editStore: {
  349. indexs: {
  350. columns: []
  351. },
  352. titles: {
  353. columns: []
  354. },
  355. // 所有选中
  356. checked: {
  357. rows: [],
  358. columns: [],
  359. tRows: [],
  360. tColumns: []
  361. },
  362. // 选中源
  363. selected: {
  364. row: null,
  365. column: null
  366. },
  367. // 已复制源
  368. copyed: {
  369. cut: false,
  370. rows: [],
  371. columns: []
  372. },
  373. // 激活
  374. actived: {
  375. row: null,
  376. column: null
  377. },
  378. insertList: [],
  379. removeList: []
  380. },
  381. // 存放数据校验相关信息
  382. validStore: {
  383. visible: false,
  384. row: null,
  385. column: null,
  386. content: '',
  387. rule: null,
  388. isArrow: false
  389. },
  390. // 导入相关信息
  391. importStore: {
  392. file: null,
  393. type: '',
  394. modeList: [],
  395. typeList: [],
  396. filename: '',
  397. visible: false
  398. },
  399. importParams: {
  400. mode: '',
  401. types: null,
  402. message: true
  403. },
  404. // 导出相关信息
  405. exportStore: {
  406. name: '',
  407. modeList: [],
  408. typeList: [],
  409. columns: [],
  410. hasFooter: false,
  411. visible: false
  412. },
  413. exportParams: {
  414. filename: '',
  415. sheetName: '',
  416. mode: '',
  417. type: '',
  418. original: false,
  419. message: true,
  420. isHeader: false,
  421. isFooter: false
  422. }
  423. }
  424. },
  425. computed: {
  426. vSize () {
  427. return this.size || this.$parent.size || this.$parent.vSize
  428. },
  429. validOpts () {
  430. return Object.assign({ message: 'default' }, GlobalConfig.table.validConfig, this.validConfig)
  431. },
  432. sXOpts () {
  433. return Object.assign({}, GlobalConfig.table.scrollX, this.optimizeOpts.scrollX, this.scrollX)
  434. },
  435. sYOpts () {
  436. return Object.assign({}, GlobalConfig.table.scrollY, this.optimizeOpts.scrollY, this.scrollY)
  437. },
  438. optimizeOpts () {
  439. return Object.assign({}, GlobalConfig.table.optimization, this.optimization)
  440. },
  441. rowHeightMaps () {
  442. return {
  443. default: 48,
  444. medium: 44,
  445. small: 40,
  446. mini: 36
  447. }
  448. },
  449. columnOpts () {
  450. return Object.assign({}, this.columnConfig)
  451. },
  452. resizableOpts () {
  453. return Object.assign({}, GlobalConfig.table.resizableConfig, this.resizableConfig)
  454. },
  455. seqOpts () {
  456. return Object.assign({ startIndex: 0 }, GlobalConfig.table.seqConfig, this.seqConfig)
  457. },
  458. radioOpts () {
  459. return Object.assign({}, GlobalConfig.table.radioConfig, this.radioConfig)
  460. },
  461. checkboxOpts () {
  462. return Object.assign({}, GlobalConfig.table.checkboxConfig, this.checkboxConfig || this.selectConfig)
  463. },
  464. tooltipOpts () {
  465. return Object.assign({ size: this.vSize, leaveDelay: 300 }, GlobalConfig.table.tooltipConfig, this.tooltipConfig)
  466. },
  467. validTipOpts () {
  468. return Object.assign({ isArrow: false }, this.tooltipOpts)
  469. },
  470. editOpts () {
  471. return Object.assign({}, GlobalConfig.table.editConfig, this.editConfig)
  472. },
  473. sortOpts () {
  474. return Object.assign({ orders: ['asc', 'desc', null] }, GlobalConfig.table.sortConfig, this.sortConfig)
  475. },
  476. filterOpts () {
  477. return Object.assign({}, GlobalConfig.table.filterConfig, this.filterConfig)
  478. },
  479. mouseOpts () {
  480. return Object.assign({}, GlobalConfig.table.mouseConfig, this.mouseConfig)
  481. },
  482. areaOpts () {
  483. return Object.assign({}, GlobalConfig.table.areaConfig, this.areaConfig)
  484. },
  485. keyboardOpts () {
  486. return Object.assign({}, GlobalConfig.table.keyboardConfig, this.keyboardConfig)
  487. },
  488. clipOpts () {
  489. return Object.assign({}, GlobalConfig.table.clipConfig, this.clipConfig)
  490. },
  491. fnrOpts () {
  492. return Object.assign({}, GlobalConfig.table.fnrConfig, this.fnrConfig)
  493. },
  494. // 是否使用了分组表头
  495. isGroup () {
  496. return this.collectColumn.some(UtilTools.hasChildrenList)
  497. },
  498. hasTip () {
  499. return VXETable._tooltip
  500. },
  501. isResizable () {
  502. return this.resizable || this.tableFullColumn.some(column => column.resizable)
  503. },
  504. headerCtxMenu () {
  505. const headerOpts = this.ctxMenuOpts.header
  506. return headerOpts && headerOpts.options ? headerOpts.options : []
  507. },
  508. bodyCtxMenu () {
  509. const bodyOpts = this.ctxMenuOpts.body
  510. return bodyOpts && bodyOpts.options ? bodyOpts.options : []
  511. },
  512. footerCtxMenu () {
  513. const footerOpts = this.ctxMenuOpts.footer
  514. return footerOpts && footerOpts.options ? footerOpts.options : []
  515. },
  516. isCtxMenu () {
  517. return (this.contextMenu || this.menuConfig) && UtilTools.isEnableConf(this.ctxMenuOpts) && (this.headerCtxMenu.length || this.bodyCtxMenu.length || this.footerCtxMenu.length)
  518. },
  519. ctxMenuOpts () {
  520. return Object.assign({}, GlobalConfig.table.contextMenu, GlobalConfig.table.menuConfig, this.contextMenu, this.menuConfig)
  521. },
  522. ctxMenuList () {
  523. const rest = []
  524. this.ctxMenuStore.list.forEach(list => {
  525. list.forEach(item => {
  526. rest.push(item)
  527. })
  528. })
  529. return rest
  530. },
  531. exportOpts () {
  532. return Object.assign({}, GlobalConfig.table.exportConfig, this.exportConfig)
  533. },
  534. importOpts () {
  535. return Object.assign({}, GlobalConfig.table.importConfig, this.importConfig)
  536. },
  537. printOpts () {
  538. return Object.assign({}, GlobalConfig.table.printConfig, this.printConfig)
  539. },
  540. expandOpts () {
  541. return Object.assign({}, GlobalConfig.table.expandConfig, this.expandConfig)
  542. },
  543. treeOpts () {
  544. return Object.assign({}, GlobalConfig.table.treeConfig, this.treeConfig)
  545. },
  546. emptyOpts () {
  547. return Object.assign({}, GlobalConfig.table.emptyRender, this.emptyRender)
  548. },
  549. cellOffsetWidth () {
  550. return this.border ? Math.max(2, Math.ceil(this.scrollbarWidth / this.tableColumn.length)) : 1
  551. },
  552. customOpts () {
  553. return Object.assign({}, GlobalConfig.table.customConfig, this.customConfig)
  554. },
  555. tableBorder () {
  556. const { border } = this
  557. if (border === true) {
  558. return 'full'
  559. }
  560. if (border) {
  561. return border
  562. }
  563. return 'default'
  564. },
  565. /**
  566. * 判断列全选的复选框是否禁用
  567. */
  568. isAllCheckboxDisabled () {
  569. const { tableFullData, treeConfig, checkboxOpts } = this
  570. const { strict, checkMethod } = checkboxOpts
  571. if (strict) {
  572. if (tableFullData.length) {
  573. if (checkMethod) {
  574. if (treeConfig) {
  575. // 暂时不支持树形结构
  576. }
  577. // 如果所有行都被禁用
  578. return tableFullData.every((row) => !checkMethod({ row }))
  579. }
  580. return false
  581. }
  582. return true
  583. }
  584. return false
  585. }
  586. },
  587. watch: {
  588. data (value) {
  589. this.loadTableData(value).then(() => {
  590. if (!this.inited) {
  591. this.inited = true
  592. this.handleDefaults()
  593. }
  594. if ((this.scrollXLoad || this.scrollYLoad) && this.expandColumn) {
  595. UtilTools.warn('vxe.error.scrollErrProp', ['column.type=expand'])
  596. }
  597. })
  598. },
  599. customs (value) {
  600. if (!this.isUpdateCustoms) {
  601. this.mergeCustomColumn(value)
  602. }
  603. this.isUpdateCustoms = false
  604. },
  605. collectColumn (value) {
  606. const tableFullColumn = UtilTools.getColumnList(value)
  607. this.tableFullColumn = tableFullColumn
  608. this.clearMergeCells()
  609. this.clearMergeFooterItems()
  610. this.cacheColumnMap()
  611. if (this.customs) {
  612. this.mergeCustomColumn(this.customs)
  613. }
  614. if (this.customConfig) {
  615. this.restoreCustomStorage()
  616. }
  617. this.refreshColumn().then(() => {
  618. if (this.scrollXLoad) {
  619. this.loadScrollXData(true)
  620. }
  621. })
  622. this.handleTableData(true)
  623. if ((this.scrollXLoad || this.scrollYLoad) && this.expandColumn) {
  624. UtilTools.warn('vxe.error.scrollErrProp', ['column.type=expand'])
  625. }
  626. if (this.isGroup && this.mouseConfig && this.mouseOpts.checked) {
  627. UtilTools.error('vxe.error.groupMouseRange', ['mouse-config.checked'])
  628. }
  629. this.$nextTick(() => {
  630. if (this.$toolbar) {
  631. this.$toolbar.syncUpdate({ collectColumn: value, $table: this })
  632. // 在 v3.0 中废弃 toolbar 方式
  633. if (!this.customConfig) {
  634. this.restoreCustomStorage()
  635. this.analyColumnWidth()
  636. this.refreshColumn()
  637. }
  638. }
  639. })
  640. },
  641. tableColumn () {
  642. this.analyColumnWidth()
  643. },
  644. showHeader () {
  645. this.$nextTick(() => {
  646. this.recalculate(true).then(() => this.refreshScroll())
  647. })
  648. },
  649. showFooter () {
  650. this.$nextTick(() => {
  651. this.recalculate(true).then(() => this.refreshScroll())
  652. })
  653. },
  654. height () {
  655. this.$nextTick(() => this.recalculate(true))
  656. },
  657. maxHeight () {
  658. this.$nextTick(() => this.recalculate(true))
  659. },
  660. syncResize (value) {
  661. if (value) {
  662. const { $el } = this
  663. // 只在可视状态下才去更新
  664. if ($el.clientWidth && $el.clientHeight) {
  665. this.recalculate()
  666. }
  667. this.$nextTick(() => {
  668. setTimeout(() => {
  669. if ($el.clientWidth && $el.clientHeight) {
  670. this.recalculate(true)
  671. }
  672. })
  673. })
  674. }
  675. },
  676. mergeCells (value) {
  677. this.clearMergeCells()
  678. this.setMergeCells(value)
  679. },
  680. mergeFooterItems (value) {
  681. this.clearMergeFooterItems()
  682. this.setMergeFooterItems(value)
  683. }
  684. },
  685. created () {
  686. const { sXOpts, scrollXStore, sYOpts, scrollYStore, mouseOpts, data, editOpts, treeOpts, treeConfig, showOverflow } = Object.assign(this, {
  687. tZindex: 0,
  688. elemStore: {},
  689. // 存放横向 X 虚拟滚动相关的信息
  690. scrollXStore: {},
  691. // 存放纵向 Y 虚拟滚动相关信息
  692. scrollYStore: {},
  693. // 存放 tooltip 相关信息
  694. tooltipStore: {},
  695. // 表格宽度
  696. tableWidth: 0,
  697. // 表格高度
  698. tableHeight: 0,
  699. // 表头高度
  700. headerHeight: 0,
  701. // 表尾高度
  702. footerHeight: 0,
  703. // 当前 hover 行
  704. // hoverRow: null,
  705. // 最后滚动位置
  706. lastScrollLeft: 0,
  707. lastScrollTop: 0,
  708. // 单选框属性,已选中保留的行
  709. radioReserveRow: null,
  710. // 复选框属性,已选中保留的行
  711. checkboxReserveRowMap: {},
  712. // 行数据,已展开保留的行
  713. rowExpandedReserveRowMap: {},
  714. // 树结构数据,已展开保留的行
  715. treeExpandedReserveRowMap: {},
  716. // 完整数据、条件处理后
  717. tableFullData: [],
  718. afterFullData: [],
  719. // 缓存数据集
  720. fullAllDataRowMap: new Map(),
  721. fullAllDataRowIdData: {},
  722. fullDataRowMap: new Map(),
  723. fullDataRowIdData: {},
  724. fullColumnMap: new Map(),
  725. fullColumnIdData: {},
  726. fullColumnFieldData: {}
  727. })
  728. if (!this.rowId && (this.checkboxOpts.reserve || this.checkboxOpts.checkRowKeys || this.radioOpts.reserve || this.radioOpts.checkRowKey || this.expandOpts.expandRowKeys || this.treeOpts.expandRowKeys)) {
  729. UtilTools.warn('vxe.error.reqProp', ['row-id'])
  730. }
  731. // 在 v3.0 中废弃 column-width
  732. if (this.columnWidth) {
  733. UtilTools.warn('vxe.error.delProp', ['column-width', 'column-config.width'])
  734. }
  735. // 在 v3.0 中废弃 column-min-width
  736. if (this.columnMinWidth) {
  737. UtilTools.warn('vxe.error.delProp', ['column-min-width', 'column-config.minWidth'])
  738. }
  739. // 在 v3.0 中废弃 start-index
  740. if (this.startIndex) {
  741. UtilTools.warn('vxe.error.delProp', ['start-index', 'seq-config.startIndex'])
  742. }
  743. // 在 v3.0 中废弃 select-config
  744. if (this.selectConfig) {
  745. UtilTools.warn('vxe.error.delProp', ['select-config', 'checkbox-config'])
  746. }
  747. if (this.editConfig && editOpts.showStatus && !this.keepSource) {
  748. UtilTools.warn('vxe.error.reqProp', ['keep-source'])
  749. }
  750. if (treeConfig && treeOpts.line && (!this.rowKey || !showOverflow)) {
  751. UtilTools.warn('vxe.error.reqProp', ['row-key | show-overflow'])
  752. }
  753. if (this.showFooter && !this.footerMethod) {
  754. UtilTools.warn('vxe.error.reqProp', ['footer-method'])
  755. }
  756. // 在 v3.0 中废弃 customs
  757. if (this.customs) {
  758. UtilTools.warn('vxe.error.removeProp', ['customs'])
  759. }
  760. // 在 v3.0 中废弃 sort-method
  761. if (this.sortMethod) {
  762. UtilTools.warn('vxe.error.delProp', ['sort-method', 'sort-config.sortMethod'])
  763. }
  764. // 在 v3.0 中废弃 remote-sort
  765. if (this.remoteSort) {
  766. UtilTools.warn('vxe.error.delProp', ['remote-sort', 'sort-config.remote'])
  767. }
  768. // 在 v3.0 中废弃 remote-filter
  769. if (this.remoteFilter) {
  770. UtilTools.warn('vxe.error.delProp', ['remote-filter', 'filter-config.remote'])
  771. }
  772. if (!this.handleUpdateCellAreas) {
  773. if (this.clipConfig) {
  774. UtilTools.warn('vxe.error.notProp', ['clip-config'])
  775. }
  776. if (this.fnrConfig) {
  777. UtilTools.warn('vxe.error.notProp', ['fnr-config'])
  778. }
  779. if (this.mouseOpts.area) {
  780. UtilTools.error('vxe.error.notProp', ['mouse-config.area'])
  781. return
  782. }
  783. }
  784. if (mouseOpts.selected && mouseOpts.area) {
  785. UtilTools.error('vxe.error.errConflicts', ['mouse-config.area', 'mouse-config.selected'])
  786. }
  787. if (mouseOpts.checked && mouseOpts.area) {
  788. UtilTools.error('vxe.error.errConflicts', ['mouse-config.checked', 'mouse-config.area'])
  789. }
  790. // v3 中只支持对象类型
  791. // 在 v3.0 中废弃 context-menu
  792. if (this.contextMenu) {
  793. UtilTools.warn('vxe.error.delProp', ['context-menu', 'menu-config'])
  794. if (!XEUtils.isObject(this.contextMenu)) {
  795. UtilTools.warn('vxe.error.errProp', [`table.context-menu=${this.contextMenu}`, 'table.context-menu={}'])
  796. }
  797. }
  798. if (this.menuConfig && !XEUtils.isObject(this.menuConfig)) {
  799. UtilTools.warn('vxe.error.errProp', [`table.menu-config=${this.menuConfig}`, 'table.menu-config={}'])
  800. }
  801. if (this.exportConfig && !XEUtils.isObject(this.exportConfig)) {
  802. UtilTools.warn('vxe.error.errProp', [`table.export-config=${this.exportConfig}`, 'table.export-config={}'])
  803. }
  804. if (this.importConfig && !XEUtils.isObject(this.importConfig)) {
  805. UtilTools.warn('vxe.error.errProp', [`table.import-config=${this.importConfig}`, 'table.import-config={}'])
  806. }
  807. if (this.printConfig && !XEUtils.isObject(this.printConfig)) {
  808. UtilTools.warn('vxe.error.errProp', [`table.print-config=${this.printConfig}`, 'table.print-config={}'])
  809. }
  810. if (this.treeConfig && !XEUtils.isObject(this.treeConfig)) {
  811. UtilTools.warn('vxe.error.errProp', [`table.tree-config=${this.treeConfig}`, 'table.tree-config={}'])
  812. }
  813. if (this.customConfig && !XEUtils.isObject(this.customConfig)) {
  814. UtilTools.warn('vxe.error.errProp', [`table.custom-config=${this.customConfig}`, 'table.custom-config={}'])
  815. }
  816. if (this.editConfig && !XEUtils.isObject(this.editConfig)) {
  817. UtilTools.warn('vxe.error.errProp', [`table.edit-config=${this.editConfig}`, 'table.edit-config={}'])
  818. }
  819. if (this.emptyRender && !XEUtils.isObject(this.emptyRender)) {
  820. UtilTools.warn('vxe.error.errProp', [`table.empty-render=${this.emptyRender}`, 'table.empty-render={}'])
  821. }
  822. if (this.mouseConfig && this.editConfig) {
  823. if (mouseOpts.checked && editOpts.trigger !== 'dblclick') {
  824. UtilTools.warn('vxe.error.errProp', ['mouse-config.checked', 'edit-config.trigger=dblclick'])
  825. }
  826. }
  827. if (this.mouseOpts.area && this.checkboxOpts.range) {
  828. UtilTools.error('vxe.error.errConflicts', ['mouse-config.area', 'checkbox-config.range'])
  829. }
  830. if (treeConfig && this.stripe) {
  831. UtilTools.warn('vxe.error.noTree', ['stripe'])
  832. }
  833. // 在 v3.0 中废弃 optimization
  834. if (this.optimization) {
  835. UtilTools.warn('vxe.error.removeProp', ['optimization'])
  836. }
  837. // 废弃 optimization.cloak
  838. if (this.optimizeOpts.cloak) {
  839. UtilTools.warn('vxe.error.delProp', ['optimization.cloak', 'cloak'])
  840. }
  841. // 废弃 optimization.animat
  842. if (this.optimizeOpts.animat) {
  843. UtilTools.warn('vxe.error.delProp', ['optimization.animat', 'animat'])
  844. }
  845. // 废弃 optimization.delayHover
  846. if (this.optimizeOpts.delayHover) {
  847. UtilTools.warn('vxe.error.delProp', ['optimization.delayHover', 'delay-hover'])
  848. }
  849. // 废弃 optimization.scrollX
  850. if (this.optimizeOpts.scrollX) {
  851. UtilTools.warn('vxe.error.delProp', ['optimization.scrollX', 'scroll-x'])
  852. }
  853. // 废弃 optimization.scrollY
  854. if (this.optimizeOpts.scrollY) {
  855. UtilTools.warn('vxe.error.delProp', ['optimization.scrollY', 'scroll-y'])
  856. }
  857. const customOpts = this.customOpts
  858. if (!this.id && this.customConfig && (customOpts.storage === true || (customOpts.storage && customOpts.storage.resizable) || (customOpts.storage && customOpts.storage.visible))) {
  859. UtilTools.error('vxe.error.reqProp', ['id'])
  860. }
  861. if (this.treeConfig && this.checkboxOpts.range) {
  862. UtilTools.error('vxe.error.noTree', ['checkbox-config.range'])
  863. }
  864. if (this.treeConfig && this.mouseOpts.area) {
  865. UtilTools.error('vxe.error.noTree', ['mouse-config.area'])
  866. }
  867. // 检查是否有安装需要的模块
  868. let errorModuleName
  869. if (!VXETable._edit && this.editConfig) {
  870. errorModuleName = 'Edit'
  871. } else if (!VXETable._valid && this.editRules) {
  872. errorModuleName = 'Validator'
  873. } else if (!VXETable._keyboard && (this.checkboxOpts.range || this.keyboardConfig || this.mouseConfig)) {
  874. errorModuleName = 'Keyboard'
  875. } else if (!VXETable._export && (this.importConfig || this.exportConfig)) {
  876. errorModuleName = 'Export'
  877. }
  878. if (errorModuleName) {
  879. throw new Error(UtilTools.getLog('vxe.error.reqModule', [errorModuleName]))
  880. }
  881. Object.assign(scrollYStore, {
  882. startIndex: 0,
  883. visibleIndex: 0,
  884. adaptive: sYOpts.adaptive !== false,
  885. renderSize: XEUtils.toNumber(sYOpts.rSize),
  886. offsetSize: XEUtils.toNumber(sYOpts.oSize)
  887. })
  888. Object.assign(scrollXStore, {
  889. startIndex: 0,
  890. visibleIndex: 0,
  891. renderSize: XEUtils.toNumber(sXOpts.rSize),
  892. offsetSize: XEUtils.toNumber(sXOpts.oSize)
  893. })
  894. if (this.cloak) {
  895. this.isCloak = true
  896. setTimeout(() => {
  897. this.isCloak = false
  898. }, DomTools.browse ? 500 : 300)
  899. }
  900. this.loadTableData(data).then(() => {
  901. if (data && data.length) {
  902. this.inited = true
  903. this.handleDefaults()
  904. }
  905. this.updateStyle()
  906. this.recalculate()
  907. })
  908. GlobalEvent.on(this, 'paste', this.handleGlobalPasteEvent)
  909. GlobalEvent.on(this, 'copy', this.handleGlobalCopyEvent)
  910. GlobalEvent.on(this, 'cut', this.handleGlobalCutEvent)
  911. GlobalEvent.on(this, 'mousedown', this.handleGlobalMousedownEvent)
  912. GlobalEvent.on(this, 'blur', this.handleGlobalBlurEvent)
  913. GlobalEvent.on(this, 'mousewheel', this.handleGlobalMousewheelEvent)
  914. GlobalEvent.on(this, 'keydown', this.handleGlobalKeydownEvent)
  915. GlobalEvent.on(this, 'resize', this.handleGlobalResizeEvent)
  916. GlobalEvent.on(this, 'contextmenu', this.handleGlobalContextmenuEvent)
  917. this.preventEvent(null, 'created')
  918. },
  919. mounted () {
  920. const { $listeners } = this
  921. if (!this.menuConfig && ($listeners['menu-click'] || $listeners['cell-menu'] || $listeners['header-cell-menu'] || $listeners['footer-cell-menu'])) {
  922. UtilTools.warn('vxe.error.reqProp', ['menu-config'])
  923. }
  924. if (!this.tooltipConfig && ($listeners['cell-mouseenter'] || $listeners['cell-mouseleave'])) {
  925. UtilTools.warn('vxe.error.reqProp', ['tooltip-config'])
  926. }
  927. if (!this.tooltipConfig && (this.$listeners['cell-mouseenter'] || this.$listeners['cell-mouseleave'])) {
  928. UtilTools.warn('vxe.error.reqProp', ['tooltip-config'])
  929. }
  930. if (this.autoResize) {
  931. const resizeObserver = new ResizeEvent(() => this.recalculate(true))
  932. resizeObserver.observe(this.$el)
  933. resizeObserver.observe(this.getParentElem())
  934. this.$resize = resizeObserver
  935. }
  936. if (!this.$xegrid && this.customs) {
  937. UtilTools.warn('vxe.error.removeProp', ['customs'])
  938. }
  939. document.body.appendChild(this.$refs.tableWrapper)
  940. this.preventEvent(null, 'mounted')
  941. },
  942. activated () {
  943. this.recalculate().then(() => this.refreshScroll())
  944. this.preventEvent(null, 'activated')
  945. },
  946. deactivated () {
  947. this.preventEvent(null, 'deactivated')
  948. },
  949. beforeDestroy () {
  950. const tableWrapper = this.$refs.tableWrapper
  951. if (tableWrapper && tableWrapper.parentNode) {
  952. tableWrapper.parentNode.removeChild(tableWrapper)
  953. }
  954. if (this.$resize) {
  955. this.$resize.disconnect()
  956. }
  957. this.closeFilter()
  958. this.closeMenu()
  959. this.preventEvent(null, 'beforeDestroy')
  960. },
  961. destroyed () {
  962. GlobalEvent.off(this, 'paste')
  963. GlobalEvent.off(this, 'copy')
  964. GlobalEvent.off(this, 'cut')
  965. GlobalEvent.off(this, 'mousedown')
  966. GlobalEvent.off(this, 'blur')
  967. GlobalEvent.off(this, 'mousewheel')
  968. GlobalEvent.off(this, 'keydown')
  969. GlobalEvent.off(this, 'resize')
  970. GlobalEvent.off(this, 'contextmenu')
  971. this.preventEvent(null, 'destroyed')
  972. },
  973. render (h) {
  974. const {
  975. _e,
  976. $scopedSlots,
  977. tId,
  978. tableData,
  979. tableColumn,
  980. visibleColumn,
  981. tableGroupColumn,
  982. isGroup,
  983. isResizable,
  984. isCtxMenu,
  985. loading,
  986. isCloak,
  987. stripe,
  988. showHeader,
  989. height,
  990. tableBorder,
  991. treeOpts,
  992. treeConfig,
  993. mouseConfig,
  994. mouseOpts,
  995. vSize,
  996. validOpts,
  997. editRules,
  998. showFooter,
  999. overflowX,
  1000. overflowY,
  1001. scrollXLoad,
  1002. scrollYLoad,
  1003. scrollbarHeight,
  1004. highlightCell,
  1005. highlightHoverRow,
  1006. highlightHoverColumn,
  1007. editConfig,
  1008. checkboxOpts,
  1009. validTipOpts,
  1010. tooltipOpts,
  1011. columnStore,
  1012. filterStore,
  1013. ctxMenuStore,
  1014. ctxMenuOpts,
  1015. footerTableData,
  1016. hasTip,
  1017. emptyRender,
  1018. emptyOpts
  1019. } = this
  1020. const { leftList, rightList } = columnStore
  1021. let emptyContent
  1022. if ($scopedSlots.empty) {
  1023. emptyContent = $scopedSlots.empty.call(this, { $table: this }, h)
  1024. } else {
  1025. const compConf = emptyRender ? VXETable.renderer.get(emptyOpts.name) : null
  1026. if (compConf) {
  1027. emptyContent = compConf.renderEmpty.call(this, h, emptyOpts, { $table: this }, { $table: this })
  1028. } else {
  1029. emptyContent = this.emptyText || GlobalConfig.i18n('vxe.table.emptyText')
  1030. }
  1031. }
  1032. return h('div', {
  1033. class: ['vxe-table', 'vxe-table--render-default', `tid_${tId}`, vSize ? `size--${vSize}` : '', `border--${tableBorder}`, {
  1034. 'vxe-editable': !!editConfig,
  1035. 'show--head': showHeader,
  1036. 'show--foot': showFooter,
  1037. 'is--group': isGroup,
  1038. 'has--height': height,
  1039. 'has--tree-line': treeConfig && treeOpts.line,
  1040. 'fixed--left': leftList.length,
  1041. 'fixed--right': rightList.length,
  1042. 'c--highlight': highlightCell,
  1043. 't--animat': !!this.animat,
  1044. 'is--round': this.round,
  1045. 't--stripe': !treeConfig && stripe,
  1046. 't--selected': mouseConfig && mouseOpts.selected,
  1047. // 在 v3.0 中废弃 mouse-config.checked
  1048. 't--checked': mouseConfig && mouseOpts.checked,
  1049. 'is--area': mouseConfig && mouseOpts.area,
  1050. 'row--highlight': highlightHoverRow,
  1051. 'column--highlight': highlightHoverColumn,
  1052. 'is--loading': isCloak || loading,
  1053. 'is--empty': !loading && !tableData.length,
  1054. 'scroll--y': overflowY,
  1055. 'scroll--x': overflowX,
  1056. 'virtual--x': scrollXLoad,
  1057. 'virtual--y': scrollYLoad
  1058. }],
  1059. attrs: {
  1060. 'x-cloak': isCloak
  1061. }
  1062. }, [
  1063. /**
  1064. * 隐藏列
  1065. */
  1066. h('div', {
  1067. class: 'vxe-table-slots',
  1068. ref: 'hideColumn'
  1069. }, this.$slots.default),
  1070. h('div', {
  1071. class: 'vxe-table--main-wrapper'
  1072. }, [
  1073. /**
  1074. * 主头部
  1075. */
  1076. showHeader ? h('vxe-table-header', {
  1077. ref: 'tableHeader',
  1078. props: {
  1079. tableData,
  1080. tableColumn,
  1081. visibleColumn,
  1082. tableGroupColumn,
  1083. size: vSize,
  1084. isGroup
  1085. }
  1086. }) : _e(),
  1087. /**
  1088. * 主内容
  1089. */
  1090. h('vxe-table-body', {
  1091. ref: 'tableBody',
  1092. props: {
  1093. tableData,
  1094. tableColumn,
  1095. visibleColumn,
  1096. size: vSize,
  1097. isGroup
  1098. }
  1099. }),
  1100. /**
  1101. * 底部
  1102. */
  1103. showFooter ? h('vxe-table-footer', {
  1104. props: {
  1105. footerTableData,
  1106. tableColumn,
  1107. visibleColumn,
  1108. size: vSize
  1109. },
  1110. ref: 'tableFooter'
  1111. }) : null
  1112. ]),
  1113. /**
  1114. * 左侧固定列
  1115. */
  1116. leftList && leftList.length && overflowX ? renderFixed(h, this, 'left') : _e(),
  1117. /**
  1118. * 右侧固定列
  1119. */
  1120. rightList && rightList.length && overflowX ? renderFixed(h, this, 'right') : _e(),
  1121. /**
  1122. * 空数据
  1123. */
  1124. h('div', {
  1125. ref: 'emptyPlaceholder',
  1126. class: 'vxe-table--empty-placeholder'
  1127. }, [
  1128. h('div', {
  1129. class: 'vxe-table--empty-content'
  1130. }, emptyContent)
  1131. ]),
  1132. /**
  1133. * 边框线
  1134. */
  1135. h('div', {
  1136. class: 'vxe-table--border-line'
  1137. }),
  1138. /**
  1139. * 列宽线
  1140. */
  1141. isResizable ? h('div', {
  1142. class: 'vxe-table--resizable-bar',
  1143. style: overflowX ? {
  1144. 'padding-bottom': `${scrollbarHeight}px`
  1145. } : null,
  1146. ref: 'resizeBar'
  1147. }) : _e(),
  1148. /**
  1149. * 加载中
  1150. */
  1151. h('div', {
  1152. class: ['vxe-table--loading vxe-loading', {
  1153. 'is--visible': isCloak || loading
  1154. }]
  1155. }, [
  1156. h('div', {
  1157. class: 'vxe-loading--spinner'
  1158. })
  1159. ]),
  1160. /**
  1161. * 筛选
  1162. */
  1163. this.hasFilterPanel ? h('vxe-table-filter', {
  1164. props: {
  1165. filterStore
  1166. },
  1167. ref: 'filterWrapper'
  1168. }) : _e(),
  1169. /**
  1170. * 导入
  1171. */
  1172. this.importConfig ? h('vxe-import-panel', {
  1173. props: {
  1174. defaultOptions: this.importParams,
  1175. storeData: this.importStore
  1176. }
  1177. }) : _e(),
  1178. /**
  1179. * 导出/打印
  1180. */
  1181. this.exportConfig || this.printConfig ? h('vxe-export-panel', {
  1182. props: {
  1183. defaultOptions: this.exportParams,
  1184. storeData: this.exportStore
  1185. }
  1186. }) : _e(),
  1187. h('div', {
  1188. class: `vxe-table${tId}-wrapper ${this.$vnode.data.staticClass || ''}`,
  1189. ref: 'tableWrapper'
  1190. }, [
  1191. /**
  1192. * 复选框-范围选择
  1193. */
  1194. checkboxOpts.range ? h('div', {
  1195. class: 'vxe-table--checkbox-range',
  1196. ref: 'checkboxRange'
  1197. }) : _e(),
  1198. /**
  1199. * 快捷菜单
  1200. */
  1201. isCtxMenu ? h('vxe-table-context-menu', {
  1202. props: {
  1203. ctxMenuStore,
  1204. ctxMenuOpts
  1205. },
  1206. ref: 'ctxWrapper'
  1207. }) : _e(),
  1208. /**
  1209. * 公用提示
  1210. */
  1211. hasTip ? h('vxe-tooltip', {
  1212. key: 'cTip',
  1213. ref: 'commTip',
  1214. props: {
  1215. isArrow: false,
  1216. enterable: false
  1217. }
  1218. }) : _e(),
  1219. /**
  1220. * 单元格溢出的提示
  1221. */
  1222. hasTip ? h('vxe-tooltip', {
  1223. ref: 'tooltip',
  1224. props: tooltipOpts,
  1225. on: tooltipOpts.enterable ? {
  1226. leave: this.handleTooltipLeaveEvent
  1227. } : null
  1228. }) : _e(),
  1229. /**
  1230. * 单元格校验不通过的提示
  1231. * 仅用于一行数据时有效,多行数据使用内部的提示框
  1232. */
  1233. hasTip && editRules && validOpts.showMessage && (validOpts.message === 'default' ? !height : validOpts.message === 'tooltip') ? h('vxe-tooltip', {
  1234. class: 'vxe-table--valid-error',
  1235. props: validOpts.message === 'tooltip' || tableData.length === 1 ? validTipOpts : null,
  1236. ref: 'validTip'
  1237. }) : _e()
  1238. ])
  1239. ])
  1240. },
  1241. methods
  1242. }