一、什麼是資料看闆,資料看闆有什麼用
在解釋資料看闆概念之前,我們要先知道,什麼是資料可視化。
資料可視化被許多學科視為與視覺傳達含義相同的現代概念。它涉及到資料的可視化表示的建立和研究。 為了清晰有效地傳遞資訊,資料可視化使用統計圖形、圖表、資訊圖表和其他工具。可以使用點、線或條對數字資料進行編碼,以便在視覺上傳達定量資訊。 有效的可視化可以幫助使用者分析和推理資料和證據。它使複雜的資料更容易了解和使用。 - 維基百科
資料看闆即是資料可視化的載體,通過合理的頁面布局、效果設計來将可視化資料更好的展現。
個人認為,資料看闆的作用大緻為以下兩種:
1、掌握情況
通過資料呈現,決策者們能較為清晰的掌握自己産品的營運情況。
2、問題解決
通過資料分析,能夠通過資料可視化,從動态資料中提煉出規律,發現不符合預期的部分并給出修改意見。
二、配置檔案資料結構設計
假設有如下這樣的一個看闆頁面,讓你用一份json檔案來記錄元件的資訊,類似,寬高、位置以及标題等等,試想一下你會怎麼設計 json 的資料結構(可以不用關心具體的值是什麼)。
這個問題并不是很難,相信大部分人都能設計一份自己的資料結構,比如我設計的結構就是下面這樣:
[
{
"type": 'line', // 類型
"id": 1, // 唯一辨別
"data": [], // 資料存放
"title": "貨物銷售情況", // 元件标題
"layout": { x: 0, y: 0, w: 3, h: 2 }, // 頁面布局資訊(坐标、寬高)
},
{
"type": 'bar',
"id": 2,
"data": [],
"title": "貨物留存情況",
"layout": { i: 'c', x: 3, y: 0, w: 3, h: 2 },
}
]
複制代碼
有了這樣一份資料結構之後,接下來,我們接下來就要開發元件,比如{type:line}的配置項就去用line元件渲染,并且我們需要把資料還有一些其他配置項傳給元件。關于每個元件的開發,這裡就不深入探讨了,需要考慮的就是你的内部元件要具有接受資料并處理配置的能力。
三、元件容器
現在元件有了,配置也有了,接下來就很簡單了,根元件直接循環周遊下,就可以了,代碼如下:
<div>
{widgets.map(widget => {
const WidgetComp = getWidgetComp(widget.type);
return <WidgetComp config={widget} key={widget.id} />
})}
</div>
複制代碼
好了,大功告成,頁面渲染完成!
先别着急,我們想想看,是不是每個元件,我們都需要去做同樣的工作,比如資料請求、布局處理等等。
這時候,我們就需要在一個統一的地方去做這些同樣且重複的工作。這裡我想到了兩種方式:
1、公共的 util 函數。
2、給所有元件增加一層包裹容器。
第一種方法雖然可以滿足我們的要求,但是還是存在局限性,那就是當我們想要在 dom 上做一些處理的時候,還是不可避免的會有重複代碼量,比如給元件添加點選事件、設定 dom 的 style 屬性等。
我個人比較推薦第二種方法,也就是元件容器。一個元件容器大概長這樣:
constWidget = ({config}) => {
// 元件點選事件consthandleClick=() => {/**/};
// 布局處理
consthandleLayout=() => {/**/};
// 擷取元件資料
constgetWidgetData=() => {/**/};
// 其他的一些公共邏輯
.......
constWidgetComp = getWidgetComp(widget.type);
return (
return<WidgetCompconfig={widget} />
)
}
複制代碼
對應的根元件代碼可以改成這樣:
<div>
{widgets.map(widget => <Widgetconfig={widget}key={widget.id} />)}
</div>複制代碼
四、配置檔案的編輯
上面的工作做完之後,我們可以做一個簡單的渲染了,但是既然是搭建系統,怎麼可能僅僅滿足于渲染呢?接下來,我們要考慮下,給搭建的使用者提供一個可以修改配置的地方。為了統一口徑,我們把使用配置的地方,稱使用者側,修改配置的地方,稱編輯側。
一個編輯側可能長這樣:
大緻分為三個區域,元件商店、展示區域和配置區域,這裡我們先說右側的元件配置區域。
我們這裡拿 line 元件 舉例。假設,現在産品小姐姐給你提了第一個需求,需要這個line元件支援修改名稱。so easy!直接寫個 form 表單:
<Form form={form}>
<Item name="name" label="名稱" rules={[{ required: true, message: '請輸入' }]}>
<Input placeholder="請輸入" />
</Item>
</Form>
複制代碼
修改完之後,直接把新的名稱發給後端存起來就完事了。
一天後,産品小姐姐又提了另一個需求,bar 元件需要支援修改寬度。沒辦法,接着改,不能讓産品小姐姐看不起!于是你的代碼可能變成了這樣:
constrenderForm = ({type}) => {
if(type === 'line') {
return (
<Itemname="name"label="名稱"rules={[{required:true, message: '請輸入' }]}>
<Inputplaceholder="請輸入" />
</Item>
)
} elseif(type === 'bar') {
return (
<Itemname="width"label="寬度"rules={[{required:true, message: '請輸入' }]}>
<Inputplaceholder="請輸入" />
</Item>
)
}
}
return (<Formform={form}>
{renderForm()}
</Form>)
複制代碼
緊接着,産品小姐姐的需求與日增多,元件數量也越來越龐大,你的 if else 越寫越多....。是以我們需要一個統一的修改器,和一個統一的描述元件配置的 schema 檔案。
先說元件的 schema 檔案,每一個元件都佩帶一個 schema 檔案,schema 裡主要記錄目前元件支援修改的配置項(fields),和目前元件配置項的預設值(models)。類似這樣:
{
"fields": [{
"label": "名稱",
"type": "input",
"name": "name"
}],
"models": {
"name": "預設名稱"
}
}
複制代碼
當點選一個元件的編輯按鈕時,根據元件類型擷取到對應的 schema 檔案,将元件配置項預設值 models 和從後端拿到的資料,做一個 merge,将 merge 後的資料和fieds傳給修改器。
修改器要做的工作就是,根據 fileds 動态渲染表單,關于表單動态渲染,我們團隊有一篇不錯的文章《表單資料形式配置化設計》,大家有興趣可以參考下。
總結下編輯側的工作,第一步,拿到對應元件的 schema 檔案,傳給修改器。第二步,修改器根據 fileds 動态渲染表單,并根據後端傳回資料和 schema 中的預設資料,用做表單回顯。最後就是,搭建使用者修改配置項,再把修改後的資料發送給後端儲存。
五、從遠端元件商店加載元件
以上已經完成了配置的産出、使用和修改。接下來我們再思考思考元件。我們現在的元件都是存在本地的,後期随着元件數量的增多,頁面js檔案肯定會越來越大,即使你使用了代碼分割,也不可避免會導緻build後的包體積越來越大。
是以我們需要一個遠端存放元件的地方,也就是元件商店。
那麼商店既然是遠端的,那把這個商店建在哪裡呢?我們團隊的解決方案就是,把每個元件打上版本号上傳到靜态伺服器上這樣,版本号的作用這裡先不管,這樣不管在編輯側還是使用者側,我們可以根據項目的配置資料遠端加載元件,關于遠端元件的加載方案,可以參考下我們團隊另一篇寫的不錯的文章《淺談低代碼平台遠端元件加載方案》。
當然,一個元件商店不僅于此,我們目前隻實作了一些基本功能,一個完整的元件商店功能包括:
- 元件線上編輯(上傳)子產品。
- 元件稽核子產品。
- 元件更新/釋出子產品。
- 元件管理(上架/下架/删除/下載下傳/版本)。
六、靜态化
現在我們在編輯側修改送出,使用者側就能實時的得到修改後的配置了,對應的頁面重新整理就會變化。
可是這樣會導緻一個問題,假設以前的老版本 v1.0 需要修改到新版本 v2.0,并且工作量很大,需要兩天才能完成,那麼你第一天隻能改一半,第二天早上你準備改另一半的時候,可能你們公司的投訴電話已經被打爆了,因為,你的客戶早上打開頁面的時候,是你第一天隻改了一半配置的頁面。
怎麼解決這個問題呢?答案是增加一個釋出操作,隻有釋出過後,你修改的配置才會在使用者側生效。
但是這樣還是會有問題,假設你在項目 B 修改了一個元件,該元件在項目A也用到了,那一旦該元件引發了 bug,項目 A,項目 B 都發出問題,如果是十幾個項目,那就會引起十幾個項目的問題。
基于此,我們需要思考一種方法,針對釋出過後的項目,即使對應元件有修改,也不會影響到它們,我們團隊使用的解決方案就是元件靜态化。
大緻思路就是,釋出時,首先擷取對應的項目配置,根據項目配置擷取元件清單。然後根據清單,擷取遠端元件商店的 js 檔案,将擷取到的 js 檔案插入到對應的 html 模版中。最後,将拼裝好的 html 放到靜态伺服器上。
這樣,後續使用者側隻需要通路靜态伺服器上的 html 就可以了,即使元件也修改,已釋出的項目隻要不重新釋出,就不會影響已經釋出的項目。
Tips: 進一步的話,我們可以把項目配置也做成靜态化,這樣,第一可以省去後端同學同步兩份不同環境資料的工作量,但對于前端來說,就是順手的事。第二,友善前端自己管理已釋出的配置資料。
但是如果元件修改,後續已釋出的項目也需要重新釋出呢?怎麼盡量減少釋出風險呢?這個就需要做元件的版本管理和容器的版本管理了。
七、元件和容器的版本管理
前面我們在介紹元件商店的時候說到,上傳元件的時候,我們給對應元件打上了版本号,後續元件有修改的時候,修改過的元件,會被打上新的版本号。這樣,針對已釋出的項目,隻要不更新對應元件的版本号,便不會影響對應的項目元件了。
那為什麼要做容器的版本管理呢?前面我們介紹了元件容器的作用就是處理元件的通用邏輯,如果說元件的修改有可能會影響到其他項目,那麼元件容器的修改就是一定會影響到其他項目。是以容器的版本管理比元件的版本管理更加重要。思路其實跟元件差不多,我們可以把容器了解成一個特殊的元件,跟元件不同的是,這個元件不在配置檔案解析出來的元件清單中。
八、元件之間的通信
在真實的搭建場景中,避免不了的就是,元件之間需要通信,比如,點選元件 A,元件 B 需要做出對應的響應。我們在這裡借鑒的是【釋出-訂閱】。
我們設計一個事件排程中心,可以處理所有的事件注冊與事件響應。訂閱者釋出對應的事件,事件排程中心負責将事件放入事件池中。釋出者負責在對應的時機觸發對應事件,上面例子中,元件 A 就是釋出者,當元件 A 被點選的時候,就是觸發事件的對應時機。事件在排程中心出發後,再将結果回報給訂閱者。訂閱者拿到回報結果做出行為。
關于事件的配置描述的資料結構,形式有很多種,這裡貼一份我們目前項目中使用的資料結構:
exportdefault {
publish:[ // 事件釋出
{
name: "電子賣場預警釋出/流程/onChange", // 釋出事件名
reflectName: "onChange"// 什麼行為觸發該事件
}
],
subscribe: [ // 事件訂閱
{
list: ["電子賣場預警釋出/onChange"], // 訂閱的事件集合
action: "setClass", // 事件行為,就是你訂閱的事件被觸發後,你要幹什麼
handler: "function parse(params) {↵ return {};↵ }"// 結合事件行為與該事件的傳回值,元件做出自身行為
}
]
}
作者:政采雲前端團隊
連結: https://juejin.cn/post/7197433202171854885