treeNode.vue 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  1. <template>
  2. <div class="p-tree-node">
  3. <div
  4. :class="['p-tree-node-content', !multiple&&treeItem.checked==='checked'&&'p-tree-node-content-checked', treeItem.disabled&&'p-tree-node-content-disabled']"
  5. :style="{paddingLeft: paddingLeft+'px'}"
  6. >
  7. <section class="p-tree-svg" @click="openChild" >
  8. <ArrowTriangle
  9. :class="['p-tree-icon-svg', (treeItem.open)&&'p-tree-icon-rotate']"
  10. v-if="triangleShow"
  11. />
  12. </section>
  13. <div class="p-tree-node-check" @click="handleCheck(treeItem, index)">
  14. <!-- v-if="multiple&&(!lastStage||!triangleShow)" -->
  15. <section class="p-tree-node-title">
  16. <article class="p-tree-node-name" @mouseenter="treeItemEnter" v-html="treeItem.name" />
  17. </section>
  18. </div>
  19. </div>
  20. <div class="p-tree-child" v-if="triangleShow" v-show="treeItem.open">
  21. <TreeNode
  22. :multiple="multiple"
  23. :linkage="linkage"
  24. :lastStage="lastStage"
  25. v-for="(item, ind) in treeItem.children"
  26. :key="item.id+'-'+ind"
  27. :treeItem="item"
  28. :triangleShow="!!(item.children&&item.children.length)"
  29. :index="`${index}-${ind}`"
  30. :change="change"
  31. :leftPosition="leftPosition"
  32. />
  33. </div>
  34. </div>
  35. </template>
  36. <script>
  37. import ArrowTriangle from './arrow_triangle.svg';
  38. export default {
  39. name: 'TreeNode',
  40. components: { ArrowTriangle},
  41. props: {
  42. /**
  43. * 是否开启多选
  44. */
  45. multiple: {
  46. type: Boolean,
  47. default: false
  48. },
  49. /**
  50. * 是否联动选择
  51. */
  52. linkage: {
  53. type: Boolean,
  54. default: true
  55. },
  56. /**
  57. * 只能选择末级
  58. */
  59. lastStage: {
  60. type: Boolean,
  61. default: false
  62. },
  63. /**
  64. * 树形结构子项数据列表
  65. */
  66. treeItem: {
  67. type: Object,
  68. default: {}
  69. },
  70. /**
  71. * 点击某项
  72. */
  73. change: {
  74. type: Function,
  75. default: () => false
  76. },
  77. /**
  78. * 下拉三角形是否显示
  79. */
  80. triangleShow: {
  81. type: Boolean,
  82. default: false
  83. },
  84. /**
  85. * 索引
  86. */
  87. index: {
  88. type: String,
  89. default: ''
  90. },
  91. leftPosition: {
  92. type: Number,
  93. default: 12
  94. }
  95. },
  96. computed: {
  97. // 左边内边距
  98. paddingLeft() {
  99. return (this.index.split('-').length-1)*24+Number(this.leftPosition);
  100. },
  101. checkboxShow() {
  102. const item = this.treeItem
  103. debugger
  104. // const flag = item.hasOwnProperty('isleaf') ? item.isleaf : true
  105. return this.multiple && (!this.triangleShow || !this.lastStage) && flag
  106. }
  107. },
  108. methods: {
  109. // 展开/收起
  110. openChild() {
  111. // if (!this.disabledOpen && this.treeItem.disabled ) return
  112. this.treeItem.open=!this.treeItem.open
  113. },
  114. // 鼠标hover
  115. treeItemEnter(e) {
  116. const target=e.target;
  117. const {clientWidth, scrollWidth, title}=target;
  118. if (!title && scrollWidth > clientWidth) target.title=target.innerText;
  119. },
  120. // 选择
  121. handleCheck(obj, index) {
  122. if (obj.disabled) return;
  123. if (this.multiple) {
  124. if(this.checkboxShow) {
  125. let status='';
  126. const treeItem=this.treeItem;
  127. const {checked, children}=treeItem;
  128. if (checked === 'checked') {
  129. status='uncheck';
  130. } else {
  131. // if (checked === 'uncheck' || checked === 'notNull')
  132. status='checked';
  133. }
  134. if (this.linkage) {
  135. // 上下级联动
  136. if (children && children.length) treeItem.children=this.setCheckedStatus(children, status);
  137. treeItem.checked=status;
  138. this.treeItem=treeItem;
  139. this.change(obj, index);
  140. } else {
  141. // 上下级不联动 this.lastStage为true-表示只能选择末级节点
  142. if (this.lastStage && children && children.length) return;
  143. this.treeItem=treeItem;
  144. treeItem.checked=status;
  145. this.change(obj, index);
  146. }
  147. }
  148. } else {
  149. // const notLastNode = obj.hasOwnProperty('children') || (obj.hasOwnProperty('isleaf') ? !obj.isleaf : false)
  150. if(this.lastStage && notLastNode) return
  151. // 执行父级的函数
  152. this.change(obj, index);
  153. }
  154. },
  155. // 设置checked状态
  156. setCheckedStatus(data, status) {
  157. return data.map(d => {
  158. d.checked=status;
  159. if (d.children && d.children.length)
  160. d.children=this.setCheckedStatus(d.children, status);
  161. return d;
  162. })
  163. }
  164. }
  165. }
  166. </script>