selecttree.vue 5.0 KB

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