文章篇幅較長琳彩,慎入
隨著網(wǎng)絡(luò)應(yīng)用的豐富和發(fā)展,網(wǎng)站往往不能迅速跟進(jìn)大量信息衍生及業(yè)務(wù)模式變革的腳步,常常需要花費(fèi)許多時(shí)間脱衙、人力和物力來處理信息更新和維護(hù)工作。 ——引自「百科」
小公司例驹、小網(wǎng)站因人員捐韩、技術(shù)問題,在內(nèi)容管理處理上處于「食之無味棄之可惜」的一種情況:內(nèi)容維護(hù)會(huì)經(jīng)常打亂開發(fā)人員節(jié)奏鹃锈,但是又沒有精力去思考投入統(tǒng)一去解決類似問題荤胁。
有哪些運(yùn)營內(nèi)容需要維護(hù)
開始之前,我們先看下小網(wǎng)站一般會(huì)存在哪些內(nèi)容需要維護(hù)配置:
- 頁面靜態(tài)內(nèi)容屎债,一般用于導(dǎo)流或者介紹:如輪播圖仅政,特色垢油、功能、產(chǎn)品介紹等圆丹;
- 全站統(tǒng)一內(nèi)容:如導(dǎo)航滩愁、友情鏈接等;
- 站點(diǎn)新聞公告:包含列表辫封、詳情硝枉;
- 其他類似的靜態(tài)文檔,用來展示或者介紹公司相關(guān):如幫助秸讹、關(guān)于我們等檀咙;
- 其余無業(yè)務(wù)功能邏輯,需要人工維護(hù)的內(nèi)容
現(xiàn)狀
遇到這些內(nèi)容維護(hù)璃诀,好的小公司可能會(huì)一開始就同步建立一個(gè)配置發(fā)布管理功能弧可,其他的可能因?yàn)楣て谮s就代碼寫死,通過發(fā)布解決劣欢,發(fā)布頻繁了才去做配置發(fā)布管理功能棕诵。
- 頁面代碼寫死,調(diào)整即發(fā)布
抓狂
- 每類內(nèi)容都配套「配置發(fā)布管理功能」凿将,需要處理以下內(nèi)容
- 抽象數(shù)據(jù)校套,創(chuàng)建表
- 前端開發(fā)相關(guān)管理頁面,包含「列表」牧抵、「新增編輯」笛匙、「表單」功能
- 因?yàn)槭呛笈_(tái)管理頁面,一般情況這個(gè)配置頁面都比較簡單犀变,甚至缺少校驗(yàn)妹孙,只能人肉在線查看效果來決定是否配置正確
作為一個(gè)有追求的攻城獅,這樣的重復(fù)性工作應(yīng)該主動(dòng)拒絕获枝,通過工具或者流程去改善生活
CMS是什么
在很早以前蠢正,內(nèi)容管理就成為一個(gè)重要的應(yīng)用領(lǐng)域,并且伴隨著時(shí)間省店、技術(shù)的推移嚣崭,CMS的功能也變得越來越強(qiáng)大。
CMS簡單來說就是內(nèi)容管理系統(tǒng)(Content Management System)懦傍,主要解決用戶網(wǎng)站建設(shè)與信息發(fā)布中常見的問題和需求雹舀,運(yùn)營同學(xué)可以通過它進(jìn)行網(wǎng)站內(nèi)容新增、修改谎脯、審核發(fā)布葱跋,提高信息發(fā)布效率和準(zhǔn)確性;其技術(shù)核心思想是分離內(nèi)容的管理和設(shè)計(jì)。
業(yè)界CMS系統(tǒng)
篇幅原因娱俺,這里并不想去對(duì)比和介紹業(yè)界相關(guān)的系統(tǒng)稍味,只是想大概介紹下相關(guān)類型
- 傳統(tǒng)CMS系統(tǒng)
- 簡單的小至類似上面提到的「配置發(fā)布管理功能」,如公告發(fā)布模塊
- 可視化建站荠卷,如
- 云鳳蝶:可以基于組件可視化搭建頁面模庐,站點(diǎn)托管在云鳳蝶提供的服務(wù)。
- 阿里內(nèi)部CMS系統(tǒng):也是基于組件可視化搭建頁面油宜,天貓掂碱、淘寶成千上萬的活動(dòng)頁面都是基于此運(yùn)營自己選擇相關(guān)組件搭建并投放的;
不對(duì)外
從小公司的訴求和運(yùn)營的專業(yè)水平來看慎冤,類似云鳳蝶這樣的基于組件化搭建頁面的CMS平臺(tái)疼燥,其操作成本高,另外組件開發(fā)蚁堤、維護(hù)成本也很高醉者,小公司也很難有業(yè)務(wù)發(fā)展需求,可以沉淀出自己的組件模塊披诗。所以除非一開始就不打算投入網(wǎng)站服務(wù)建設(shè)撬即,只是簡單得搭個(gè)網(wǎng)站門面,才會(huì)使用類似可視化建站服務(wù)呈队。
下面的篇幅我們還是以實(shí)現(xiàn)「?jìng)鹘y(tǒng)CMS系統(tǒng)」為目標(biāo)剥槐,去考慮如何做得更好
訴求
那么小網(wǎng)站對(duì)內(nèi)容管理又有哪些訴求呢?
- 有一套通用解決方案可以為任意運(yùn)營內(nèi)容快速生成「配置發(fā)布管理頁面」
- 表單頁面強(qiáng)化校驗(yàn)宪摧,增加體驗(yàn)
- 盡可能保證內(nèi)容填寫的正確性粒竖,避免線上出現(xiàn)問題
- 統(tǒng)一的數(shù)據(jù)獲取API,避免重復(fù)開發(fā)
- 上篇文章提到的jsonschema-form-vue - 自動(dòng)生成表單庫几于,就能快速生成體驗(yàn)一致的表單温圆;
- 通過抽象將內(nèi)容表設(shè)計(jì)成一套統(tǒng)一結(jié)構(gòu),一方面避免每種配置都建表孩革,另一方面也容易提供統(tǒng)一API;
- 關(guān)于正確性保障得运,可以通過 預(yù)覽 -> 審核發(fā)布流程 提前保障膝蜈;
不過雖然保證了內(nèi)容配置管理,但是文章一開始提到的「新聞公共」熔掺、「幫助」饱搏、「關(guān)于我們」這些內(nèi)容相似、字段一致的頁面置逻,難道每次都要?jiǎng)?chuàng)建類似的配置管理推沸,然后在web應(yīng)用創(chuàng)建相關(guān)頁面,再發(fā)布應(yīng)用嗎?
- 需要提供一套頁面模板機(jī)制鬓催,通過復(fù)制頁面模板肺素,快速復(fù)制同類型頁面以及跟它關(guān)聯(lián)的內(nèi)容配置;通過這種關(guān)聯(lián)關(guān)系宇驾,應(yīng)用只要通過路由
pageId
去查詢頁面相關(guān)的內(nèi)容倍靡,即可避免發(fā)布
目標(biāo)
基于訴求,先明確解決小網(wǎng)站內(nèi)容管理需要完成的目標(biāo)
- 內(nèi)容管理:減少內(nèi)容運(yùn)營成本
- 減少內(nèi)容的維護(hù)成本
- 減少應(yīng)用發(fā)布成本
- 通過配置化自動(dòng)生成「配置表單」课舍,減少開發(fā)投入成本
- jsonschema-form-vue
- 可基于頁面模板快速復(fù)制塌西、新增頁面
- 保證發(fā)布質(zhì)量、體驗(yàn)
- 支持預(yù)覽筝尾、審核發(fā)布捡需、回滾
- 支持可視化編輯
- 成本小
- 能容易和現(xiàn)有系統(tǒng)結(jié)合
- 考慮投入產(chǎn)出比
分層關(guān)系和表設(shè)計(jì)
通過內(nèi)容,對(duì)數(shù)據(jù)模型進(jìn)行抽象筹淫,主要分成以下三層:
組件
最底層組件站辉,它包含了基于 jsonschema-form-vue的表單相關(guān)配置,可以使用版本管理贸街,讓配置升級(jí)更安全庵寞。
{
id: Schema.Types.ObjectId,
name: String, // 配置名稱
version: String, // 版本號(hào)
jsonSchema: String, // JSONSchema
definition: String, // Form Definition
histories: Array, // 歷史記錄
author: String, // 用戶
createdAt: Date, // 創(chuàng)建時(shí)間
modifiedAt: Date // 修改時(shí)間
}
模塊
模塊是運(yùn)營內(nèi)容編輯單元,基于組件表單配置去生成表單薛匪,可以保存草稿和發(fā)布數(shù)據(jù)捐川,用于預(yù)覽和線上內(nèi)容
{
id: Schema.Types.ObjectId,
name: String, // 模塊名稱
title: String, // 模塊標(biāo)題
siteId: Schema.Types.ObjectId, // 所屬站點(diǎn)ID
pageId: Schema.Types.ObjectId, // 頁面ID
componentId: Schema.Types.ObjectId, // 組件ID
componentVersion: String, // 組件版本號(hào)
model: {}, // 配置數(shù)據(jù)
draft: {}, // 配置草稿
status: Number, // 狀態(tài) 0: 配置更新, 1: 內(nèi)容更新, 2: 發(fā)布審核
online: Boolean,
histories: Array, // 歷史記錄
author: String, // 用戶
createdAt: Date, // 創(chuàng)建時(shí)間
modifiedAt: Date // 修改時(shí)間
}
為什么不把表單配置直接放模塊,而是增加組件這一層逸尖? 這主要是因?yàn)槟K和組件是「多對(duì)一」的關(guān)系古沥,一個(gè)表單配置可能會(huì)被用到多個(gè)模塊;另外上面提到的相似頁面娇跟,會(huì)復(fù)制出相似模塊岩齿,如果將表單配置放在模塊表中,會(huì)存在重復(fù)數(shù)據(jù)苞俘,后續(xù)也很難同步配置升級(jí)
頁面
頁面就是瀏覽器中看到頁面盹沈,主要用來保存模塊的關(guān)聯(lián)關(guān)系,一個(gè)頁面可能存在多個(gè)獨(dú)立模塊
{
id: Schema.Types.ObjectId,
name: String, // 頁面名稱
url: String, // 頁面url
realUrl: String, // 頁面實(shí)際url
useRoute: Boolean, // 是否啟用路由規(guī)則
router: String, // 路由規(guī)則
siteId: Schema.Types.ObjectId, // 所屬站點(diǎn)ID
modules: String, // 模塊
owner: String, // 用戶
createdAt: Date, // 創(chuàng)建時(shí)間
modifiedAt: Date // 修改時(shí)間
}
為什么有url又有實(shí)際url吃谣?這主要考慮后面的「可視化編輯」功能乞封,需要去請(qǐng)求真實(shí)頁面,所以在頁面復(fù)制發(fā)布時(shí)岗憋,需要基于「頁面路由」生成實(shí)際url
因?yàn)閿?shù)據(jù)模型的核心是配置和內(nèi)容肃晚,所以選用了文檔型數(shù)據(jù)庫
MongoDB
整體設(shè)計(jì)
抽象了數(shù)據(jù)模型,先通過設(shè)計(jì)看下CMS需要提供哪些功能
設(shè)計(jì)上仔戈,CMS遵循以下幾點(diǎn)原則:
- 對(duì)現(xiàn)有web應(yīng)用侵入性关串、影響最小拧廊,方便接入
- 操作簡單,盡量設(shè)計(jì)簡單晋修,功能明確
- CMS只提供數(shù)據(jù)服務(wù)吧碾,不允許用戶流量直接進(jìn)入,導(dǎo)致需要跟web應(yīng)用同步擴(kuò)容
所以:
- 提供組件飞蚓、模塊滤港、頁面管理功能;
- 提供API讓接入方可以方便獲取數(shù)據(jù)趴拧,但是接入方需要對(duì)數(shù)據(jù)進(jìn)行緩存溅漾,減小對(duì)CMS服務(wù)的壓力;
- 支持獲取草稿數(shù)據(jù)著榴,讓web應(yīng)用支持預(yù)覽功能添履;
- 提供可視化編輯功能,頁面編輯可以可視化預(yù)覽編輯線上頁面脑又,實(shí)時(shí)查看效果暮胧,方面查找模塊;
Web應(yīng)用接入只要改動(dòng)以下幾點(diǎn):
- 如果之前沒有數(shù)據(jù)问麸、結(jié)構(gòu)分離往衷,要先分離,數(shù)據(jù)源替換成CMS數(shù)據(jù)严卖;
- 線上數(shù)據(jù)要進(jìn)行緩存席舍,減少CMS服務(wù)壓力;在服務(wù)啟動(dòng)時(shí)讀取CMS內(nèi)容數(shù)據(jù)哮笆,進(jìn)行緩存来颤;
- 提供方法讓Controller可以獲取CMS數(shù)據(jù);
- 可選擇支持預(yù)覽功能稠肘,如定義url規(guī)則
?preview=true
則實(shí)時(shí)請(qǐng)求CMS草稿數(shù)據(jù)福铅; - 提供緩存更新API,在CMS內(nèi)容審核發(fā)布更新時(shí)项阴,能更新緩存滑黔,不用重啟應(yīng)用;
- 可選擇接入「可視化編輯腳本」环揽,在使用CMS數(shù)據(jù)的html模塊進(jìn)行
moduleId
標(biāo)識(shí)
流程
通過流程可以更清楚了解CMS的功能
- 創(chuàng)建組件配置
前端在本地開發(fā)完靜態(tài)頁面后拷沸,先mock內(nèi)容,完成數(shù)據(jù)模板分離薯演;然后可以借助JSON2JSONSchema工具快速生成JSONSchema結(jié)構(gòu),根據(jù) jsonschema-form-vue文檔秧了,生成組件配置
創(chuàng)建內(nèi)容模塊跨扮,引用相應(yīng)的組件配置(內(nèi)容模塊才是運(yùn)營內(nèi)容維護(hù)單元);如果有初始數(shù)據(jù),可以幫運(yùn)營填入衡创;復(fù)制
moduleId
到web應(yīng)用中調(diào)用相應(yīng)方法獲取CMS數(shù)據(jù)帝嗡;然后,發(fā)布web應(yīng)用后璃氢,開發(fā)的工作就完成了哟玷,以后的內(nèi)容維護(hù)都交由運(yùn)營同學(xué)。運(yùn)營同學(xué)維護(hù)模塊內(nèi)容一也,有兩種方式:
3.1 通過模塊名查找模塊進(jìn)行編輯
3.2 通過頁面編輯進(jìn)行可視化編輯巢寡,見下面內(nèi)容編輯確認(rèn)無誤后,進(jìn)行保存預(yù)覽
預(yù)覽確認(rèn)沒有問題后椰苟,審核發(fā)布抑月,內(nèi)容上線
到這里,CMS最基本的功能已經(jīng)完成了舆蝴;再也不用因?yàn)槲陌竷?nèi)容改動(dòng)谦絮,需要進(jìn)行應(yīng)用發(fā)布重啟了
MORE
接下來的篇幅最后介紹「頁面復(fù)制」和「可視化編輯」功能
關(guān)于頁面復(fù)制
上文提到的新聞公告、關(guān)于我們洁仗,或者一些風(fēng)格類似的活動(dòng)頁面层皱,需要提供快捷復(fù)制創(chuàng)建新頁面,然后修改頁面內(nèi)容即可赠潦。
主要思考如下:
- 模塊才是內(nèi)容編輯單元叫胖,頁面維護(hù)著模塊映射關(guān)系,復(fù)制頁面的同時(shí)復(fù)制相應(yīng)模塊祭椰,并更新對(duì)應(yīng)的映射關(guān)系即可臭家;
- 提供通過
pageId
獲取數(shù)據(jù)接口,這樣類似頁面可以通過路由規(guī)則params或query
來獲取對(duì)應(yīng)頁面數(shù)據(jù)渲染方淤;
可視化編輯
最后必須來點(diǎn)看起來科技感滿滿的功能來個(gè)收尾钉赁,以提供該CMS系統(tǒng)的檔次,直接跟前沿接軌携茂。
在具備了模塊編輯功能后你踩,可視化編輯就是如何獲取編輯的數(shù)據(jù)并實(shí)時(shí)渲染頁面預(yù)覽,同時(shí)預(yù)覽頁面可識(shí)別可編輯模塊讳苦,并表現(xiàn)出自己能被編輯带膜,引起運(yùn)營點(diǎn)擊修改的欲望:
- 關(guān)于實(shí)時(shí)預(yù)覽
上文我們已經(jīng)提到預(yù)覽功能,實(shí)時(shí)預(yù)覽問題不攻而破 - 關(guān)于可編輯模塊
要想識(shí)別模塊并編輯鸳谜,必須在HTML Template上標(biāo)識(shí)上moduleId
膝藕,然后通過規(guī)則識(shí)別在CMS系統(tǒng)中引入「可視化編輯.js」,CMS在編輯時(shí)通過iframe引入線上頁面咐扭,做以下事情:- 識(shí)別頁面可編輯模塊芭挽,在上面遮上一層編輯DIV滑废,表現(xiàn)出可編輯樣子
- 點(diǎn)擊編輯DIV時(shí),iframe通信袜爪,告知CMS編輯模塊蠕趁,彈出模塊配置
- 編輯保存后,更新iframe時(shí)間戳辛馆,重新請(qǐng)求頁面俺陋,獲取新數(shù)據(jù)
就這樣,馬上提供一個(gè)檔次
到這里昙篙,文章就結(jié)束了腊状,在工作過程中,多去發(fā)現(xiàn)工作流程中瓢对,重復(fù)性的莫湘、自己不喜歡去處理但又不得不去處理的活兒峻贮,去思考如何通過工具、流程化去處理它們;讓事情變得簡單陪蜻、可復(fù)制纳猪;這個(gè)思考和實(shí)現(xiàn)的過程址愿,不僅能提升你的設(shè)計(jì)和技術(shù)能力谭企,同時(shí)也能增加公司對(duì)你的依賴性,走向升職加薪的路上埃仪。