index.vue 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234
  1. <template>
  2. <el-select ref="treeSelect" :size="size" :value="valueTitle" :clearable="clearable" @clear="clearHandle" :style="{width:width}">
  3. <el-input :size="size" class="selectInput" :placeholder="placeholder" v-model="filterText"></el-input>
  4. <el-option :value="valueTitle" :label="valueTitle" class="options">
  5. <el-tree
  6. id="tree-option"
  7. ref="selectTree"
  8. :accordion="accordion"
  9. :data="optionData"
  10. :props="props"
  11. :node-key="props.value"
  12. :default-expanded-keys="defaultExpandedKey"
  13. :filter-node-method="filterNode"
  14. @node-click="handleNodeClick"
  15. ></el-tree>
  16. </el-option>
  17. </el-select>
  18. </template>
  19. <script>
  20. export default {
  21. name: "el-tree-select",
  22. props: {
  23. /* 配置项 */
  24. props: {
  25. type: Object,
  26. default: () => {
  27. return {
  28. value: "id", // ID字段名
  29. label: "name", // 显示名称
  30. children: "children" // 子级字段名
  31. };
  32. }
  33. },
  34. /* 选项列表数据(树形结构的对象数组) */
  35. options: {
  36. type: Array,
  37. default: () => {
  38. return [];
  39. }
  40. },
  41. /* 初始值 */
  42. value: {
  43. type: String,
  44. default: () => {
  45. return null;
  46. }
  47. },
  48. /* 初始值 */
  49. size: {
  50. type: String,
  51. default: () => {
  52. return "small";
  53. }
  54. },
  55. width: {
  56. type: String,
  57. default: () => {
  58. return "200px";
  59. }
  60. },
  61. /* 可清空选项 */
  62. clearable: {
  63. type: Boolean,
  64. default: () => {
  65. return true;
  66. }
  67. },
  68. /* 自动收起 */
  69. accordion: {
  70. type: Boolean,
  71. default: () => {
  72. return true;
  73. }
  74. },
  75. placeholder: {
  76. type: String,
  77. default: () => {
  78. return "检索关键字";
  79. }
  80. }
  81. },
  82. computed: {
  83. /* 转树形数据 */
  84. optionData() {
  85. //第一个节点为根节点
  86. if (this.options.length > 0) {
  87. var rootId = this.options[0].id;
  88. let cloneData = JSON.parse(JSON.stringify(this.options)); // 对源数据深度克隆
  89. return cloneData.filter(father => {
  90. // 循环所有项,并添加children属性
  91. let branchArr = cloneData.filter(
  92. child => father.id == child.parentId
  93. ); // 返回每一项的子级数组
  94. branchArr.length > 0 ? (father.children = branchArr) : ""; //给父级添加一个children属性,并赋值
  95. return father.id == rootId || father.parentId == null; //返回第一层
  96. });
  97. } else {
  98. return [];
  99. }
  100. }
  101. },
  102. data() {
  103. return {
  104. filterText: "",
  105. valueId: this.value, // 初始值
  106. valueTitle: "",
  107. defaultExpandedKey: []
  108. };
  109. },
  110. mounted() {
  111. this.initHandle();
  112. },
  113. methods: {
  114. // 初始化值
  115. initHandle() {
  116. console.log("options.length=" + this.options.length);
  117. console.log(this.value);
  118. var arr = this.options.filter(item=>item.id == this.value);
  119. if(arr.length>0){
  120. this.valueTitle = arr[0][this.props.label];
  121. }
  122. if(this.valueId){
  123. this.$refs.selectTree.setCurrentKey(this.valueId); // 设置默认选中
  124. this.defaultExpandedKey = [this.valueId]; // 设置默认展开
  125. }
  126. this.initScroll();
  127. },
  128. // 初始化滚动条
  129. initScroll() {
  130. this.$nextTick(() => {
  131. let scrollWrap = document.querySelectorAll(
  132. ".el-scrollbar .el-select-dropdown__wrap"
  133. )[0];
  134. let scrollBar = document.querySelectorAll(
  135. ".el-scrollbar .el-scrollbar__bar"
  136. );
  137. scrollWrap.style.cssText =
  138. "margin: 0px; max-height: none; overflow: hidden;";
  139. scrollBar.forEach(ele => (ele.style.width = 0));
  140. });
  141. },
  142. // 切换选项
  143. handleNodeClick(node) {
  144. this.valueTitle = node[this.props.label];
  145. this.valueId = node[this.props.value];
  146. //this.node = node;
  147. this.$emit("input", this.valueId);
  148. this.$refs.treeSelect.blur();
  149. //this.$emit('getValue',node)
  150. this.defaultExpandedKey = [];
  151. },
  152. // 清除选中
  153. clearHandle() {
  154. this.valueTitle = "";
  155. this.valueId = null;
  156. this.defaultExpandedKey = [];
  157. this.clearSelected();
  158. this.$emit("input", null);
  159. },
  160. /* 清空选中样式 */
  161. clearSelected() {
  162. let allNode = document.querySelectorAll("#tree-option .el-tree-node");
  163. allNode.forEach(element => element.classList.remove("is-current"));
  164. },
  165. filterNode(value, data) {
  166. if (!value) return true;
  167. return data.name.indexOf(value) !== -1;
  168. }
  169. },
  170. watch: {
  171. value(newVal,oldVal) {
  172. this.valueId = newVal;
  173. if(newVal=='') {
  174. this.clearHandle();
  175. }
  176. this.initHandle();
  177. },
  178. options(newVal,oldVal) {
  179. //如果options读取慢,则
  180. if(oldVal==null || oldVal.length==0){
  181. setTimeout(()=>{
  182. this.initHandle();
  183. },100);
  184. }
  185. },
  186. filterText(val) {
  187. this.$refs.selectTree.filter(val);
  188. }
  189. }
  190. };
  191. </script>
  192. <style>
  193. .el-scrollbar .el-scrollbar__view .el-select-dropdown__item {
  194. height: auto;
  195. max-height: 274px;
  196. padding: 0;
  197. overflow: hidden;
  198. overflow-y: auto;
  199. }
  200. .el-select-dropdown__item.selected {
  201. font-weight: normal;
  202. }
  203. ul li >>> .el-tree .el-tree-node__content {
  204. height: auto;
  205. padding: 0 20px;
  206. }
  207. .el-tree-node__label {
  208. font-weight: normal;
  209. }
  210. .el-tree >>> .is-current .el-tree-node__label {
  211. color: #409eff;
  212. font-weight: 700;
  213. }
  214. .el-tree >>> .is-current .el-tree-node__children .el-tree-node__label {
  215. color: #606266;
  216. font-weight: normal;
  217. }
  218. .selectInput {
  219. padding: 0 5px;
  220. box-sizing: border-box;
  221. }
  222. </style>