selecttree.vue 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210
  1. <template>
  2. <div class="selectTree">
  3. <el-select
  4. ref="elSelect"
  5. v-model="newVal"
  6. :placeholder="placeholder"
  7. :filter-method="filterTree"
  8. @change="$forceUpdate()"
  9. @clear="clear"
  10. popper-append-to-body
  11. >
  12. <el-option :value="newVal" :label="label" class="hasTree" disabled>
  13. <el-tree
  14. :data="openSearch ? searchData : list"
  15. ref="tree"
  16. :node-key="defaultParentProps.value"
  17. :expand-on-click-node="false"
  18. :default-expanded-keys="defaultExpandedKeys"
  19. :current-node-key="newVal"
  20. highlight-current
  21. :props="defaultParentProps"
  22. check-on-click-node
  23. auto-expand-parent
  24. @node-click="handleNodeClick"
  25. ></el-tree>
  26. </el-option>
  27. </el-select>
  28. </div>
  29. </template>
  30. <script>
  31. export default {
  32. name: "ElSelectTree",
  33. props: {
  34. value: {
  35. type: String,
  36. require: true,
  37. },
  38. list: {
  39. //树状列表:{label:'',value:'',children:[]}
  40. type: Array,
  41. default: () => {
  42. return [];
  43. },
  44. },
  45. placeholder: {
  46. type: String,
  47. default: "请选择",
  48. },
  49. type: {
  50. type: String,
  51. default: "0",
  52. },
  53. defaultParentProps: {
  54. type: Object,
  55. default: () => {
  56. return {
  57. children: "children",
  58. label: "companyName",
  59. value: "companyCode",
  60. };
  61. },
  62. },
  63. },
  64. data() {
  65. return {
  66. defaultProps: {},
  67. newVal: "", //本页面选中的数据
  68. label: "",
  69. selectTree: {},
  70. defaultExpandedKeys: [], //默认展开
  71. searchData: [], //带搜索数据
  72. openSearch: false, //是否开启搜索
  73. };
  74. },
  75. watch: {
  76. value: {
  77. handler(value) {
  78. if (value) {
  79. this.newVal = value;
  80. this.defaultExpandedKeys = [value];
  81. this.$nextTick(() => {
  82. this.$refs.tree.setCurrentKey(value); //设置默认选择
  83. });
  84. const check = this.findLabel(this.list, value);
  85. if (check) {
  86. this.label = check.companyName;
  87. }
  88. }
  89. },
  90. deep: true, // 深度监听
  91. immediate: true, //首次触发
  92. },
  93. list: {
  94. handler(value) {
  95. if (value && this.type === "1") {
  96. this.newVal = value[0][this.defaultParentProps.value];
  97. }
  98. },
  99. deep: true, // 深度监听
  100. },
  101. newVal(value) {
  102. const check = this.findLabel(this.list, value);
  103. if (check) {
  104. this.label = check.companyName;
  105. }
  106. this.$emit("input", value);
  107. },
  108. },
  109. created() {
  110. // el-select 中加了filterable 点击箭头回收不去问题
  111. Object.getPrototypeOf(
  112. this.$options.components
  113. ).ElSelect.options.methods.handleFocus = () => {};
  114. },
  115. mounted() {},
  116. methods: {
  117. //节点选择事件
  118. handleNodeClick(data) {
  119. this.newVal = data[this.defaultParentProps.value];
  120. this.label = data[this.defaultParentProps.label];
  121. this.$refs.elSelect.blur();
  122. this.searchData = [];
  123. this.openSearch = false;
  124. this.$emit("change", data);
  125. },
  126. //筛选树
  127. async filterTree(value) {
  128. if (value) {
  129. this.openSearch = true;
  130. this.searchData = [];
  131. await this.findItem(this.list, value);
  132. } else {
  133. this.openSearch = false;
  134. this.searchData = [];
  135. }
  136. },
  137. //递归筛选,查询时用
  138. findItem(arr, value) {
  139. return new Promise((resolve) => {
  140. for (let i = 0; i < arr.length; i++) {
  141. const item = arr[i];
  142. if (item.label.includes(value)) {
  143. this.searchData.push(item);
  144. } else if (item.children && item.children.length > 0) {
  145. this.findItem(item.children, value);
  146. }
  147. }
  148. resolve(true);
  149. });
  150. },
  151. //递归筛选,回显label
  152. findLabel(arr, value) {
  153. for (let i = 0; i < arr.length; i++) {
  154. const item = arr[i];
  155. if (item[this.defaultParentProps.value] === value) {
  156. return item;
  157. } else if (item.children && item.children.length > 0) {
  158. const result = this.findLabel(item.children, value);
  159. if (result) {
  160. return result;
  161. }
  162. }
  163. }
  164. },
  165. //清空事件
  166. clear() {
  167. this.$refs.tree.setCurrentKey(null); //清空高亮
  168. this.label = "";
  169. this.newVal = "";
  170. this.searchData = [];
  171. this.openSearch = false;
  172. this.$emit("change", {});
  173. },
  174. },
  175. };
  176. </script>
  177. <style scoped lang="scss">
  178. .selectTree {
  179. display: inline-block;
  180. width: 100%;
  181. }
  182. .el-select {
  183. width: 100%;
  184. }
  185. .hasTree {
  186. padding: 0 !important;
  187. margin: 0;
  188. overflow: auto;
  189. line-height: normal;
  190. height: auto;
  191. cursor: default !important;
  192. font-weight: 500 !important;
  193. ::v-deep .el-tree-node__content {
  194. height: 34px;
  195. line-height: 34px;
  196. }
  197. ::v-deep .el-tree-node__label {
  198. font-size: 14px !important;
  199. }
  200. }
  201. </style>