当前位置:   article > 正文

vue树形组件封装(移动端)_移动端树形控件

移动端树形控件

最近在做移动端的项目,由于没有找见移动端树形组件,所以封装了一个。包含加载所有数据的功能以及懒加载功能。

以下是目录结构

以下是完成后的ui  点击左侧切换“展开”、“收起”   点击右侧其他操作

然后直接上代码 

以下是懒加载的例子,一次性全部加载的就不放了

组件说明:

  1. * 组件说明:树形组件
  2. itemActive:是否需要高亮显示 Boolean
  3. data:树形组件的数据 Array类型
  4. props:组件属性 Object {id:'',children:'',name:''}
  5. lazy:是否开启懒加载 Boolean
  6. @load:懒加载回调方法 Funciton 返回当前点击项的所有数据
  7. @click:点击事件方法 Funciton 返回当前点击项的所有数据
  8. clickableConditions: 可以点击的条件 Object
  9. {
  10. //所有的列表是否可以点击
  11. all: {
  12. enable: true
  13. },
  14. //部分的列表可以点击
  15. //以下条件说明【 orgType = 1或orgType = 2时可以点击】
  16. part: {
  17. prop: "orgType",
  18. value: [1,2]
  19. }
  20. },

WarningMessage.vue

  1. /*
  2. * @Autor: Mr Lu
  3. * @Version: 1.0
  4. * @Date: 2019-12-03
  5. * @LastEditors: OBKoro1
  6. * @LastEditTime: 2019-12-03
  7. * @Description: 预警信息
  8. * 组件说明:树形组件
  9. itemActive:是否需要高亮显示 Boolean
  10. data:树形组件的数据 Array类型
  11. props:组件属性 Object {id:'',children:'',name:''}
  12. lazy:是否开启懒加载 Boolean
  13. @load:懒加载回调方法 Funciton 返回当前点击项的所有数据
  14. @click:点击事件方法 Funciton 返回当前点击项的所有数据
  15. clickableConditions: 可以点击的条件 Object
  16. {
  17. //所有的列表是否可以点击
  18. all: {
  19. enable: true
  20. },
  21. //部分的列表可以点击
  22. //以下条件说明【 orgType = 1或orgType = 2时可以点击】
  23. part: {
  24. prop: "orgType",
  25. value: [1,2]
  26. }
  27. },
  28. */
  29. <template>
  30. <div id="WarningMessage" class="p-box">
  31. <div class="p-return">
  32. <mu-appbar color="primary" class="lan-header">
  33. <mu-button icon slot="left" v-close>
  34. <i class="iconfont angle-left iconangle-left"></i>
  35. </mu-button>预警信息
  36. </mu-appbar>
  37. </div>
  38. <div class="p-content">
  39. <wallModule name="预警总计(个)" :total="totalCount" :bgImage="wallBgImage" />
  40. <div class="t-box">
  41. <div class="t-title">质量检查</div>
  42. <div class="t-content">
  43. <div class="t-header">
  44. <span class="name">超期未整改</span>
  45. <span class="total">{{totalCount}}</span>
  46. </div>
  47. <div class="t-body">
  48. <mTree
  49. v-show="tree.data.length"
  50. :data="tree.data"
  51. :props="tree.defaultProps"
  52. :lazy="true"
  53. @load="loadData"
  54. :clickableConditions="tree.clickableConditions"
  55. @click="skipPage"
  56. :showTotal="true"
  57. ></mTree>
  58. <NoData v-if="!tree.data.length&&!tree.loading" />
  59. </div>
  60. </div>
  61. </div>
  62. </div>
  63. </div>
  64. </template>
  65. <script>
  66. import WeatherModule from "@/weather/WeatherModule";
  67. import wallModule from "@/wall/wallModule";
  68. import mTree from "@/tree/mTree";
  69. export default {
  70. name: "WarningMessage",
  71. components: {
  72. WeatherModule,
  73. mTree,
  74. wallModule
  75. },
  76. data() {
  77. return {
  78. totalCount: 0,
  79. overflowDateCount: 0,
  80. wallBgImage: require("#/assets/img/wall/wall.png"),
  81. tree: {
  82. loading: false,
  83. defaultProps: {
  84. id: "orgId",
  85. name: "orgName",
  86. children: "children"
  87. },
  88. clickableConditions: {
  89. all: {
  90. //所有的是否可以点击
  91. enable: false
  92. },
  93. part: {
  94. //部分的可以点击的条件
  95. prop: "orgType",
  96. value: [1]
  97. }
  98. },
  99. data: []
  100. }
  101. };
  102. },
  103. computed: {},
  104. created() {
  105. this.initPage();
  106. },
  107. mounted() {},
  108. watch: {},
  109. methods: {
  110. skipPage(treeRowData) {},
  111. initPage() {
  112. this.getTotal();
  113. let params = {
  114. orgId: this.$A.GS("orgInfo")["orgId"],
  115. type: this.$A.GS("orgInfo")["type"],
  116. alarmStatus: 2
  117. };
  118. this.getData(params).then(response => {
  119. if (response.code == 200) {
  120. this.tree.data =
  121. response.body && response.body.length ? response.body : [];
  122. } else {
  123. this.tree.data = [];
  124. }
  125. });
  126. },
  127. getTotal() {
  128. let params = {
  129. orgId: this.$A.GS("orgInfo")["orgId"],
  130. type: this.$A.GS("orgInfo")["type"]
  131. };
  132. this.$A.Go("get", "/safety/qualityTotalAlarm/statistic", params).then(
  133. response => {
  134. if (response.code == 200) {
  135. this.totalCount = response.body.totalAlarmCount;
  136. }
  137. },
  138. err => {
  139. console.log(err);
  140. }
  141. );
  142. },
  143. loadData(treeRowData) {
  144. let params = {
  145. orgId: treeRowData.orgId,
  146. type: treeRowData.orgType,
  147. alarmStatus: 2
  148. };
  149. this.getData(params).then(response => {
  150. if (response.code == 200) {
  151. if (response.body && response.body.length) {
  152. var newArray = response.body;
  153. newArray.forEach(element => {
  154. element.level = treeRowData.level + 1;
  155. });
  156. this.$set(treeRowData, "children", newArray);
  157. this.$set(treeRowData, "expanded", true);
  158. } else {
  159. this.$set(treeRowData, "isLeaf", true);
  160. }
  161. } else {
  162. }
  163. });
  164. },
  165. getData(params) {
  166. this.$openLoading();
  167. this.tree.loading = true;
  168. let p = new Promise((resolve, reject) => {
  169. this.$A.Go("post", "/safety/importantRectLayer/statistic", params).then(
  170. response => {
  171. this.$closeLoading();
  172. this.tree.loading = false;
  173. resolve(response);
  174. },
  175. err => {
  176. this.$closeLoading();
  177. this.tree.loading = false;
  178. console.log(err);
  179. }
  180. );
  181. });
  182. return p;
  183. }
  184. },
  185. destroyed() {}
  186. };
  187. </script>
  188. <style lang="scss">
  189. #WarningMessage {
  190. //树形组件样式
  191. .treeList {
  192. border-top: 0.01rem solid $borderColor;
  193. [role="tree-content"] {
  194. background-color: #fff;
  195. -webkit-box-sizing: border-box;
  196. box-sizing: border-box;
  197. color: inherit;
  198. height: 0.55rem;
  199. display: block;
  200. overflow: hidden;
  201. position: relative;
  202. text-decoration: none;
  203. display: flex;
  204. align-items: center;
  205. border-bottom: 0.01rem solid #e0e0e0;
  206. [role="title"].active {
  207. >.tree-content-icon {
  208. background: $themeColoro;
  209. }
  210. }
  211. [role="title"].active {
  212. >.tree-content-label {
  213. background: $themeColoro;
  214. }
  215. }
  216. [role="title"] {
  217. height: 100%;
  218. width: 100%;
  219. display: flex;
  220. align-items: center;
  221. .tree-content-icon {
  222. display: flex;
  223. align-items: center;
  224. justify-content: center;
  225. color: $themeColor;
  226. height: 100%;
  227. padding: 0 0.14rem;
  228. border-right: 0.01rem solid rgba(224, 224, 224, 1);
  229. .iconfont {
  230. margin-left: 0.03rem;
  231. font-size: 0.08rem;
  232. }
  233. }
  234. .tree-content-icon.disabled {
  235. color: $themeColoro;
  236. cursor: not-allowed;
  237. }
  238. .tree-content-label {
  239. flex: 1;
  240. height: 100%;
  241. display: flex;
  242. min-width: 0;
  243. align-items: center;
  244. justify-content: space-between;
  245. padding: 0 0.14rem;
  246. .name {
  247. flex: 1;
  248. white-space: nowrap;
  249. text-overflow: hidden;
  250. text-overflow: ellipsis;
  251. overflow: hidden;
  252. }
  253. .icon {
  254. display: flex;
  255. height: 100%;
  256. align-items: center;
  257. margin-left: 0.05rem;
  258. .iconfont {
  259. margin-left: 0.15rem;
  260. color: #dbdbdb;
  261. }
  262. }
  263. }
  264. }
  265. }
  266. [role="tree-children"] {
  267. background: #fff;
  268. }
  269. [role="tree-children"]::before {
  270. content: "";
  271. }
  272. .iconfont.iconhidden {
  273. visibility: hidden;
  274. }
  275. .iconfont.iconnone {
  276. display: none;
  277. }
  278. }
  279. }
  280. </style>

mTree.vue

  1. <template>
  2. <div role="tree" class="treeList">
  3. <treeItem :node="node" v-bind="$attrs" v-on="$listeners" ref="tree" />
  4. </div>
  5. </template>
  6. <script>
  7. import treeItem from "./tree-item";
  8. export default {
  9. name: "mTree",
  10. components: {
  11. treeItem
  12. },
  13. props: {
  14. data: {
  15. type: Array,
  16. default: []
  17. }
  18. },
  19. data() {
  20. return {
  21. node: []
  22. };
  23. },
  24. computed: {},
  25. created() {},
  26. mounted() {},
  27. watch: {
  28. data: {
  29. handler(val, oldVal) {
  30. this.node = this.dealTreeData(val, 1);
  31. },
  32. deep: true
  33. }
  34. },
  35. methods: {
  36. dealTreeData(tree, level) {
  37. let arr = [];
  38. tree.length &&
  39. tree.forEach((item, index) => {
  40. let obj = {};
  41. obj = this.deepCopy(item);
  42. obj.level = level;
  43. // obj.expanded = true;
  44. if (item.children && item.children.length) {
  45. obj.children = this.dealTreeData(item.children, level + 1);
  46. } else {
  47. if (!this.$attrs.lazy) {
  48. obj.isLeaf = true;
  49. } else {
  50. obj.isLeaf = false;
  51. }
  52. }
  53. arr.push(obj);
  54. });
  55. return arr;
  56. },
  57. deepCopy(obj) {
  58. var result = Array.isArray(obj) ? [] : {};
  59. for (var key in obj) {
  60. if (obj.hasOwnProperty(key)) {
  61. if (typeof obj[key] === "object" && obj[key] !== null) {
  62. result[key] = this.deepCopy(obj[key]); //递归复制
  63. } else {
  64. result[key] = obj[key];
  65. }
  66. }
  67. }
  68. return result;
  69. },
  70. postData(data) {
  71. // this.$emit("load", data);
  72. }
  73. },
  74. destroyed() {}
  75. };
  76. </script>
  77. <style lang="scss">
  78. </style>

treeItem.vue

  1. <template>
  2. <div class>
  3. <div role="tree-item" class="treeItem" v-for="(item) in node" :key="item[$attrs.props.id]">
  4. <div role="tree-content">
  5. <div
  6. role="title"
  7. :class="item[$attrs.props.id]==currentId?'active':''"
  8. :style="{'background':`rgba(${255-colorLevel*(item.level-1)},${255-colorLevel*(item.level-1)},${255-colorLevel*(item.level-1)})`}"
  9. >
  10. <!-- 展开或收起 -->
  11. <!-- :style="{'visibility':item.isLeaf&&!item[$attrs.props.children]?'hidden':'visible'}" -->
  12. <span
  13. class="tree-content-icon"
  14. @click.stop="item.isLeaf&&!item[$attrs.props.children]?'':treeToggleClick(item)"
  15. :class="item.isLeaf&&!item[$attrs.props.children]?'disabled':''"
  16. >
  17. {{item.isLeaf&&!item[$attrs.props.children]?"展开":item['expanded']?'收起':"展开"}}
  18. <!-- <span
  19. class="iconfont"
  20. :class="item['expanded']?'iconangle-down':'iconangle-right'"
  21. ></span>-->
  22. </span>
  23. <!-- 标题 -->
  24. <!-- !enabledConfigClick?'':clickType == 'all'?treeConfigClick(item):(item[$attrs.clickableConditions.part.prop]==$attrs.clickableConditions.part.value?treeConfigClick(item):false) -->
  25. <label
  26. class="tree-content-label"
  27. @click.stop="!enabledConfigClick?'':clickType == 'all'?treeConfigClick(item):($attrs.clickableConditions.part.value.includes(item[$attrs.clickableConditions.part.prop])?treeConfigClick(item):false)"
  28. >
  29. <span class="name">{{ item[$attrs.props.name]}}</span>
  30. <span class="icon">
  31. <span v-if="$attrs.showTotal">{{item.projectCount}}</span>
  32. <i
  33. class="iconfont iconangle-right"
  34. v-if="!enabledConfigClick?false:clickType == 'all'?true:($attrs.clickableConditions.part.value.includes(item[$attrs.clickableConditions.part.prop])?true:false)"
  35. ></i>
  36. <i
  37. class="iconfont iconangle-right"
  38. v-else
  39. :class="$attrs.showTotal?'iconhidden':'iconnone'"
  40. ></i>
  41. </span>
  42. </label>
  43. </div>
  44. </div>
  45. <VerticalToggle>
  46. <!-- :style="{ 'padding-left': .14 + 'rem' }" -->
  47. <div role="tree-children" v-if="item['expanded']">
  48. <treeItem :node="item[$attrs.props.children]" v-bind="$attrs" v-on="$listeners" />
  49. </div>
  50. </VerticalToggle>
  51. </div>
  52. </div>
  53. </template>
  54. <script>
  55. import VerticalToggle from "./js/VerticalToggle";
  56. export default {
  57. name: "treeItem",
  58. components: {
  59. VerticalToggle
  60. },
  61. props: {
  62. node: {}
  63. },
  64. data() {
  65. return {
  66. tree: null,
  67. data: [],
  68. currentId: "",
  69. enabledConfigClick: false,
  70. clickType: "all",
  71. colorLevel: 5
  72. };
  73. },
  74. computed: {},
  75. created() {
  76. if (this.$attrs.clickableConditions) {
  77. if (
  78. this.$attrs.clickableConditions.all &&
  79. this.$attrs.clickableConditions.all.enable
  80. ) {
  81. this.enabledConfigClick = true;
  82. this.clickType = "all";
  83. } else if (this.$attrs.clickableConditions.part) {
  84. this.enabledConfigClick = true;
  85. this.clickType = "part";
  86. } else {
  87. this.enabledConfigClick = false;
  88. }
  89. } else {
  90. this.enabledConfigClick = false;
  91. }
  92. },
  93. mounted() {},
  94. watch: {},
  95. methods: {
  96. /**点击展开收起的事件 */
  97. treeToggleClick(item) {
  98. // this.currentId = item[this.$attrs.props.id];
  99. if (this.$attrs.lazy) {
  100. if (item.isLeaf || item[this.$attrs.props.children]) {
  101. this.$set(item, "expanded", !item.expanded);
  102. } else {
  103. if (item.orgType && item.orgType == 1) {
  104. this.$set(item, "expanded", !item.expanded);
  105. this.$set(item, "isLeaf", true);
  106. } else {
  107. this.$parent.$emit("load", item);
  108. }
  109. //this.$parent.$emit("load", item);
  110. }
  111. } else {
  112. this.$set(item, "expanded", !item.expanded);
  113. }
  114. },
  115. /**点击右侧文字的事件 */
  116. treeConfigClick(item) {
  117. this.$attrs.itemActive
  118. ? (this.currentId = item[this.$attrs.props.id])
  119. : "";
  120. this.$parent.$emit("click", item);
  121. },
  122. postData(item) {
  123. debugger;
  124. }
  125. },
  126. destroyed() {}
  127. };
  128. </script>
  129. <style lang="scss">
  130. /*树形组件*/
  131. </style>

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/繁依Fanyi0/article/detail/231606
推荐阅读
相关标签
  

闽ICP备14008679号