tree_select.vue 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262
  1. <template>
  2. <div>
  3. <div class="mask" v-show="isShowSelect" @click="isShowSelect = !isShowSelect"></div>
  4. <el-popover placement="bottom-start" :width="width" trigger="manual" v-model="isShowSelect" @hide="popoverHide">
  5. <el-tree class="common-tree" :style="style" ref="tree" :data="data" :props="defaultProps"
  6. :show-checkbox="multiple" :node-key="nodeKey" :check-strictly="checkStrictly" default-expand-all
  7. :expand-on-click-node="false" :check-on-click-node="multiple" :highlight-current="true"
  8. @node-click="handleNodeClick" @check-change="handleCheckChange"></el-tree>
  9. <el-select :style="selectStyle" slot="reference" ref="select" :size="size" v-model="selectedData"
  10. :multiple="multiple" :clearable="clearable" :collapse-tags="collapseTags"
  11. @click.native="isShowSelect = !isShowSelect" @remove-tag="removeSelectedNodes"
  12. @clear="removeSelectedNode" @change="changeSelectedNodes" class="tree-select">
  13. <el-option v-for="(item, idx) in options" :key="idx" :label="item.label" :value="item.value">
  14. </el-option>
  15. </el-select>
  16. </el-popover>
  17. </div>
  18. </template>
  19. <script>
  20. export default {
  21. name: "tree-select",
  22. props: {
  23. // 树结构数据
  24. data: {
  25. type: Array,
  26. default () {
  27. return [];
  28. }
  29. },
  30. defaultProps: {
  31. type: Object,
  32. default () {
  33. return {};
  34. }
  35. },
  36. // 配置是否可多选
  37. multiple: {
  38. type: Boolean,
  39. default () {
  40. return false;
  41. }
  42. },
  43. // 配置是否可清空选择
  44. clearable: {
  45. type: Boolean,
  46. default () {
  47. return false;
  48. }
  49. },
  50. // 配置多选时是否将选中值按文字的形式展示
  51. collapseTags: {
  52. type: Boolean,
  53. default () {
  54. return false;
  55. }
  56. },
  57. nodeKey: {
  58. type: String,
  59. default () {
  60. return "id";
  61. }
  62. },
  63. // 显示复选框情况下,是否严格遵循父子不互相关联
  64. checkStrictly: {
  65. type: Boolean,
  66. default () {
  67. return false;
  68. }
  69. },
  70. // 默认选中的节点key数组
  71. checkedKeys: {
  72. type: Array,
  73. default () {
  74. return [];
  75. }
  76. },
  77. size: {
  78. type: String,
  79. default () {
  80. return "";
  81. }
  82. },
  83. width: {
  84. type: Number,
  85. default () {
  86. return 250;
  87. }
  88. },
  89. height: {
  90. type: Number,
  91. default () {
  92. return 300;
  93. }
  94. }
  95. },
  96. data() {
  97. return {
  98. isShowSelect: false, // 是否显示树状选择器
  99. options: [],
  100. selectedData: [], // 选中的节点
  101. style: "width:" + this.width + "px;" + "height:" + this.height + "px;",
  102. selectStyle: "width:" + (this.width + 24) + "px;",
  103. checkedIds: [],
  104. checkedData: []
  105. };
  106. },
  107. mounted() {
  108. this.initCheckedData();
  109. },
  110. methods: {
  111. // 单选时点击tree节点,设置select选项
  112. setSelectOption(node) {
  113. let tmpMap = {};
  114. tmpMap.value = node.key;
  115. tmpMap.label = node.label;
  116. this.options = [];
  117. this.options.push(tmpMap);
  118. this.selectedData = node.key;
  119. },
  120. // 单选,选中传进来的节点
  121. checkSelectedNode(checkedKeys) {
  122. var item = checkedKeys[0];
  123. this.$refs.tree.setCurrentKey(item);
  124. var node = this.$refs.tree.getNode(item);
  125. this.setSelectOption(node);
  126. },
  127. // 多选,勾选上传进来的节点
  128. checkSelectedNodes(checkedKeys) {
  129. this.$refs.tree.setCheckedKeys(checkedKeys);
  130. },
  131. // 单选,清空选中
  132. clearSelectedNode() {
  133. this.selectedData = "";
  134. this.$refs.tree.setCurrentKey(null);
  135. },
  136. // 多选,清空所有勾选
  137. clearSelectedNodes() {
  138. var checkedKeys = this.$refs.tree.getCheckedKeys(); // 所有被选中的节点的 key 所组成的数组数据
  139. for (let i = 0; i < checkedKeys.length; i++) {
  140. this.$refs.tree.setChecked(checkedKeys[i], false);
  141. }
  142. },
  143. initCheckedData() {
  144. if (this.multiple) {
  145. // 多选
  146. if (this.checkedKeys.length > 0) {
  147. this.checkSelectedNodes(this.checkedKeys);
  148. } else {
  149. this.clearSelectedNodes();
  150. }
  151. } else {
  152. // 单选
  153. if (this.checkedKeys.length > 0) {
  154. this.checkSelectedNode(this.checkedKeys);
  155. } else {
  156. this.clearSelectedNode();
  157. }
  158. }
  159. },
  160. popoverHide() {
  161. if (this.multiple) {
  162. this.checkedIds = this.$refs.tree.getCheckedKeys(); // 所有被选中的节点的 key 所组成的数组数据
  163. this.checkedData = this.$refs.tree.getCheckedNodes(); // 所有被选中的节点所组成的数组数据
  164. } else {
  165. this.checkedIds = this.$refs.tree.getCurrentKey();
  166. this.checkedData = this.$refs.tree.getCurrentNode();
  167. }
  168. this.$emit("popoverHide", this.checkedIds, this.checkedData);
  169. },
  170. // 单选,节点被点击时的回调,返回被点击的节点数据
  171. handleNodeClick(data, node) {
  172. if (!this.multiple) {
  173. this.setSelectOption(node);
  174. this.isShowSelect = !this.isShowSelect;
  175. this.$emit("change", this.selectedData);
  176. }
  177. },
  178. // 多选,节点勾选状态发生变化时的回调
  179. handleCheckChange() {
  180. var checkedKeys = this.$refs.tree.getCheckedKeys(); // 所有被选中的节点的 key 所组成的数组数据
  181. this.options = checkedKeys.map(item => {
  182. var node = this.$refs.tree.getNode(item); // 所有被选中的节点对应的node
  183. let tmpMap = {};
  184. tmpMap.value = node.key;
  185. tmpMap.label = node.label;
  186. return tmpMap;
  187. });
  188. this.selectedData = this.options.map(item => {
  189. return item.value;
  190. });
  191. this.$emit("change", this.selectedData);
  192. },
  193. // 多选,删除任一select选项的回调
  194. removeSelectedNodes(val) {
  195. this.$refs.tree.setChecked(val, false);
  196. var node = this.$refs.tree.getNode(val);
  197. if (!this.checkStrictly && node.childNodes.length > 0) {
  198. this.treeToList(node).map(item => {
  199. if (item.childNodes.length <= 0) {
  200. this.$refs.tree.setChecked(item, false);
  201. }
  202. });
  203. this.handleCheckChange();
  204. }
  205. this.$emit("change", this.selectedData);
  206. },
  207. treeToList(tree) {
  208. var queen = [];
  209. var out = [];
  210. queen = queen.concat(tree);
  211. while (queen.length) {
  212. var first = queen.shift();
  213. if (first.childNodes) {
  214. queen = queen.concat(first.childNodes);
  215. }
  216. out.push(first);
  217. }
  218. return out;
  219. },
  220. // 单选,清空select输入框的回调
  221. removeSelectedNode() {
  222. this.clearSelectedNode();
  223. this.$emit("change", this.selectedData);
  224. },
  225. // 选中的select选项改变的回调
  226. changeSelectedNodes(selectedData) {
  227. // 多选,清空select输入框时,清除树勾选
  228. if (this.multiple && selectedData.length <= 0) {
  229. this.clearSelectedNodes();
  230. }
  231. this.$emit("change", this.selectedData);
  232. }
  233. },
  234. watch: {
  235. isShowSelect() {
  236. // 隐藏select自带的下拉框
  237. this.$refs.select.blur();
  238. }
  239. }
  240. };
  241. </script>
  242. <style>
  243. .mask {
  244. width: 100%;
  245. height: 100%;
  246. position: fixed;
  247. top: 0;
  248. left: 0;
  249. opacity: 0;
  250. z-index: 11;
  251. }
  252. .common-tree {
  253. overflow: auto;
  254. }
  255. .tree-select {
  256. z-index: 111;
  257. }
  258. </style>