| <template> | 
|   <div> | 
|     <el-tree | 
|       ref="tree" | 
|       class="comb-tree" | 
|       :disabled="disabled" | 
|       highlight-current | 
|       :check-strictly="checkStrictly" | 
|       :default-expand-all="!lazy" | 
|       :expand-on-click-node="true" | 
|       :props="defaultProps" | 
|       :show-checkbox="multiple" | 
|       :check-on-click-node="leafOnly" | 
|       :node-key="idField" | 
|       :data="treeDatas" | 
|       :filter-node-method="filterNode" | 
|       :lazy="lazy" | 
|       :load="loadNode" | 
|       :default-expanded-keys="expandedIds" | 
|       @node-click="onNodeClick" | 
|       @check-change="onCheckChange"> | 
|     </el-tree> | 
|     <div style="margin-top: 10px;">{{filterTip}}</div> | 
|   </div> | 
| </template> | 
| <script> | 
|   | 
|   import cloneDeep from 'lodash/cloneDeep' | 
|   | 
|   export default { | 
|     name: 'ZtTreeSelector', | 
|     components: {}, | 
|     props: { | 
|       value: [String, Array], | 
|       idField: { | 
|         type: String, | 
|         default: 'id' | 
|       }, | 
|       textField: { | 
|         type: String, | 
|         default: 'name' | 
|       }, | 
|       disabled:{ | 
|         type: Boolean, | 
|         default: false, | 
|       }, | 
|       parentIdField: { | 
|         type: String, | 
|         default: 'pid' | 
|       }, | 
|       url: String, | 
|       datas: [String, Array], | 
|       simple: Boolean, // 简单模式 | 
|       multiple: { // 默认多选 | 
|         type: Boolean, | 
|         default: true | 
|       }, | 
|       leafOnly: { // 是否只能选择叶子节点 | 
|         type: Boolean, | 
|         default: false | 
|       }, | 
|       hasHalfChecked: { // 是否包含半选的节点 | 
|         type: Boolean, | 
|         default: false | 
|       }, | 
|       checkStrictly: { // 在显示复选框的情况下,是否严格的遵循父子不互相关联的做法 | 
|         type: Boolean, | 
|         default: false | 
|       }, | 
|       lazy: { // 懒加载子节点 | 
|         type: Boolean, | 
|         default: false | 
|       }, | 
|       expandLevel: { // 懒加载展开层级 | 
|         type: Number, | 
|         default: 0 | 
|       }, | 
|       disabledFilter: Function, // 可选的节点 | 
|       placeholder: String | 
|     }, | 
|     data() { | 
|       return { | 
|         editing: false, | 
|         dataList: [], | 
|         treeDatas: [], // 带children的 | 
|         dataMap: {}, | 
|         expandedIds: [], | 
|         filterTip: '', | 
|         defaultProps: { | 
|           children: 'children', | 
|           label: this.textField, | 
|           isLeaf: 'leaf', | 
|           disabled: this.disabledFilter | 
|         } | 
|       } | 
|     }, | 
|     computed: {}, | 
|     watch: { | 
|       value(val, oldval) { | 
|         if (!this.editing) { | 
|           this.setText(val) | 
|         } | 
|         this.editing = false | 
|       }, | 
|       url(val, oldval) { | 
|         this.queryDataList(val) | 
|       }, | 
|       datas(val, oldval) { | 
|         this.setDataList(val) | 
|       } | 
|     }, | 
|     mounted() { | 
|       if (this.datas !== undefined && this.datas.length > 0) { | 
|         this.setDataList(cloneDeep(this.datas)) | 
|       } else if (this.url !== undefined) { // 指定了url | 
|         this.queryDataList(this.url) | 
|       } | 
|     }, | 
|     methods: { | 
|       async queryDataList(url) { | 
|         let res = await this.$http.get(url, null) | 
|         this.setDataList(res.data) | 
|       }, | 
|       setDataList(data) { // 设置树的值 | 
|         let dataList | 
|         if (Array.isArray(data)) { | 
|           dataList = data | 
|         } else { | 
|           dataList = data.rows | 
|         } | 
|         if (this.simple === true) { // 简单数组 | 
|           this.dataList = dataList | 
|   | 
|           let dataMap = {} | 
|           let treeDatas = [] | 
|           dataList.forEach(item => { | 
|             dataMap[item[this.idField]] = item | 
|           }) | 
|           dataList.forEach(item => { | 
|             let parent = this.dataMap[item[this.parentIdField]] | 
|             if (parent) { // 存在父节点 | 
|               let children = parent.children || [] | 
|               children.push(item) | 
|               parent.children = children | 
|             } else { | 
|               treeDatas.push(item) | 
|             } | 
|           }) | 
|           this.treeDatas = treeDatas | 
|           this.flattenTrees(treeDatas) // 设置level | 
|         } else { // 带children的 | 
|           this.treeDatas = dataList | 
|           this.dataList = this.flattenTrees(dataList) | 
|         } | 
|         if (this.lazy) { // 懒加载时 | 
|           let expandedIds = [] | 
|           this.dataList.forEach(item => { | 
|             // console.log(item,'itemitemitemitem') | 
|             if (item.children ===undefined || item.children.length === 0) { | 
|               item.leaf = true | 
|             } | 
|             if (item._level < this.expandLevel) { | 
|               expandedIds.push(item[this.idField]) | 
|             } | 
|           }) | 
|           this.expandedIds = expandedIds | 
|         } | 
|         if (this.value && this.value.length > 0) { | 
|           this.setText(this.value) | 
|         } | 
|       }, | 
|   | 
|       filter(val) { // 输入过滤 | 
|         this.filterTip = '' | 
|         if (this.lazy && val.length > 0) { | 
|           let expandedIds = [] // 需要展开的节点 | 
|           for (var i = 0; i < this.dataList.length; i++) { | 
|             let item = this.dataList[i] | 
|             if (item[this.textField].indexOf(val) !== -1) { | 
|               expandedIds.push(item[this.idField]) | 
|             } | 
|           } | 
|           if (expandedIds.length > 0) { | 
|             let maxLength = 50 | 
|             if (expandedIds.length >= maxLength) { // 最多展示maxLength条 | 
|               this.filterTip = `*找到${expandedIds.length}条结果,只展示前${maxLength}条` | 
|               expandedIds = expandedIds.slice(0, maxLength) | 
|             } | 
|             this.expandNodes(expandedIds) | 
|             this.$nextTick(() => { | 
|               this.$refs.tree.filter(val) | 
|             }) | 
|             return | 
|           } | 
|         } | 
|         this.$refs.tree.filter(val) | 
|       }, | 
|       onNodeClick(data, node) { // 单选:修改了父节点也可以被选中。 | 
|         if (!this.multiple && (!this.disabledFilter || !this.disabledFilter(data))) { // 单选 | 
|           if (this.leafOnly && (data.children || []).length > 0) { // 只能选择叶子节点,但当前不是叶子节点 | 
|             return | 
|           } | 
|           this.editing = true // 编辑中 | 
|   | 
|           this.$emit('input', data[this.idField]) | 
|           this.$emit('selected', data, true) | 
|         } | 
|       }, | 
|       onCheckChange(data, checked, indeterminate) { // 多选选中 | 
|         if (this.multiple) { | 
|           this.editing = true // 编辑中 | 
|           let checkedNodes = this.$refs.tree.getCheckedNodes(this.leafOnly) | 
|           if (this.hasHalfChecked) { // 半选的 | 
|             checkedNodes = checkedNodes.concat(this.$refs.tree.getHalfCheckedNodes()) | 
|           } | 
|           checkedNodes = checkedNodes.filter(node => (!this.disabledFilter || !this.disabledFilter(node))) // 所有允许选中的 | 
|           let values = [] | 
|           checkedNodes.forEach(node => { | 
|             values.push(node[this.idField]) | 
|           }) | 
|           this.$emit('input', values) | 
|           this.$emit('selected', checkedNodes, true) | 
|         } | 
|       }, | 
|       cancelSelected(node) { // 取消节点选中 | 
|         this.$refs.tree.setChecked(node, false) | 
|       }, | 
|       setText(value) { // 设置值 | 
|         value = value || '' | 
|         if (!this.multiple) { // 单选 | 
|           if (!value) { | 
|             this.$emit('selected', null, false) | 
|           } else { | 
|             let that = this | 
|             let nodes = this.dataList.filter(item => item[that.idField] === value) | 
|             if (nodes && nodes.length === 1) { | 
|               this.$refs.tree.setCurrentKey(nodes[0][that.idField])// 选中 | 
|               this.$emit('selected', nodes[0], false) | 
|             } else { | 
|               this.$emit('selected', null, false) | 
|             } | 
|           } | 
|         } else { // 多选 | 
|           let selectValues = Array.isArray(value) ? value : value.split(',') | 
|           let selectNodes = this.dataList.filter(d => selectValues.indexOf(d[this.idField]) >= 0) | 
|           let values = [] | 
|           selectNodes.filter(d => (d.children || []).length === 0).forEach(node => { | 
|             if (!this.disabledFilter || !this.disabledFilter(node)) { | 
|               values.push(node[this.idField]) | 
|             } | 
|           }) | 
|           this.$refs.tree.setCheckedKeys(values)// 会级联选中上级 | 
|           this.$emit('selected', selectNodes, false) | 
|         } | 
|         if (this.lazy) { // 懒加载时 | 
|           if (value.length > 0) { | 
|             this.expandNodes(Array.isArray(value) ? value : value.split(',')) | 
|           } | 
|         } | 
|       }, | 
|       filterNode(value, data) { // 筛选 | 
|         if (!value) { | 
|           return true | 
|         } | 
|         return data[this.textField].indexOf(value) !== -1 && (!this.disabledFilter || !this.disabledFilter(data)) | 
|       }, | 
|       flattenTrees(trees, level = 0) { // tree转array | 
|         let result = [] | 
|         trees.forEach(item => { | 
|           result.push(item) | 
|           item._level = level | 
|           item.children && result.push(...this.flattenTrees(item.children, level + 1)) | 
|         }) | 
|         return result | 
|       }, | 
|       loadNode(node, resolve) { | 
|         let that = this | 
|         if (node.level === 0) { | 
|           return resolve(that.treeDatas) | 
|         } else if (node.data) { | 
|           return resolve((node.data.children || [])) | 
|         } else { | 
|           return resolve([]) | 
|         } | 
|       }, | 
|       expandNodes(ids) { // 展开节点及其父节点 | 
|         let expandedIds = [] | 
|         let getParentIds = (id) => { | 
|           if (expandedIds.indexOf(id) !== -1) { | 
|             return [] | 
|           } | 
|           for (var i = 0; i < this.dataList.length; i++) { | 
|             let item = this.dataList[i] | 
|             if (expandedIds.indexOf(item[this.idField]) === -1) { | 
|               if (item.children != undefined) | 
|               { | 
|                 for (var j = 0; j < item.children.length; j++) { | 
|                   let children = item.children[j] | 
|                   if (children[this.idField] === id) { | 
|                     return [item.id, ...getParentIds(item.id)] | 
|                   } | 
|                 } | 
|               } | 
|             } | 
|           } | 
|           return [] | 
|         } | 
|         ids.forEach((id) => { | 
|           expandedIds.push(...getParentIds(id), id) | 
|         }) | 
|         this.expandedIds = expandedIds | 
|       } | 
|     } | 
|   } | 
| </script> | 
| <style lang="scss"> | 
|   .is-reverse { | 
|     transform: rotate(-180deg); | 
|   } | 
|   | 
|   .comb-tree { | 
|     display: flex; | 
|     width: auto; | 
|     height: 250px; | 
|     overflow-y: auto; | 
|   | 
|     label.el-checkbox { | 
|       margin-right: 8px; | 
|     } | 
|   } | 
| </style> |