selecttree.vue 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213
  1. <template>
  2. <div class="selectTree">
  3. <el-select
  4. size="small"
  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. defaultParentProps: {
  55. type: Object,
  56. default: () => {
  57. return {
  58. children: "children",
  59. label: "companyName",
  60. value: "companyCode",
  61. };
  62. },
  63. },
  64. },
  65. data() {
  66. return {
  67. defaultProps: {},
  68. newVal: "", //本页面选中的数据
  69. label: "",
  70. selectTree: {},
  71. defaultExpandedKeys: [], //默认展开
  72. searchData: [], //带搜索数据
  73. openSearch: false, //是否开启搜索
  74. };
  75. },
  76. watch: {
  77. value: {
  78. handler(value) {
  79. if (value) {
  80. this.newVal = value;
  81. this.defaultExpandedKeys = [value];
  82. this.$nextTick(() => {
  83. this.$refs.tree.setCurrentKey(value); //设置默认选择
  84. });
  85. const check = this.findLabel(this.list, value);
  86. if (check) {
  87. this.label = check.companyName;
  88. }
  89. } else {
  90. this.newVal = "";
  91. this.label = "";
  92. }
  93. },
  94. deep: true, // 深度监听
  95. immediate: true, //首次触发
  96. },
  97. list: {
  98. handler(value) {
  99. if (value && this.type === "1") {
  100. this.newVal = value[0][this.defaultParentProps.value];
  101. }
  102. },
  103. deep: true, // 深度监听
  104. },
  105. newVal(value) {
  106. const check = this.findLabel(this.list, value);
  107. if (check) {
  108. this.label = check.companyName;
  109. }
  110. this.$emit("input", value);
  111. },
  112. },
  113. created() {
  114. // el-select 中加了filterable 点击箭头回收不去问题
  115. Object.getPrototypeOf(
  116. this.$options.components
  117. ).ElSelect.options.methods.handleFocus = () => {};
  118. },
  119. mounted() {},
  120. methods: {
  121. //节点选择事件
  122. handleNodeClick(data) {
  123. this.newVal = data[this.defaultParentProps.value];
  124. this.label = data[this.defaultParentProps.label];
  125. this.$refs.elSelect.blur();
  126. this.searchData = [];
  127. this.openSearch = false;
  128. this.$emit("change", data);
  129. },
  130. //筛选树
  131. async filterTree(value) {
  132. if (value) {
  133. this.openSearch = true;
  134. this.searchData = [];
  135. await this.findItem(this.list, value);
  136. } else {
  137. this.openSearch = false;
  138. this.searchData = [];
  139. }
  140. },
  141. //递归筛选,查询时用
  142. findItem(arr, value) {
  143. return new Promise((resolve) => {
  144. for (let i = 0; i < arr.length; i++) {
  145. const item = arr[i];
  146. if (item.label.includes(value)) {
  147. this.searchData.push(item);
  148. } else if (item.children && item.children.length > 0) {
  149. this.findItem(item.children, value);
  150. }
  151. }
  152. resolve(true);
  153. });
  154. },
  155. //递归筛选,回显label
  156. findLabel(arr, value) {
  157. for (let i = 0; i < arr.length; i++) {
  158. const item = arr[i];
  159. if (item[this.defaultParentProps.value] === value) {
  160. return item;
  161. } else if (item.children && item.children.length > 0) {
  162. const result = this.findLabel(item.children, value);
  163. if (result) {
  164. return result;
  165. }
  166. }
  167. }
  168. },
  169. //清空事件
  170. clear() {
  171. this.$refs.tree.setCurrentKey(null); //清空高亮
  172. this.label = "";
  173. this.newVal = "";
  174. this.searchData = [];
  175. this.openSearch = false;
  176. this.$emit("change", {});
  177. },
  178. },
  179. };
  180. </script>
  181. <style scoped lang="scss">
  182. .selectTree {
  183. display: inline-block;
  184. width: 100%;
  185. }
  186. .el-select {
  187. width: 100%;
  188. }
  189. .hasTree {
  190. padding: 0 !important;
  191. margin: 0;
  192. overflow: auto;
  193. line-height: normal;
  194. height: auto;
  195. cursor: default !important;
  196. font-weight: 500 !important;
  197. ::v-deep .el-tree-node__content {
  198. height: 34px;
  199. line-height: 34px;
  200. }
  201. ::v-deep .el-tree-node__label {
  202. font-size: 14px !important;
  203. }
  204. }
  205. </style>