随手写系列--react-sortablejs速成一个可视化编辑表单结构

1,781 阅读2分钟

随便抽了点时间用react-sortablejs构造了可视化编辑表单:

基本能力:

1.组件拖拽到画布

2.同级拖拽

3.跨级拖拽

4.无限容器嵌套

--临时写了一下,利用input类型组件搭建了一个骨架

流程: create-react-app demo

npm i -D react-sortablejs

替换app.js app.css文件即可

npm run start

image.png

import React, { useEffect, useState } from "react";
import { ReactSortable } from "react-sortablejs";
import './App.css'

const BasicFunction = () => {
  const [operateCom, setOperateCom] = useState([
    { id: 1, name: "input", value: 213 },
    { id: 2, name: "input", value: 23 },
    { id: 3, name: "input", value: 61 },
    { id: 4, name: "input", value: 67 },
    {
      id: 5, name: "container", children: []
    }
  ]);
  const [container, setContainer] = useState([]);
  //储存全局key--方便拿到最大的key进行构造最新的key
  const [keyArr,setKeyArr]=useState([]);

  useEffect(() => {
    console.log(container, 'stated');
  }, [container])

  const renderContainer = (childNode, parentCHild) => {
    return (
      <ReactSortable
        className="ReactSortableChild"
        group={{ name: 'formItem', pull: true, put: true }}
        list={childNode.children} setList={(...args) => {
          //需要构造递增id,新拖入的组件的id必须比数组里面的最大的,进行加1
          //id不能数组下标的递增id,所以需要构造一些固定特殊字符再加上递增数字,
          //后面新增id只需改变递增数组那部分即可
          let max_id = 0
          keyArr.map(id => {
            let pos = id.slice(3)
            if (Number(pos) > max_id) {
              max_id = pos
            }
          })
          let new_id = 'key' + (++max_id)//初始时候
          let new_container = JSON.parse(JSON.stringify(args[0]))
          //需要找出哪些是新的--这里可以判断id是否函数经过处理的固定字符,没有就是新增的
          new_container.map(item => {
            if (typeof item.id === 'number' || !item.id.includes('key')) {
              item.id = new_id
            }
          })
          childNode.children = new_container
          setKeyArr([...keyArr,new_id])
        }}
      >
        {childNode.children.map((item, index) => (
          <div key={item.id}>
            {
              item.name == 'container' ? (
                renderContainer(item,childNode.children)
              ) : (
                <item.name defaultValue={item.value} onInput={e => {
                  childNode.children[index].value = e.target.value
                }} />
              )

            }
          </div>
        ))}
      </ReactSortable>
    )
  }

  return (
    <div className="App">
      <div className="componentArea">
        <ReactSortable
          className="ReactSortable"
          group={{ name: 'formItem', pull: 'clone', put: false }}
          list={operateCom} setList={setOperateCom}
        >
          {operateCom.map((item) => (
            <div key={item.id}>
              {
                item.name == 'container' ? (
                  <div style={{ minHeight: '100px', background: '#fff', padding: '12px' }}>子容器</div>
                ) : (<item.name defaultValue={item.value} onChange={e => {
                  let temp = operateCom
                  temp.map(itemc => {
                    if (itemc.id == item.id) {
                      itemc.value = e.target.value
                    }
                  })
                  setOperateCom(temp)
                }} />
                )
              }
            </div>
          ))}
        </ReactSortable>
      </div>
      <div className="drawArea">
        <ReactSortable
          className="ReactSortable"
          group={{ name: 'formItem' }}
          onAdd={(...args)=>{
            console.log(args,'-------');
          }}
          list={container} setList={(...args) => {
            console.log(args);
            //需要构造递增id,新拖入的组件的id必须比数组里面的最大的,进行加1
            //id不能数组下标的递增id,所以需要构造一些固定特殊字符再加上递增数字,
            //后面新增id只需改变递增数组那部分即可
            let max_id = 0
            keyArr.map(id => {
              let pos = id.slice(3)
              if (Number(pos) > max_id) {
                max_id = pos
              }
            })
            let new_id = 'key' + (++max_id)//初始时候
            let new_container = JSON.parse(JSON.stringify(args[0]))
            //需要找出哪些是新的--这里可以判断id是否函数经过处理的固定字符,没有就是新增的
            new_container.map(item => {
              if (typeof item.id === 'number' || !item.id.includes('key')) {
                item.id = new_id
              }
            })
            setKeyArr([...keyArr,new_id])
            setContainer(new_container)
          }}
        >
          {container.map((item, index) => (
            <div key={item.id}>
              {
                item.name == 'container' ? (
                  renderContainer(item,container)
                ) : (
                  <item.name defaultValue={item.value} onChange={e => {
                    container[index].value = e.target.value
                  }} />
                )

              }
            </div>
          ))}
        </ReactSortable>
      </div>
    </div>
  );
};
export default BasicFunction
.componentArea{
  width: 400px;
  min-height: 400px;
  background-color: aliceblue;
  margin: 24px;
  
}
.componentArea .ReactSortable{
  min-height: 400px;
  padding: 12px;
}
.drawArea{
  width: 400px;
  min-height: 400px;
  margin: 24px;
  background-color: black;
}
.drawArea .ReactSortable{
  min-height: 400px;
  padding: 12px;
}
.ReactSortableChild{
  min-height: 100px;
  padding: 12px;
  border: 1px solid red;
  background-color: #fff;
}