在低代码中平台记录sortablejs拖拽使用经验

21 篇文章 2 订阅

 只需要关注sortablejs的api方面使用,业务方面可以忽略

import Sortable from "sortablejs";
import {
  generateRawInfo,
  getSplitTag,
  findCodeElemNode,
  findRawVueInfo,
  insertPresetAttribute,
  replaceRowID,
} from "@/utils/forCode";
import { html2Json } from "@/libs/bundle-html2json-esm";
import { getRawComponentContent, getRawComponentKey } from "@/utils/common";
import { addDiyFileByDragId } from "@/utils/dragComponentUtil/index.js";
import { setAnyTable } from "@/libs/tableEditor.js";
import { setDropAfterPos } from "./move-line.js";
import { drawLine } from "@/utils/lineHelper";
import { store as _store } from "@/libs/store.js";
import { cloneDeep, uniqBy } from "lodash-es";

const handleObj = { key: "bob", entity: null, containerDom: null, vccElKey: null };
const whiteListKeys = ["el-card", "el-table"]; //含有子节点的必须提前写在这

function loopDom(childNodes) {
  childNodes.forEach((ele) => {
    let key = geVccElKey(ele);
    if (ele.nodeName.includes("#")) {
      return;
    }
    if (!key) {
      return;
    }
    if (ele.classList.contains("actionWrap")) {
      return;
    }
    Sortable.create(ele, commonOps);
    if (ele.childNodes && ele.childNodes.length) {
      loopDom(ele.childNodes);
    }
  });
}

const setData = (dataTransfer, element) => {
  const raw = generateRawInfo(element);
  const str = `${element.localName}${getSplitTag()}${
    element.innerText
  }${getSplitTag()}${0}${getSplitTag()}${element.style.cssText}${getSplitTag()}${JSON.stringify(
    raw
  )}`;
  dataTransfer.setData("text/plain", str);
};

const newMerge = (o1, o2, currentPointPositionAfterIndex = -1, fn = null) => {
  if (o1 && o2) {
    if (!o1["__children"]) {
      o1["__children"] = [];
    }
    if (currentPointPositionAfterIndex > -1) {
      o1["__children"].splice(currentPointPositionAfterIndex, 0, o2);
    } else {
      o1["__children"].push(o2);
    }
    o2.__proto__ = { parentCodeNode: o1 };
    if (fn) {
      fn();
    }
  }
};

const onEnd = async (event) => {
  const {
    originalEvent: { dataTransfer },
  } = event;
  const renderControlPanel = window.mainPanelProvider.getControlPanelRoot();
  let container = renderControlPanel.firstChild; //querySelector(`[lc_id="container"]`);
  let json = await html2Json(container.innerHTML);
  const data = dataTransfer.getData("text/plain");
  const [, , , , rawInfo] = data.split(getSplitTag());
  console.log("转换得原始数据:", json);
  if (!rawInfo || rawInfo == "undefined") {
    console.log('rawInfo == "undefined":', rawInfo);
    return;
  }
  const newDropObj = JSON.parse(rawInfo);
  console.log("newDropObj:", newDropObj);
  //判断lc_id是否是diy组件并import
  let diy_lc_id = getRawComponentContent(newDropObj).lc_id;
  addDiyFileByDragId(diy_lc_id);
  window.mainPanelProvider.removeSame(newDropObj);
  // 插入预设属性
  insertPresetAttribute(newDropObj);
  // 使新拖入的代码与原来的做脱离
  replaceRowID(newDropObj, "");
  // 更新代码结构关系
  const codeTargetElement = findCodeElemNode(window.mainPanelProvider.currentPointDropInfo.target);
  if (codeTargetElement) {
    let temp = findRawVueInfo(codeTargetElement);
    console.log("渲染容器:", getRawComponentContent(temp));
    window.mainPanelProvider.backup();

    newMerge(
      getRawComponentContent(temp),
      newDropObj,
      window.mainPanelProvider.currentPointDropInfo.index,
      () => {
        window.mainPanelProvider.sustainedMarkElement(getRawComponentContent(newDropObj).lc_id);
        window.mainPanelProvider.eventEmitter.emit("onMerged");
      }
    );

    //任意拖拽
    window.mainPanelProvider.isAnyDrag
      ? setDropAfterPos(originalEvent.clientX, originalEvent.clientY, newDropObj)
      : null;
    setAnyTable(newDropObj); //设置任意表格
    window.mainPanelProvider.render(window.mainPanelProvider._rawDataStructure);
  }
};

const onMove = (/**Event*/ event, /**Event*/ originalEvent) => {
  drawLine(event, originalEvent);
};

const isEmpty = (obj) => {
  return JSON.stringify(obj) === "{}";
};

//防止内存爆
const changeObjectToTree = (data, attr = "__children", sub = "__children", label = "label") => {
  let newArr = [];
  for (let i = 0; i < data.length; i++) {
    const key = getRawComponentKey(data[i]);
    let item = cloneDeep(data[i][key]);
    let oldInfo = cloneDeep(data[i][key]);
    if (item) {
      newArr[i] = {
        [key]: {
          ...item,
          [sub]: [],
        },
      };
      if (oldInfo[attr] && oldInfo[attr].length) {
        newArr[i][key][sub] = changeObjectToTree(oldInfo[attr], attr, sub);
      }
    }
  }
  return newArr;
};

const isChildrenEmpty = (lcidObj, parentLc_id) => {
  for (const key in lcidObj) {
    const obj = lcidObj[key];
    if (!obj) {
      return;
    }
    // debugger;
    if (!obj || !obj.children || isEmpty(obj.children)) {
      lcidObj[parentLc_id] = null;
    } else {
      //debugger;
      let k = Object.keys(obj.children)[0];
      let o1 = obj.children[k];
      let k1 = Object.keys(o1)[0];

      isChildrenEmpty(o1, k1);
    }
  }
};

//白名单key
const whiteListKeyFn = (obj) => {
  let key = getRawComponentKey(tree[obj.lc_id]);
  let isClear = whiteListKeys.some((k) => {
    return k === key;
  });

  isClear ? null : (obj.__children = []);
};

const setLcidChildren = (objC, template, treeObjC = null) => {
  for (let lc_id in objC) {
    let obj = objC[lc_id];
    let treeObj = tree[lc_id];
    let o1 = getRawComponentContent(treeObj);
    whiteListKeyFn(o1);
    if (treeObjC) {
      treeObjC.__children.push(treeObj);
    } else {
      template.push(treeObj);
    }
    if (obj && obj.children && !isEmpty(obj.children)) {
      for (let num in obj.children) {
        let lcidObj = obj.children[num];
        setLcidChildren(lcidObj, template, o1);
      }
    }
  }
};

//获取最新模板
const getTemplate = (lcidObj, template, treeObj = null) => {
  for (let num in lcidObj) {
    let obj = lcidObj[num];
    setLcidChildren(obj, template, treeObj);
  }
};

const getLcids = (children, lcidObj, parentLc_id = null, parentIndex = null) => {
  //debugger;
  children.length &&
    children.forEach((dom, index) => {
      //debugger;
      if (dom.classList.contains("actionWrap")) {
        return;
      }
      let lc_id = dom.getAttribute("lc_id");
      if (lc_id) {
        // debugger;
        if (parentLc_id) {
          if (dom.children && dom.children.length) {
            let obj = {};
            obj[lc_id] = { children: {} };
            if (!lcidObj[parentLc_id] || isEmpty(lcidObj[parentLc_id])) {
              lcidObj[parentLc_id] = { children: {} };
            }
            lcidObj[parentLc_id].children[index] = obj;
            let childrendoms = [].slice.call(dom.children);
            getLcids(childrendoms, lcidObj[parentLc_id].children[index], lc_id, index);
          } else {
            //debugger;
            let obj = {};
            obj[lc_id] = null;
            let parentChild = lcidObj[parentLc_id].children;
            let parentChildLen = Object.keys(parentChild).length;
            parentChild[parentChildLen] = obj;
            console.log("parentChildLen:", parentChildLen);
            console.log("parentChild:", parentChild);
          }
        } else {
          if (dom.children && dom.children.length) {
            let obj = {};
            obj[lc_id] = { children: {} };
            lcidObj[index] = obj;
            let childrendoms = [].slice.call(dom.children);
            getLcids(childrendoms, lcidObj[index], lc_id, index);
          } else {
            let obj = {};
            obj[lc_id] = null;
            lcidObj[index] = obj;
          }
        }
      } else {
        isChildrenEmpty(lcidObj, parentLc_id);
      }
    });
};

const geVccElKey = (target) => {
  try {
    const __rawVueInfo__ = window.tree[target.attributes.lc_id.nodeValue];
    const key = getRawComponentKey(__rawVueInfo__);
    return key;
  } catch (error) {
    return null;
  }
};

export const leftOps = {
  animation: 200,
  group: { name: "group", put: false, pull: "clone" },
  sort: false,
  easing: "cubic-bezier(1, 0, 0, 1)",
  chosenClass: "mark-element-unit",
  setData,
  onStart: function (event) {
    _store.commit("setIsDrop", false);
  },
};

export const commonOps = {
  animation: 200,
  handle: ".copyIcon", //必须搭配draggable属性才会生效喔
  draggable: ".mark-element",
  group: {
    name: "group",
    /*
    因为用了filter属性,根据你自己的需求注释掉
    put: () => {
      if (handleObj.vccElKey != "div") {
        return true;
      }
      return false;
    },
    pull: () => {
      if (!handleObj.vccElKey) {
        return false;
      }
      return true;
    },*/
  },
  filter: (evt, target) => {
    let key = geVccElKey(target);
    if (key) {
      return false;
    }
    return true;
  },
  easing: "cubic-bezier(1, 0, 0, 1)",
  setData,
  onStart: function (event) {
    window.mainPanelProvider.backup();
    const { item } = event;
    let key = geVccElKey(item);
    handleObj.vccElKey = key;

    _store.commit("setIsDrop", true);
  },
  onEnd: async function (event) {
    if (!handleObj.vccElKey) {
      return;
    }

    /*let lcidObj = {
      0: {
        "42qryko5ba": {
          children: {
            0: {
              kdc7rq479g: null,
            },
          },
        },
      },
      1: {
        "2fdjr1n7w2": {
          children: {
            0: {
              "8jdoyxe938": null,
            },
          },
        },
      },
      2: {
        w9tr5ojf1f: {
          children: {
            0: {
              wriaw2ggwp: {
                children: {
                  0: {
                    kdc7rq479g: null,
                  },
                },
              },
            },
          },
        },
      },
      3: {
        kdc7rq479g: null,
      },
    };*/
    let lcidObj = {};
    let template = [];

    const renderControlPanel = window.mainPanelProvider.getControlPanelRoot();
    let wrapdom = renderControlPanel.firstChild;
    let wrapdoms = [].slice.call(wrapdom.children);
    getLcids(wrapdoms, lcidObj);
    getTemplate(lcidObj, template);
    let temp = changeObjectToTree(template);
    console.log("顺序", lcidObj);
    console.log("模板", template);
    console.log("最终模板", temp);

    setTimeout(() => {
      window.tree.container.div.__children = temp;
      let cloneR = window.tree.root; //cloneDeep(window.tree.root);
      let obj0 = cloneR.template.__children[0];
      obj0.div.__children = temp;
      window.mainPanelProvider.render(cloneR);
    }, 0);
  },
};

export default function sortableInit() {
  handleObj.containerDom = document.querySelector(`[lc_id="container"]`);
  handleObj.entity = Sortable.create(handleObj.containerDom, commonOps);
  loopDom(handleObj.containerDom.childNodes);
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值