index.jsx 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112
  1. import { ref, onMounted, watch, nextTick, computed } from 'vue'
  2. import { ElDropdown, ElDropdownMenu, ElDropdownItem } from 'element-plus'
  3. import CipButtonText from '@cip/components/cip-button-text'
  4. import CipButton from '@cip/components/cip-button'
  5. import { useTable } from '../hooks/use-table'
  6. import './index.less'
  7. import { getUsingConfig } from '@cip/utils/util'
  8. const getButtonInfo = (vnode) => {
  9. if (vnode.component) {
  10. const text = vnode.component.slots.default?.()
  11. // console.log(vnode.component.emitsOptions.click)
  12. const info = { ...vnode.component.ctx._.props, ...vnode.component.ctx._.attrs }
  13. const { onClick = (e) => vnode.component.ctx._.emit('click', e) } = info
  14. return {
  15. ...info,
  16. onClick,
  17. text
  18. }
  19. }
  20. return {}
  21. }
  22. const RenderComponent = (props) => {
  23. const list = props.buttonList // .value
  24. let dropDownNode
  25. let buttonNodeList = list
  26. if (list.length > props.limit) {
  27. buttonNodeList = list.slice(0, props.limit - 1)
  28. dropDownNode = <ElDropdown style={'margin-left: 8px'} size={props.size} trigger={'click'}>
  29. {{
  30. default: () => props.buttonComp === 'button'
  31. ? <CipButton square={true} icon={'el-icon-arrow-down'}/>
  32. : <CipButtonText>更多<i class={'el-icon-caret-bottom'}/></CipButtonText>,
  33. dropdown: () => <ElDropdownMenu >
  34. {
  35. list.slice(props.limit - 1).map(item => {
  36. const { onClick, text, disabled } = getButtonInfo(item)
  37. return <ElDropdownItem onClick={disabled ? undefined : onClick} disabled={disabled}>{text}</ElDropdownItem>
  38. })
  39. }
  40. </ElDropdownMenu>
  41. }}
  42. </ElDropdown>
  43. }
  44. const result = buttonNodeList.map(item => {
  45. const { onClick, text, type, icon, disabled, ...buttonProps } = getButtonInfo(item)
  46. const ButtonComponent = props.buttonComp === 'button' ? CipButton : CipButtonText
  47. return <ButtonComponent
  48. {...buttonProps}
  49. type={type}
  50. disabled={disabled}
  51. icon={icon}
  52. onClick={onClick}
  53. v-slots={text ? { default: () => text } : undefined}
  54. />
  55. })
  56. if (dropDownNode) {
  57. result.push(dropDownNode)
  58. }
  59. return result
  60. }
  61. export default {
  62. name: 'CipTableHandler',
  63. props: {
  64. limit: { type: Number },
  65. row: { type: Object, required: true },
  66. buttonComp: { type: String, default: 'text', validate: (val) => ['text', 'button'].includes(val) }
  67. },
  68. setup (props, { slots }) {
  69. const cipTable = useTable()
  70. const buttonList = ref([])
  71. const originRef = ref()
  72. const handlerLimit = computed(() => {
  73. return getUsingConfig(props.limit, props.buttonComp === 'text' ? 3 : 4)
  74. })
  75. let vnodeList = []
  76. onMounted(() => {
  77. watch(() => props.row, () => {
  78. nextTick().then(() => collectButtons())
  79. }, { immediate: true, deep: true })
  80. })
  81. const collectButtons = () => {
  82. buttonList.value = []
  83. vnodeList.forEach(vnode => getButtons(vnode))
  84. }
  85. const getButtons = (vnode) => {
  86. if (vnode.shapeFlag === 16) { // 数组
  87. vnode.children.forEach(v => getButtons(v))
  88. }
  89. if (vnode.shapeFlag === 17) { // 原生的dom
  90. vnode.children.forEach(v => getButtons(v))
  91. }
  92. if ([4, 36].includes(vnode.shapeFlag)) { // 组件 shapeFlag 4 [注: 4与36的区别4无slots]
  93. const componentName = (vnode.type.name || '').toLowerCase()
  94. if (componentName.indexOf('button') > -1) {
  95. buttonList.value.push(vnode)
  96. } else {
  97. if (vnode.component) {
  98. const children = vnode.component.subTree.children || []
  99. children.forEach(v => getButtons(v))
  100. }
  101. }
  102. }
  103. }
  104. return () => {
  105. vnodeList = slots.default?.()
  106. return <div class={'cip-table-handler'}>
  107. <div ref={el => { originRef.value = el }} style={'display: none'}>{vnodeList}</div>
  108. <RenderComponent limit={handlerLimit.value} size={cipTable.size} buttonList={buttonList.value} buttonComp={props.buttonComp} />
  109. </div>
  110. }
  111. }
  112. }