mix-tree.vue 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153
  1. <template>
  2. <view class="content">
  3. <view class="mix-tree-list">
  4. <block v-for="(item, index) in treeList" :key="index">
  5. <view
  6. class="mix-tree-item solid-bottom flex"
  7. :style="[{
  8. paddingLeft: item.rank*15 + 'px',
  9. zIndex: item.rank*-1 +50
  10. }]"
  11. :class="{
  12. border: treeParams.border === true,
  13. show: item.show,
  14. last: item.lastRank,
  15. showchild: item.showChild
  16. }"
  17. @click.stop="treeItemTap(item, index)"
  18. >
  19. <view class="flex-treble">
  20. <image class="mix-tree-icon" :src="item.lastRank ? treeParams.lastIcon : item.showChild ? treeParams.currentIcon : treeParams.defaultIcon"></image>
  21. {{item.name}}
  22. </view>
  23. <view class="flex-sub text-right padding-right text-gray">
  24. <text></text>
  25. </view>
  26. </view>
  27. </block>
  28. </view>
  29. </view>
  30. </template>
  31. <script>
  32. export default {
  33. props: {
  34. list: {
  35. type: Array,
  36. default(){
  37. return [];
  38. }
  39. },
  40. params: {
  41. type: Object,
  42. default(){
  43. return {}
  44. }
  45. }
  46. },
  47. data() {
  48. return {
  49. treeList: [],
  50. treeParams: {
  51. defaultIcon: '/static/mix-tree/defaultIcon.png',
  52. currentIcon: '/static/mix-tree/currentIcon.png',
  53. lastIcon: '',
  54. border: false
  55. }
  56. }
  57. },
  58. watch: {
  59. list(list){
  60. this.treeParams = Object.assign(this.treeParams, this.params);
  61. this.renderTreeList(list);
  62. }
  63. },
  64. methods: {
  65. //扁平化树结构
  66. renderTreeList(list=[], rank=0, parentId=[]){
  67. list.forEach(item=>{
  68. this.treeList.push({
  69. id: item.id,
  70. name: item.label,
  71. count: item.count,
  72. parentId, // 父级id数组
  73. rank, // 层级
  74. showChild: true, //子级是否显示
  75. show: true // 自身是否显示
  76. })
  77. if(Array.isArray(item.children) && item.children.length > 0){
  78. let parents = [...parentId];
  79. parents.push(item.id);
  80. this.renderTreeList(item.children, rank+1, parents);
  81. }else{
  82. this.treeList[this.treeList.length-1].lastRank = true;
  83. }
  84. })
  85. },
  86. // 点击
  87. treeItemTap(item){
  88. let list = this.treeList;
  89. let id = item.id;
  90. if(item.lastRank === true){
  91. //点击最后一级时触发事件
  92. this.$emit('treeItemClick', item);
  93. return;
  94. }
  95. item.showChild = !item.showChild;
  96. list.forEach(childItem=>{
  97. if(item.showChild === false){
  98. //隐藏所有子级
  99. if(!childItem.parentId.includes(id)){
  100. return;
  101. }
  102. if(childItem.lastRank !== true){
  103. childItem.showChild = false;
  104. }
  105. childItem.show = false;
  106. }else{
  107. if(childItem.parentId[childItem.parentId.length-1] === id){
  108. childItem.show = true;
  109. }
  110. }
  111. })
  112. }
  113. }
  114. }
  115. </script>
  116. <style scoped>
  117. .mix-tree-list{
  118. display: flex;
  119. flex-direction: column;
  120. }
  121. .mix-tree-item{
  122. display: flex;
  123. align-items: center;
  124. font-size: 30upx;
  125. color: #333;
  126. height: 0;
  127. opacity: 0;
  128. transition: .2s;
  129. position: relative;
  130. }
  131. .mix-tree-item.border{
  132. border-bottom: 1px solid #eee;
  133. }
  134. .mix-tree-item.show{
  135. height: 100upx;
  136. opacity: 1;
  137. }
  138. .mix-tree-icon{
  139. width: 26upx;
  140. height: 26upx;
  141. margin-right: 8upx;
  142. opacity: .9;
  143. }
  144. .mix-tree-item.showchild:before{
  145. transform: rotate(90deg);
  146. }
  147. .mix-tree-item.last:before{
  148. opacity: 0;
  149. }
  150. </style>