# filter-condition **Repository Path**: chejf/filter-condition ## Basic Information - **Project Name**: filter-condition - **Description**: 使用vue2开发的或且逻辑组件 - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2024-03-29 - **Last Updated**: 2024-08-11 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # 组件入口 /render/index.vue ``` render(h){ const that = this; if (that.renderData.length === 0) { // 初始化 // renderData 为空 (mixin(useTree) --> renderData) return h( "div", { class: "cnc-ui____condition-empty-box", on: { click(e) { e.stopPropagation(); // mixins(useTree) --> addRootItem() // 添加根节点 that.addRootItem(); }, }, }, [ h( "el-button", { props: { type: "text", disabled: that.disabled, }, }, ["新增"] ), ] ); } } ``` # 添加祖先节点 点击`新增`按钮会调用mixin(useTree)中的`addRootItem`方法,创建祖先节点,并向外抛出`afterAddRootNode` 事件(可获取当前树节点以及添加的节点) ``` // /render/useTree.js addRootItem(newItem) { if (!this.disabled && this.renderData.length === 0) { // 初始化 祖先节点 // { // root: true, // id: nanoid(), // type: "string_dim", // value: undefined, // children: [], // oper: "", // parentId: "", // index: 0, // level: 0, // } const rootFilter = getDefaultTreeItem(newItem); this.renderData.push(rootFilter); // 抛出 -> 添加祖先节点之后的事件 // renderData 整个树节点 // rootFilter 当前添加的节点 this.$emit("afterAddRootNode", this.renderData, rootFilter); } } ``` # 根据添加的祖先节点渲染业务组件 `renderData`数据发生变化,会触发组件入口中render函数的执行 依次调用 1. `that.renderFilter(h, that.renderData)` 2. `this.eachItemFilter(h, d, index, data.length)` ``` renderFilter(h, data) { return data.map((d, index) => { return this.eachItemFilter(h, d, index, data.length); }); } ``` ``` eachItemFilter(h, item, index, length) { return h("div", { class: "cnc-ui____condition-box", key: item.id }, [ h("div", { class: "cnc-ui____condition-left-box" }, [ this.getLeftContentRender(h, item), ]), h("div", { class: "cnc-ui____condition-right-box" }, [ // 有children 则递归调用eachItemFilter this.getRightContentRender(h, item.children), ]), // 绘制竖线 this.getEachLine(h, index, length, item.root), // 绘制操作区域左侧水平线 !item.root && h("div", { class: "cnc-ui____condition-horizontal-line-box" }), ]); } ``` # 业务组件渲染逻辑 入口:`getLeftContentRender` - `cnc-ui____condition-slot-box` 组件功能区域:在`SlotRender`中渲染下拉框和输入框 - 当前元素有children,则会渲染“且”和“或”条件选择组件 - 无children,则会渲染下拉框和输入框 操作按钮区域:新增、一分为二、删除 - 新增操作`pushNewTreeItem` - ``` export function pushNewTreeItem(item, newItem) { item.parent.children.splice(item.index + 1, 0, { ...(newItem ?? {}), id: nanoid(), type: newItem?.type ?? "string_dim", value: newItem?.value, oper: newItem?.oper ?? "", parentId: item.parent.id, parent: item.parent, children: [], index: item.index + 1, level: item.level, root: false, operation: newItem?.operation, }); // 重新生成元素索引index resortChild(item.parent.children); } ``` - 一分为二操作,生成当前点击节点的兄弟节点`forkNewBranch` ``` export function forkNewBranch(item, newItem) { // 当前点击的那个节点 const firstChild = forkItemToChildren(item); item.children = [ firstChild, // 和新增单个节点的数据结构一致 { ...(newItem ?? {}), id: nanoid(), type: newItem?.type ?? "string_dim", value: newItem?.value, oper: newItem?.oper ?? "", parentId: item.id, parent: item, children: [], index: 1, level: item.level + 1, root: false, operation: newItem?.operation, }, ]; } ``` - 删除操作`deleteItem` ``` deleteItem(item) { if (!item.parent) { // 没有parent属性 清空树 this.renderData = []; } else { removeTreeItem(item, this.renderData); } this.$emit("afterDelete", this.renderData, item); } ``` # 节点连线逻辑 入口:`getEachLine` 竖线分为最上面的竖线、最下面的竖线、其余位置的竖线 - 最上面的竖线,top从当前元素中间到最下面 ``` #{$prefix}first-line-box { position: absolute; width: 1px; top: 50%; bottom: 0; left: -10px; background-color: #4e6dc2; } ``` - 最下面的竖线,top从0到当前元素的中间 ``` #{$prefix}last-line-box { position: absolute; width: 1px; top: 0; bottom: 50%; left: -10px; background-color: #4e6dc2; } ``` - 其余的竖线,top从0到当前元素的最下面 ``` #{$prefix}middle-line-box { position: absolute; width: 1px; top: 0; bottom: 0; left: -10px; background-color: #4e6dc2; } ``` 每个子元素都有一个水平向左的横线 ``` #{$prefix}horizontal-line-box { position: absolute; height: 1px; top: 50%; left: -10px; width: 10px; background-color: #4e6dc2; } ```