tree-node.vue 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107
  1. <template>
  2. <div
  3. ref="node$"
  4. :class="[
  5. ns.b('node'),
  6. ns.is('expanded', expanded),
  7. ns.is('current', current),
  8. ns.is('focusable', !disabled),
  9. ns.is('checked', !disabled && checked),
  10. ]"
  11. role="treeitem"
  12. tabindex="-1"
  13. :level="node.level"
  14. :aria-expanded="expanded"
  15. :aria-disabled="disabled"
  16. :aria-checked="checked"
  17. :data-key="node?.key"
  18. @click.stop="handleClick"
  19. @contextmenu="handleContextMenu"
  20. >
  21. <template v-for="item in node.level" :key="item">
  22. <i v-if="item - 2 > 0" :class="`line-i-${item - 2}`" />
  23. </template>
  24. <div
  25. :class="ns.be('node', 'content')"
  26. :style="{
  27. paddingLeft: `${(node.level - 1) * indent}px`,
  28. height: itemSize + 'px',
  29. }"
  30. >
  31. <el-icon
  32. v-if="icon"
  33. :class="[
  34. ns.is('leaf', !!node?.isLeaf),
  35. ns.is('hidden', hiddenExpandIcon),
  36. {
  37. expanded: !node?.isLeaf && expanded,
  38. },
  39. ns.be('node', 'expand-icon'),
  40. ]"
  41. @click.stop="handleExpandIconClick"
  42. >
  43. <component :is="icon" />
  44. </el-icon>
  45. <el-checkbox
  46. v-if="showCheckbox"
  47. :model-value="checked"
  48. :indeterminate="indeterminate"
  49. :disabled="disabled"
  50. @change="handleCheckChange"
  51. @click.stop
  52. />
  53. <el-node-content :node="node" />
  54. </div>
  55. </div>
  56. </template>
  57. <script lang="ts" setup>
  58. import { computed, inject } from 'vue'
  59. import ElIcon from '@element-plus/components/icon'
  60. import { CaretRight } from '@element-plus/icons-vue'
  61. import ElCheckbox from '@element-plus/components/checkbox'
  62. import { useNamespace } from '@element-plus/hooks'
  63. import ElNodeContent from './tree-node-content'
  64. import {
  65. NODE_CONTEXTMENU,
  66. ROOT_TREE_INJECTION_KEY,
  67. treeNodeEmits,
  68. treeNodeProps,
  69. } from './virtual-tree'
  70. import type { CheckboxValueType } from '@element-plus/components/checkbox'
  71. defineOptions({
  72. name: 'ElTreeNode',
  73. })
  74. const props = defineProps(treeNodeProps)
  75. const emit = defineEmits(treeNodeEmits)
  76. const tree = inject(ROOT_TREE_INJECTION_KEY)
  77. const ns = useNamespace('tree')
  78. const indent = computed(() => {
  79. return tree?.props.indent ?? 16
  80. })
  81. const icon = computed(() => {
  82. return tree?.props.icon ?? CaretRight
  83. })
  84. const handleClick = (e: MouseEvent) => {
  85. emit('click', props.node, e)
  86. }
  87. const handleExpandIconClick = () => {
  88. emit('toggle', props.node)
  89. }
  90. const handleCheckChange = (value: CheckboxValueType) => {
  91. emit('check', props.node, value)
  92. }
  93. const handleContextMenu = (event: Event) => {
  94. if (tree?.instance?.vnode?.props?.['onNodeContextmenu']) {
  95. event.stopPropagation()
  96. event.preventDefault()
  97. }
  98. tree?.ctx.emit(NODE_CONTEXTMENU, event, props.node?.data, props.node)
  99. }
  100. </script>