摘要:如何設計高擴展的在線網頁制作平臺本文主要介紹如何設計一個高擴展的在線網頁制作平臺,會交代一些背景和最終的效果以及核心設計方案。市面上可使用的一些在線制作推廣平臺制作的頁面又不能很好地結合到自己的業務流程里面。
如何設計高擴展的在線網頁制作平臺
本文主要介紹如何設計一個高擴展的在線網頁制作平臺,會交代一些背景和最終的效果以及核心設計方案。體驗地址: https://godspen.ymm56.com
官網官網: https://godspen.ymm56.com/
開源代碼: https://github.com/ymm-tech/g...
使用手冊: https://godspen.ymm56.com/doc...
在線體驗: https://godspen.ymm56.com/adm...
私有部署: https://godspen.ymm56.com/doc...
組件動畫展示運營活動對一些簡單的動畫提供支持,方便做一些入場和出場的動畫,提升活動的交互感,我們使用了 animate.css 提供的一套css動畫。下面提供簡單的展示
合成組件就是選擇已有的節點保存為一個通用的組件,方便下次直接使用
使用組合組件
導出組合組件。
模板頁面頁面模板的目的和組合組件類似,都是提供已經做好的內容,運營快速選擇使用達到快速上線活動的目的,下面是簡單演示
2018年3月份開始,隨著運滿滿的快速發展,開始在頻繁的迭代各種活動,那時最快的方式就是拷貝老的活動項目,然后按需求修改,接著上線,然而這種方式很快就遇到了瓶頸,迫使運營團隊也會去尋找一些第三方平臺去滿足自己的運營要求,不過由于定制化弱和用戶信息沒打通導致沒辦法大量使用,還是只能等待前端資源排期,兩個比較突出的問題。
產品每個活動都需要前端人員介入,甚至替換一個簡單的圖標和簡單的布局,都需要排期等待,吃掉了50%的前端資源。
市面上可使用的一些在線制作推廣平臺制作的頁面又不能很好地結合到自己的業務流程里面。
轉盤抽獎,如果使用第三方平臺需要在活動結束后把抽獎名單導出,然后導入自己的平臺里面去做匹配,然后在篩選中獎名單,很不方便。
拉新送紅包,使用第三方的平臺如果用戶提交了拉新的手機號。需要定期去同步數據然后送紅包,不能對接自己的平臺做到實時。
針對這些問題團隊迫切需要一個平臺來提供運營快速創建活動,開發也能在這平臺做一些功能擴展。最好能滿足已下幾個要求:
豐富的組件提供運營能自主創建頁面。
每個做好的頁面都可以設置為模板頁面,提供運營下次快速通過模板創建頁面簡單修改然后發布。
提供常用動畫然運營能創建炫酷效果的活動。
提供每個活動完整的數據分析方便運營查看效果,常規的pv,uv,以及自定義頁面的元素點擊打點和統計功能。
提供靈活的頁面管理,方便運營按組按項目維度給其他同事分配權限統一管理。
開發人員可以為組件植入腳本靈活擴展該活動的功能,方便運營使用。
提供統一的組件開發規范,方便開發新的業務組件為運營提供更友好的使用方式。
針對這些要求我們做了碼良平臺,碼良是一個在線H5編輯器,用于快速制作H5頁面。用戶無需掌握復雜的編程技術,通過簡單拖拽、少量配置即可制作精美的頁面,可用于營銷場景下的頁面制作。同時,也為開發者提供了完備的編程接入能力,通過腳本和組件的形式獲得強大的組件行為和交互控制能力。
下面會分享下我們的核心設計,這次主要重點說明下面幾方面內容
我們會介紹整體的架構來了解一般的編輯產生頁面的基本思路,基于數據編程。
我們會介紹核心的組件如何設計,確??梢宰杂蓴U展組件能力
我們會介紹如何設計編輯器達到可自定義屬性的控制面板
備注(由于整體項目實現使用的VUE,所以后面有部分介紹具體技術實現的時候會以VUE的使用角度說明。用其他框架的自行腦補)
整體架構
整體架構相對簡單,核心就是定義一套標準的數據規范,提供一個編輯器去編輯這個數據,同時提供一個解析器去解析該數據,然后渲染出頁面,流程如下。
數據結構
通過上面的圖看到每個頁面是由很多節點組成(node),每個節點可以嵌套子節點。而每個節點包括的基本信息如下,備注文章后續提到的 nodeInfo 都是該節點對應的如下數據
{ "id": "truck/button1l", "type": "truck/button", "label": "按鈕1l", "version": "0.1.4", "visible": true, "style": { "position": "absolute", "width": "100px", "height": "40px" }, "animate": [], "props": { "text": "輸入文字", "type": "danger", "click": [] }, "path": "https://ymm-maliang.oss-cn-hangzhou.aliyuncs.com/truck/button/0.1.4/index.js", "script": "", "events": [] }
每個組件比較核心的元素由如下幾部分組成
id 元素的唯一編號。方便代碼獲取和操作
type 組件的類型。會根據不同的類型加載不同的腳本資源,然后運行加載完的腳本會創建一個VUE Component,然后會把這個Component 掛載到VUE全局,由于每個組件節點都是一個 動態的 Component 組件。這時候只需要修改動態組件的 :is 數據進行內容替換就好了。
label 組件別名。方便運營理解使用
version 組件版本。 每個組件都是有自己的版本的。
style 組件樣式
props 組件參數。每個組件都是有一些初始化參數的,這些參數都是營銷人員在編輯器里面填寫的。這些參數就存放在這里面,在擴展編輯器屬性能力里面會詳細說明
script 擴展腳本。每個組件可以插入一些腳本代碼擴展組件的功能。這些腳本創建的對象會 mixin 到該組件對象里面,在組件設計里面會詳細介紹
event 組件綁定事件。 每個組件可以綁定常見dom事件。
child 孩子節點。
path 腳本路徑。 通過該路徑加載腳本創建組件對象。
上圖的頁面包括一個圖片,圖片下面兩個文字,圖片兄弟節點有個按鈕元素。對應頁面的詳細數據結構如下,可以感受下完整結構。
{ "id": "node", "type": "node", "visible": true, "style": { }, "props": {}, "child": [ { "id": "truck/image15j", "type": "truck/image", "label": "圖片15j", "version": "0.1.4", "visible": true, "style": { "position": "absolute", "width": "320px" }, "animate": [], "props": { "url": "https://ymm-maliang.oss-cn-hangzhou.aliyuncs.com/ymm-maliang/access/ymm_1533366999689.png", "click": [] }, "path": "https://ymm-maliang.oss-cn-hangzhou.aliyuncs.com/truck/image/0.1.4/index.js", "script": "", "events": [], "child": [ { "id": "truck/text3l", "type": "truck/text", "label": "文本3l", "version": "0.1.4", "visible": true, "style": { "position": "absolute" }, "animate": [], "props": { "text": "文字內容1", "click": [] }, "path": "https://ymm-maliang.oss-cn-hangzhou.aliyuncs.com/truck/text/0.1.4/index.js", "script": "", "events": [] }, { "id": "truck/text3l5g", "type": "truck/text", "label": "文本3l", "version": "0.1.4", "visible": true, "style": { "position": "absolute", "width": "114px" }, "animate": [], "props": { "text": "文字內容2", "click": [] }, "path": "https://ymm-maliang.oss-cn-hangzhou.aliyuncs.com/truck/text/0.1.4/index.js", "script": "", "events": [] } ] }, { "id": "truck/button1l", "type": "truck/button", "label": "按鈕1l", "version": "0.1.4", "visible": true, "style": { }, "animate": [], "props": { "text": "輸入文字", "type": "danger", "click": [] }, "path": "https://ymm-maliang.oss-cn-hangzhou.aliyuncs.com/truck/button/0.1.4/index.js", "script": "", "events": [] } ], "script": [], "animate": [], "version": "0.1.0", "events": [] }
一句話小結:頁面是由很多節點遞歸生成,每個節點包含布局,事件,腳本,參數,版本等信息,然后編輯器編輯這些信息,解析器解析這些信息。
組件設計一個頁面都是由一個個遞歸嵌套的組件組成,組件是整個項目的最核心的一部分,為了讓組件具有擴展能力,我們對組件的功能使用了 mixin 方式,通過基礎組件邏輯+自定義腳本的形式來生成組件。下面介紹下整體組件結構和初始化流程,方便理解我們是如何實現的。
上圖左部分可以看到整個頁面都是由一個一個node節點組成,他們是一個樹狀結構,每個node節點下面包含著一個組件對象做功能展示,下面是node節點的dom結構,可以看到每個節點都是遞歸節點,每個節點內部都包含一個動態組件,每個動態組件的通過nodeinfo.id為key的組件進行渲染。
上圖右部分可以看到渲染流程。為了達到組件的高擴展性,每個組件的功能包含兩個主要部分
組件代碼 ,每個組件都是有特定參數和特定功能的腳本實現,比如 圖片,富文本,分享,九宮格等組件,組件代碼通過對于的type 和 path 參數去加載對于的腳本獲取對象。
組件通過編輯器添加的腳本 , 編輯器可以為每個組件動態添加腳本來增強對組件的操作能力。如下操作,可以看到一個組件可以添加多個腳本。每個腳本其實就是一個的vue組件,終這里面的代碼會創建對象 mixin 到最終的vue組件里面,所以你可以為組件擴展各種功能進行支持你的特殊業務。
一個節點的邏輯功能=組件邏輯+腳本1+腳本2+腳本3...
每個組件在根據自己的類型加載對應js腳本后,會對該組件 nodeInfo.script 里面的 邏輯進行mixin. 然后創建一個最終的組件注冊到Vue.component 里面方便后續使用,核心代碼如下
// 通過加載到的組件腳本獲得的全局對象創建vue對象 window["image_1.0.3"] load組件腳本運行后會生成的對象 var component = Vue.extend( window["image_1.0.3"]) // 遍歷所有加入的腳本混合組件對象中 nodeInfo.script.forEach((value)=>{ component =component.extent(value) }) // 以節點id為key,注冊最終組件對象 Vue.component(nodeInfo.id,component) // 修改該節點的動態組件 :is 參數為 該節點id // done
一句話小結:通過不斷的mixin新的自定義腳本進來擴展組件能力
組件屬性編輯設計屬性編輯主要目的是開發組件的人會暴露一些可配置的參數給運營人員在編輯器里面填寫和修改。
比如選擇一個組件后再右側屬性面板可以對這個組件進行一些屬性設置.
![](https://ymm-maliang.oss-cn-hangzhou.aliyuncs.com/ymm-maliang/access/ymm_1539684410392.png)
為了便于維護和擴展,我們覺得一個組件的可配置數據包括簡單數據,復雜邏輯數據,對應可編輯屬性的部分也分為兩部分
編輯器提供基礎屬性編輯
編輯器能提供擴展編輯編輯能力,主要針對運營方便操作,特征性的開發組件屬性的編輯功能,提供對運營友好的操作體驗
下面針對這兩塊比較核心的內容說明下我們如何做的。
編輯器基礎屬性編輯能力對于一個組件的開發者來說,一是定義該組件那些參數需要暴露到編輯器讓運營操作,二是定義該屬性對應的值通過什么控件操作。
上文在整體架構數據結構中提到了每個node節點都有一個 props 屬性,該屬性就是存放著該組件可配置的參數所配置的最終值,在初始化組件的時候會把這個 props的數據傳入組件進行初始化。而定義一個組件能接受那些參數則是在每個Vue組件的props 屬性上定義, 而編輯器的作用就是通過編輯器去獲取到每個對象定義的props,然后根據每個參數的類型提供不同的編輯控件,比如 boolean 我們會提供 切換按鈕,image 我們會提供選擇圖片控件等等。擴展腳本同樣可以擴展組件的可編輯屬性,下面是一個擴展腳本的例子。主要說明支持的那些類型,可定義的格式。整體流程如下。
下面我們先看一下每個組件可定義的props 例子。
/** * * @param type: 字段類型,支持原生類型以及【碼良輸入類型】 * * 碼良輸入類型: * input 單行輸入框 * text 多行輸入框 * enum 列表單選 需提供選項字段defaultList, 支持數組、map結構 * image 圖片選擇 * audio 音頻選擇 * video 視頻選擇 * richtext 富文本 * number 數字 * function 方法設置 * data json數據 * date 時間選擇 * checkbox 多選框 同enum 不提供defaultList字段時,輸入值為布爾類型 * radio 單選框 同enum * */ return { props: { // 原生類型 foo: { type: String }, // 圖片輸入 fooImage: { type: String, editer: { type: "image" } }, // 日期 fooDate: { editer: { type: "date" } }, // checkbox 多選 fooCheckbox: { type: Array, // 此項必須為Array default: () => { // 且需提供初始值 return [] // ["day", "hour", "min", "sec"] }, editer: { label: "顯示精度", type: "checkbox", defaultList: [ // array 形式的選項 "day", "hour", "min", "sec", ] } }, // checkbox 布爾 fooCheckboxBool: { type: Boolean, // 此項必須為Boolean editer: { type: "checkbox" } }, // enum 含選項 fooEnum: { default: "value1", type: String, editer: { label: "我是字段名", // 將字段名顯示為可讀性更強的文本,不提供此項時,顯示字段名 desc: "我是幫助文本", // 為字段提供提示信息,幫助理解字段的意義 type: "enum", defaultList: { // map結構的選項 key為值,value為顯示文本 "value1": "條件1", "value2": "條件2", "value3": "條件3", } } }, // 條件屬性 ifFoo1: { type: [Number], default: 0, editer: { work: function () { return this.fooEnum == "value1" // 只有當 `fooEnum` 字段取值為 "value1" 時才顯示此項 }, label: "條件屬性1", type: "number", } }, ifFoo2: { type: [Date, String], default: null, editer: { work: function () { return this.fooEnum == "value2" // 只有當 `fooEnum` 字段取值為 "value2" 時才顯示此項 }, label: "條件屬性2", type: "date", } }, }, mounted: function () { console.log("hello " + this.foo) console.log("hello " + this.fooImage) // ... } }
上面腳本擴展的組件對應的增加的可配置的屬性如下圖。
這里面的的主要設計在于每個props屬性里面添加了一個 editer字段進行該字段在編輯器環境下提供什么組件對該屬性進行編輯。editer的字段主要包括如下。
{ label: "我是字段名", // 將字段名顯示為可讀性更強的文本,不提供此項時,顯示字段名 desc: "我是幫助文本", // 為字段提供提示信息,幫助理解字段的意義 type: "enum", ignore: true, // 不在編輯器顯示 work:function(){ // 如果滿足什么條件才會顯示 }, defaultList: { // map結構的選項 key為值,value為顯示文本 "value1": "條件1", "value2": "條件2", "value3": "條件3", } }
label 在編輯器顯示的名稱
desc 該字段在編輯器詳細描述
type 編輯該屬性的組件類型
ignore 負略在編輯器顯示,一般在該屬性提供了高級編輯模式需要隱藏掉默認的模式。
work 一個方法,該方法返回true 會在編輯器顯示該屬性,一遍用于聯動隱藏和顯示一些編輯屬性
defaultList 一些默認數據,一般提供單選,下拉等默認可選擇的值。
一句話小結:編輯器通過獲取每個組件的props,遍歷每一個屬性,按類型提供不同的操作控件,編輯生成最終的數據放到 nodeInfo.props上。
擴展編輯屬性能力很多時候一個組件可配置的屬性按我們的規劃來說就下面幾種類型。
/** * * @param type: 字段類型,支持原生類型以及【碼良輸入類型】 * * 碼良輸入類型: * input 單行輸入框 * text 多行輸入框 * enum 列表單選 需提供選項字段defaultList, 支持數組、map結構 * image 圖片選擇 * audio 音頻選擇 * video 視頻選擇 * richtext 富文本 * number 數字 * function 方法設置 * data json數據 * date 時間選擇 * checkbox 多選框 同enum 不提供defaultList字段時,輸入值為布爾類型 * radio 單選框 同enum * */
如果按每個類型提供一個基本的編輯組件就能完成90%的需求,不過在隨著組件的復雜度增加,每個組件可配置的屬性變得千奇百怪,各種需求都可能。比如一個簡單的多選,原來的可選項只能寫死,現在需要自己請求接口獲取。但這些邏輯我們不能做到統一的編輯器里面,也不能做到組件里面,所以只能在做組件的時候提供一種機制讓開發組件的同學開發組件的同時,還能對這個組件開發一個自定義的編輯器,并能整合到我們的屬性編輯面板中。
整體架構如下,最終效果可以參考上圖的自定義面板部分
一個組件打包完一般會有兩個必要的腳本,一個是組件對應的js。一個是該組件對應編輯器的腳本js。
整個平臺對編輯器的功能擴展都是相通的,通過加載腳本,創建對象,注冊到Vue,然后通過動態組件渲染。對編輯器屬性的擴展也是一樣。加載對應組件的編輯器腳本,然后按相同的方法進行植入。這里就不在細講。這里簡單分享下我們對一個組件的開發最終的結果。如下圖
組件開發過程中的界面
組件發布后在碼良編輯器里面的樣子
總結為了提供一套對運營友好,并且高擴展的h5活動制作平臺我們做了這個碼良平臺?,F在碼良的平臺現在支撐著運滿滿每天新增5-10個的新活動頁面的需求,已有活動模板的活動95% 可以營銷人員通過模板創建,做些樣式或圖片的修改,然后發布到線上,整個過程就幾分鐘。活動的模板和組件模板也在不斷沉淀,相信沉淀一段時間后隨著模板越來越全,對營銷活動的快速制作和可選擇性都會更強。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/106623.html
摘要:一個熱門視頻直播間人數可能達到幾十萬甚至上百萬人,幾十萬人發消息,幾十萬人接收,流量相當驚人,那么服務端要如何設計才能保證系統流暢本文作者將結合他在網易云信多年開發的經驗進行深度分析。網易云信至今已申請了余項專利,遠超市場同類產品。 一個熱門視頻直播間人數可能達到幾十萬甚至上百萬人,幾十萬人發消息,幾十萬人接收,流量相當驚人,那么服務端要如何設計才能保證系統流暢?本文作者將結合他在網易...
摘要:遠程醫療這一概念被提出后,已經被廣泛應用。但是,如何提高視頻傳輸性能,如何確保家庭基層醫療機構和戶外應急的遠程醫療快速接入,是當前的遠程醫療業務系統面臨的主要挑戰。 編者按:近日,Gartner最新發布了一份《Five Key Essentials for the New Generation of Intelligent Video Cloud》白皮書報告,報告中針對各行業在視頻應用...
摘要:極大地降低了平臺的復雜度,更加方便企業開發人員實現各種業務應用,幫助企業輕松打造基于云計算的軟件基礎設施。本文將從實際案例出發,結合不同的使用場景,為各位介紹的這些特性。是未來數據中心操作系統的核心。 0.前言 隨著 Docker 技術的日漸火熱,本就火爆的云計算行業進入了一個加速階段。云計算最大的特點是彈性和靈活,幫助企業應對復雜的業務需求。由于云計算的IT構架和上一代的IT構架有很...
閱讀 964·2023-04-26 02:56
閱讀 9437·2021-11-23 09:51
閱讀 1850·2021-09-26 10:14
閱讀 2980·2019-08-29 13:09
閱讀 2153·2019-08-26 13:29
閱讀 571·2019-08-26 12:02
閱讀 3562·2019-08-26 10:42
閱讀 3000·2019-08-23 18:18