treeItem.vue 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
  1. <template>
  2. <li>
  3. <!--图标 & 当前项数据-->
  4. <div :class="[model.isSelected ? 'is-selected' : '']" >
  5. <span @click="toggle(model)">
  6. <i v-if="isFolder" :class="[model.isSelected ? (open ? 'el-icon-minus': 'el-icon-plus') : (open ? 'el-icon-remove': 'el-icon-circle-plus')]"></i>
  7. <i v-if="!isFolder"></i>
  8. </span>
  9. <span class="name-label" @click="handleChoose(model)"> {{ model.local_name }} </span>
  10. </div>
  11. <!--子项数据-->
  12. <collapse-transition>
  13. <ul style="padding-left: 18px" v-show="open" v-if="isFolder">
  14. <en-tree-item
  15. v-for="item in model.children"
  16. :model="item"
  17. :parentNode="model"
  18. @selectCaputure="onselected"
  19. :key="item.id"></en-tree-item>
  20. </ul>
  21. </collapse-transition>
  22. </li>
  23. </template>
  24. <script>
  25. import collapseTransition from './collapse-transition'
  26. export default {
  27. name: 'EnTreeItem',
  28. props: {
  29. /** 当前节点 */
  30. model: {
  31. type: Object,
  32. default: {}
  33. },
  34. /** 当前节点的父节点 */
  35. parentNode: {
  36. type: Object,
  37. default: () => ({})
  38. }
  39. },
  40. components: {
  41. collapseTransition
  42. },
  43. data() {
  44. return {
  45. open: false
  46. }
  47. },
  48. computed: {
  49. isFolder() { // 是否有子项
  50. return this.model.children && !Array.isArray(this.model.children)
  51. }
  52. },
  53. methods: {
  54. // 展开/关闭
  55. toggle() {
  56. if (this.isFolder) { // 如果存在子项 则展开/ 关闭
  57. this.open = !this.open
  58. }
  59. },
  60. handleChoose(model) { // 选中/不选中 model为当前项
  61. model.isSelected = !model.isSelected
  62. // 如果当前项存在后代节点 则后代节点一并选中/不选中
  63. let stack = []
  64. stack.push(model)
  65. let item
  66. while (stack.length) {
  67. item = stack.shift()
  68. // 如果当前节点的兄弟节点 全部跟当前节点状态一样 则父节点保持同步
  69. item.isSelected = model.isSelected
  70. if (this.parentNode && this.parentNode.children) {
  71. let result = true // 默认同步
  72. for (let i in this.parentNode.children) {
  73. if (this.parentNode.children[i].isSelected !== model.isSelected) {
  74. result = false
  75. }
  76. }
  77. if (result) { // 同步
  78. this.parentNode.isSelected = model.isSelected
  79. } else {
  80. this.parentNode.isSelected = false
  81. }
  82. }
  83. // 如果该节点有子节点,继续添加进入栈顶
  84. if (item && item.children && !Array.isArray(item.children)) {
  85. for (let i in item.children) {
  86. stack.push(item.children[i])
  87. }
  88. }
  89. }
  90. this.$emit('selectCaputure', model, this.parentNode)
  91. },
  92. onselected(model, parentNode) { // 监听响应 选中之后进行计算现在选中之后的数据
  93. this.$emit('selectCaputure', model, parentNode)
  94. }
  95. }
  96. }
  97. </script>
  98. <style type="text/scss" lang="scss" scoped>
  99. ul {
  100. list-style: none;
  101. }
  102. .tree-menu li {
  103. line-height: 1.5;
  104. }
  105. .tree-menu li div{
  106. width: 100%;
  107. cursor: pointer;
  108. line-height: 40px;
  109. display: flex;
  110. flex-direction: row;
  111. flex-wrap: nowrap;
  112. justify-content: flex-start;
  113. align-items: center;
  114. i {
  115. font-size: 16px;
  116. color: #d7d7d7;
  117. margin-left: 5px;
  118. }
  119. .el-icon-minus, .el-icon-plus {
  120. font-size: 12px;
  121. background-color: #fff;
  122. border: none;
  123. border-radius: 50%;
  124. padding: 1px;
  125. }
  126. span.name-label {
  127. display: inline-block;
  128. margin-left: 5px;
  129. width: 150px;
  130. cursor: pointer;
  131. }
  132. }
  133. /deep/ .is-selected {
  134. background-color: #d7d7d7;
  135. color: #fff;
  136. }
  137. </style>