一個較為完備的 antd 視覺化編輯器實現

小芋頭君發表於2019-04-20

此專案是上古專案,程式碼基本很難維護,現在釋出出來僅供參考思路,感興趣的可以根據原理重構一版,實現一個更完備的視覺化編輯

友情提醒:不建議在團隊內投入大量精力做類似的事情(企圖一步到位改變開發現狀),與行業裡用 AI 切頁面類似,儘量作為玩具把玩一下即可。

Github 地址:github.com/xinyu198736…

線上例項

xinyu198736.github.io/antd-visual…

託管在 github,第一次載入會比較慢

截圖:

一個較為完備的 antd 視覺化編輯器實現

執行

npm run build;
npm run start;
# 因為我不太懂 webpack ,不太會配置,這個專案修改程式碼後實時生效還有問題。。求 pr
複製程式碼

特性

  • 視覺化編輯,同時實時生成結果程式碼,還可以單獨預覽
  • 豐富的資料編輯能力,可以編輯元件的二維屬性
  • 元件可巢狀
  • 自適應佈局
  • 除了 antd 的元件,還有一些原生 html 元素可使用

原理解析

1.如何實現實時編輯

第一步,抽象整個視覺化工作臺的資料表達,無非是放了一個什麼元件在什麼位置,這個元件的父元件是誰,這個元件的屬性是什麼

如下圖:

一個較為完備的 antd 視覺化編輯器實現

一個元件的基礎定義:

title 元件名
type  元件型別(元件真實類名)
can_place 元件是否可以包含子元件
children 元件的子元件,陣列型別
is_native 元件是否是原生 html 元素
config  元件可用的配置資訊
props 元件配置資訊的值,包含樣式和屬性等
複製程式碼

根據這些值,我們就可以渲染和編輯元件了,編輯元件後, 會有一個大的表示畫布當前狀態的資料結構儲存到 state 中, 另外,有一個方法可以根據這個資料結構渲染出整個畫布, 所以每次有任何編輯動作之後,我們會觸發 forceUpdate,重新繪製畫布 也就是說,新增元件,編輯屬性,和畫布的顯示是分離的,中間由一個大的資料結構連線(就是圖片裡這個)

2.如何反向生成 react 程式碼

根據上圖中的資料結構,反向遍歷,可輕易的生成 React 程式碼

3.如何定義元件可用的配置

在 pages/coms/xxx 裡面定義一個元件的可用配置,然後即可在主介面中選擇元件後在右側"屬性編輯區"中編輯屬性。

來看看我們可以定義哪些屬性吧

以一個按鈕為例

export default {
    "type": "Button",
    "title": "按鈕",
    "props": {
        type: 'primary',  // 定義可以配置的 props
        content: '按鈕一隻', // 定義可以配置的 props
        style: {  // 定義可以配置的樣式
            margin: "0px 10px 0px 0px"
        }
    },
    config: {   // 可用的配置項
        type: {   // type 這個配置的描述
            text: "主題",  // 配置的標題
            enum: [       // 可用的列舉,配置時會顯示成下拉框
                'primary',
                'default',
                'dashed',
                'danger'
            ]
        },
        icon: {
            text: "圖示",
        },
        content: {
            text: '文案',
        },
        style: {  // 可用的樣式配置
            width: {  
                text: "寬度",
            },
            margin: {
                text: "外邊距",
                type: "4-value" // 一種定製型別,會渲染成 4 個輸入框
            }
        }
    },
}
複製程式碼

這是最基本的配置項,只能適用於最基本的元件,但是遇到像 table 或者 Breadcrumb 這種元件就不行了

4.高階配置(二維資料)

以 Breadcrumb 為例,他有一個資料來源的屬性,資料來源是一個陣列+物件的混合表達,這種元件不少,應該如何定義呢

export default {
  "type":"Breadcrumb",
  "title":"麵包屑",
  props:{
      routes:[  // 這裡是資料來源的屬性,和預設值
      {
          breadcrumbName:"一級目錄",
          path:"#",
        key:1
      },
      {
          breadcrumbName:"二級目錄",
          path:"#",
        key:2
      }
    ]
  },
  config:{
      routes:{   // 如何表達這個屬性應該如何配置
          text:"專案配置",
          enumobject:[{  // 一種新的型別,enumobject,物件列舉
            key:1,  
            dataIndex:"breadcrumbName",  // 列舉的物件的第一個 key 是什麼
            title:"顯示文字",    // 列舉的物件的第一個 key 的文字描述
            type:'String',      // 列舉的物件的第一個 key 的型別
          },{
            key:2,
            dataIndex:"path",    // 列舉的物件的第二個 key 是什麼
            title:"連結",        // 列舉的物件的第二個 key 的文字描述
            type:'String',      //列舉的物件的第二個 key 的型別
          }]
    }
  }
}
複製程式碼

最終的屬性編輯區:

一個較為完備的 antd 視覺化編輯器實現

即可邊界物件列舉屬性

5.更復雜的元件

大家會發現,table 這種元件和上述的元件都不太一樣,首先看純資料表格

一個較為完備的 antd 視覺化編輯器實現

其實這裡還好,只是 table 有兩個屬性,一個表達列的資料,一個表達行的資料,我們只需要兩個物件列舉即可

{
    config:{
        columns:{
          text:"列管理",
          enumobject:[
            {
              title: '列文字',
              dataIndex: 'title',
              type:"String"
            },
            {
              title: '列key',
              dataIndex: 'dataIndex',
              type:"String"
            }
          ]
        },
        dataSource:{
          text:"值管理",
          enumobject:{
            type:'relative_props_object',
            target:'columns'
          }
        }
    }
}
複製程式碼

這裡實現了一個 關聯,可以把 dataSource 的配置和 columns 關聯起來 (relative_props_object)

6.更更復雜的表格

如果只是資料,還好, 但是 table 裡可以還可以巢狀其他元件,每行每列,想想是不是頭疼。。如下圖

一個較為完備的 antd 視覺化編輯器實現

table 的每個 column 其實可以定義內部顯示的元素,我們在預設值裡就給他塞一個空的 layout 進去, 這樣之後這裡就會變成一個可以放置其他子元素的坑,具體不展開了,這裡的邏輯比較複雜。

未完待續,或者直接看程式碼。。

相關文章