开源了,有代码管理的地方,服务端搬到了阿里云,数据库在腾讯云...。启用了GZIP压缩,打包也坑,一个Echarts 2.8M(CDN了)
elementui的下拉树很常用,一搜一大把,随便找了一个抄的,学习了一下改了改,多选还没试过
<template> <div> <div class="mask" v-show="isShowSelect" @click="isShowSelect = !isShowSelect" ></div> <el-popover placement="bottom-start" :width="width" trigger="manual" v-model="isShowSelect" @hide="popoverHide" > <el-tree class="common-tree" :style="style" ref="tree" :data="TreeData" :props="defaultProps" :show-checkbox="multiple" :node-key="idKey" :check-strictly="checkStrictly" default-expand-all :expand-on-click-node="false" :check-on-click-node="multiple" :highlight-current="true" @node-click="handleNodeClick" @check-change="handleCheckChange" > </el-tree> <el-select :style="selectStyle" slot="reference" ref="select" :size="size" :value="selectedData" :multiple="multiple" :clearable="clearable" :collapse-tags="collapseTags" @click.native="isShowSelect = !isShowSelect" @remove-tag="removeSelectedNodes" @clear="removeSelectedNode" @change="changeSelectedNodes" class="tree-select" v-bind="$attrs" > <el-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value" > </el-option> </el-select> </el-popover> </div> </template> <script> import { isArray, isArrayEmpty } from "@/utils/validate"; export default { name: "select-tree", props: { // 树结构数据 data: { type: Array, default() { return []; } }, defaultProps: { type: Object, default() { return { children: "children", label: "text" }; } }, // 配置是否可多选 multiple: { type: Boolean, default() { return false; } }, // 配置是否可清空选择 clearable: { type: Boolean, default() { return false; } }, // 配置多选时是否将选中值按文字的形式展示 collapseTags: { type: Boolean, default() { return false; } }, idKey: { type: String, default() { return "id"; } }, nameKey: String, pIdKey: String, // 显示复选框情况下,是否严格遵循父子不互相关联 checkStrictly: { type: Boolean, default() { return false; } }, size: { type: String, default() { return "small"; } }, width: { type: String, default() { return "250px"; } }, height: { type: Number, default() { return 300; } }, selectedVal: { type: [String, Number, Array], default() { return ""; } } }, data() { return { isShowSelect: false, // 是否显示树状选择器 options: [], selectedData: "", // 选中的节点 style: "height:" + this.height + "px;", selectStyle: `width:calc(${this.width});`, checkedIds: [], checkedData: [] }; }, mounted() { this.initCheckedData(); }, methods: { // 单选时点击tree节点,设置select选项 setSelectOption(node) { let tmpMap = {}; tmpMap.value = node.key; tmpMap.label = node.label; this.options = []; this.options.push(tmpMap); this.$nextTick(() => { this.selectedData = node.key; }); }, // 单选,选中传进来的节点 checkSelectedNode(checkedKeys) { var item = checkedKeys[0]; this.$refs.tree.setCurrentKey(item); var node = this.$refs.tree.getNode(item.toString()); if (node) { this.setSelectOption(node); } }, // 多选,勾选上传进来的节点 checkSelectedNodes(checkedKeys) { this.$refs.tree.setCheckedKeys(checkedKeys); }, // 单选,清空选中 clearSelectedNode() { this.selectedData = ""; this.$refs.tree.setCurrentKey(null); }, // 多选,清空所有勾选 clearSelectedNodes() { var checkedKeys = this.$refs.tree.getCheckedKeys(); // 所有被选中的节点的 key 所组成的数组数据 for (let i = 0; i < checkedKeys.length; i++) { this.$refs.tree.setChecked(checkedKeys[i], false); } }, initCheckedData() { if (this.multiple) { // 多选 if (!isArrayEmpty(this.checkedKeys)) { this.checkSelectedNodes(this.checkedKeys); } else { this.clearSelectedNodes(); } } else { // 单选 if (!isArrayEmpty(this.checkedKeys)) { this.checkSelectedNode(this.checkedKeys); } else { this.clearSelectedNode(); } } }, popoverHide() { if (this.multiple) { this.checkedIds = this.$refs.tree.getCheckedKeys(); // 所有被选中的节点的 key 所组成的数组数据 this.checkedData = this.$refs.tree.getCheckedNodes(); // 所有被选中的节点所组成的数组数据 } else { this.checkedIds = this.$refs.tree.getCurrentKey(); this.checkedData = this.$refs.tree.getCurrentNode(); } this.$emit("popoverHide", this.checkedIds, this.checkedData); }, // 单选,节点被点击时的回调,返回被点击的节点数据 handleNodeClick(data, node) { if (!this.multiple) { this.setSelectOption(node); this.isShowSelect = !this.isShowSelect; // this.$nextTick(()=>{}) this.$emit("change", node.key); } }, // 多选,节点勾选状态发生变化时的回调 handleCheckChange() { var checkedKeys = this.$refs.tree.getCheckedKeys(); // 所有被选中的节点的 key 所组成的数组数据 this.options = checkedKeys.map(item => { var node = this.$refs.tree.getNode(item); // 所有被选中的节点对应的node let tmpMap = {}; tmpMap.value = node.key; tmpMap.label = node.label; return tmpMap; }); this.selectedData = this.options.map(item => { return item.value; }); this.$emit("change", this.selectedData); }, // 多选,删除任一select选项的回调 removeSelectedNodes(val) { this.$refs.tree.setChecked(val, false); var node = this.$refs.tree.getNode(val); if (!this.checkStrictly && node.childNodes.length > 0) { this.treeToList(node).map(item => { if (item.childNodes.length <= 0) { this.$refs.tree.setChecked(item, false); } }); this.handleCheckChange(); } this.$emit("change", this.selectedData); }, treeToList(tree) { var queen = []; var out = []; queen = queen.concat(tree); while (queen.length) { var first = queen.shift(); if (first.childNodes) { queen = queen.concat(first.childNodes); } out.push(first); } return out; }, // 单选,清空select输入框的回调 removeSelectedNode() { this.clearSelectedNode(); this.$emit("change", this.selectedData); }, // 选中的select选项改变的回调 changeSelectedNodes(selectedData) { // 多选,清空select输入框时,清除树勾选 if (this.multiple && selectedData.length <= 0) { this.clearSelectedNodes(); } this.$emit("change", this.selectedData); } }, model: { prop: "selectedVal", event: "change" }, computed: { //组装Treedata TreeData() { if (this.data.length == 0) { return []; } let { data, idKey, pIdKey, nameKey } = this; if (!pIdKey) { return this.data; } let _treedata = []; // id: 1,label: '一级 1', children: [{ let getChildren = item => { let thisc = data.search({ [pIdKey]: item[idKey] }); thisc.forEach(thisc_item => { thisc_item.children = getChildren(thisc_item); }); return thisc; }; //得到子菜单 data.forEach(item => { //是否有子 let c = data.search({ [pIdKey]: item[idKey] }); if (c.length != 0) { item.children = getChildren(item); _treedata.push(item); } }); this.$nextTick(() => { this.initCheckedData(); }); return _treedata; }, checkedKeys() { let val = this.selectedVal; if (!val) { return []; } if (!isArray(val)) { val = [val]; } return val; } }, watch: { isShowSelect(val) { //如果是显示 先判断禁用状态 if (val && this.$refs.select.$children[0].disabled) { this.isShowSelect = false; } // 隐藏select自带的下拉框 this.$refs.select.blur(); }, checkedKeys(val) { if (!val) { return; } if (!isArray(val)) { val = [val]; } // this.checkedKeys = val; this.initCheckedData(); }, nameKey: { handler(newName, oldName) { this.defaultProps.label = newName; }, immediate: true }, width: { handler(newName, oldName) { this.$nextTick(() => { this.$refs.tree.$el.style.width = this.$refs.select.$el.offsetWidth - 24 + "px"; }); }, immediate: true } } }; </script> <style scoped> .mask { width: 100%; height: 100%; position: fixed; top: 0; left: 0; opacity: 0; z-index: 11; } .common-tree { overflow: auto; } .tree-select { z-index: 111; } </style>
使用
<el-form-item label="所在部门" prop="System_1_170"> <select-tree :disabled="treedisabled" v-model="form.System_1_170" width="100%" :data="sys2Data" idKey="System_2_10" pIdKey="System_2_70" nameKey="System_2_30" ></select-tree> </el-form-item>
弹出框也常用,编辑表单啥的,也单出来了,需求是表单外面不想套还得复制粘贴,还得写参数控制显示关闭,我既然表单是组件了,那我调用方法,调用指定组件给我弹出来就行了,这里没有选择动态子组件或者插槽,因为当时不会
两层,一个是组件,一个是方法
<template> <el-dialog :title="title" :visible.sync="dialogVisible" :close-on-click-modal="false" :close-on-press-escape="false" > <div ref="component" id="component"></div> </el-dialog> </template> <script> import Vue from "vue"; export default { data: () => ({ component: null, title: "编辑", dialogVisible: false, options: {}, instance: {} }), mounted() {}, watch: {}, methods: { show(opt) { this.dialogVisible = true; //把Dialog自己作为参数传过去 let data = Object.assign(this.instance, opt, { thisDialog: this }); this.$nextTick(() => { //绘制内部组件 const component = Vue.extend(this.component); this.instance = new component({ el: "#component", data: { ...data } }); }); return this; }, close() { this.dialogVisible = false; } } }; </script> <style></style>
外面再包一层
/** * @description 打开一个window * @param {Object} com 组件 * @param {String} title 标题 * @param {Object} data 参数 */ export const window = function(com, title, data = {}) { if (!com) { return; } const component = Vue.extend(windowComponent); let option = Object.assign( { component: com }, { title }, { options: { ...data } } ); // console.log(option); let instance = new component({ el: document.createElement("div"), data: option }); this.$el.appendChild(instance.$el); return instance; };
使用
//打开页面 sys10edit(item) { this.getsys10edit().show({ form: { ...item } }); }, //打开角色编辑 getsys10edit() { let edit = this.$window(sys10Edit, "编辑角色"); edit.$on("onSys10Save", (res, data) => { res.MsRbool && this.getsys10data(); }); return edit; },
<script> import { System10 } from "@/api"; export default { data() { return { form: {}, thisDialog: {} }; }, //外部属性 props: {}, //内部方法 methods: { initPage() {}, //关闭 close() { this.thisDialog.close(); }, //保存 async onSave() { let res = await System10.Save(this.form); res.strMS && this.$message(res.strMS); this.thisDialog.$emit("onSys10Save", res, this.form); res.MsRbool && this.close(); } }, //组件 components: {}, //初始化 异步加async await mounted() { this.initPage(); }, //计算属性 computed: {}, //监视 watch: {} }; </script>
本文作者:没想好
本文链接:
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!