告別龐大 PSD,輕鬆測量尺寸
起因
作為前端工程師,日常開發離不開 psd 檔案。
但是日常開發的一個小彈窗頁面,它的 psd 居然需要 30+Mb,所以經常得定期清理 psd...
對於我一個 PS 小菜雞來說,用 PSD 無非只是需要用來度量元素大小(元素間距),檢視屬性等簡單的功能。
思考,對比
相對比於 sketch,sketch 具有 sketch-measure,設計師匯出成靜態資源給前端即可。
對於 PSD 來說,市面上已經有如 pxcook / lanhuapp,體驗也很不錯,但是需要下載 U 同學提供的 (龐大的) psd 才能進行標註體驗。
而且有時候還是需要 U 同學給(龐大的) PSD 檔案,我們才能在 pxcook / lanhuapp 中自動標註。
於是鑑於以上,考慮做一個開源專案,類似於 sketch-measure, 定位為 psd-measure。
效果展示
命令列
我們也可以使用命令列來匯出頁面標註
bash
npm i measure-export-cli -g
# 開啟服務,線上預覽 `path/to/psdDir` 下的 psd
measure-export start path/to/psdDir
# 構建 `path/to/psdDir` 下的 psd 至 `dist` 檔案目錄
measure-export build path/to/psdDir
Chrome 外掛
提供 Chrome 外掛,當我們點選 psd 連結時候跳出 Measure UI,而不是下載 PSD,當然我們也可以點選右上方的下載進行下載。
安裝
- 下載擴充套件,點選下載
- 開啟 Chrome 擴充套件頁面: chrome://extensions/
- 拖拽下載的包至頁面中進行安裝
- 出現該圖標表示安裝完成
設計與實現
流程如下:
PSD 檔案格式介紹
- File Header(定長) 主要包括這個 psd 檔案整體的資料,如版本,尺寸大小,圖片通道數,使用的顏色類別(rgb、cmyk...)
- Color Mode Data Section(變長) 主要是部分顏色型別圖片需要用到
- Image Resources(變長) 放置一些外部的圖片資源
- Layer and Mask(變長) 放置圖層和蒙層的各種資訊,大小位置,字型,描邊等等
- Image Data(變長) 放置影象畫素資料
PSD.js
使用 psd.js 便是解析上述檔案結構,得到可讀的資料結構。其中 psd.js 使用 getter 得到懶解析資料,即如下程式碼:
const obj = Object.defineProperty({}, 'someParsedVal', {
get: function () {
if (!this._someParsedVal) {
const afterMs = Date.now() + 3000
while (true) {
if (Date.now() >= afterMs) {
this._someParsedVal = 'ok'
break
}
}
}
return this._someParsedVal
}
})
obj.someParsedVal // 3s 後出來
obj.someParsedVal // 很快
在 mobx3 中也有類似的設計(LazyInitializer)
psd-html
將 PSD 解析為 HAST,進而轉換為 HTML
HAST (HTML 抽象語法樹)
如下 html:
<a href="http://alpha.com" class="bravo" download></a>
對應 HAST 為
{
"type": "element",
"tagName": "a",
"properties": {
"href": "http://alpha.com",
"id": "bravo",
"className": ["bravo"],
"download": true
},
"children": []
}
前後端同構
前後端同構的意思:同時執行在客戶端和服務端,具體便是同時執行在瀏覽器環境和 nodejs 環境
實現前後端同構的一些常用方式,藉助構建工具 browserify / rollup / webpack 來分別打包不同環境的 js
模擬環境
- 在 browser 環境,則將預設的 built-in modules 打包進去,以及一些 global 變數(如
process.env / __dirname
)也會進行 mock
利用 變數替換 + treeshake 區分不同環境的程式碼
-
如 webpack 配置
DefinePlugin
{ plugins: [ new webpack.DefinePlugin({ 'process.env.RUN_ENV': JSON.stringify('browser') }) ] }
-
在程式碼中對不同環境打包進行區分
module.exports = process.env.RUN_ENV === 'browser' ? { psdToHtml, psdToHtmlFromBuffer, psdToHtmlFromURL, psdToHAST, psdToHASTFromBuffer } : { psdToHtml, psdToHtmlFromPath, psdToHtmlFromBuffer, psdToHAST, psdToHASTFromBuffer, psdToHASTFromPath }
- 最終打包出來的 js 則會剔除掉
psdToHASTFromPath
相關程式碼
package.json
配置
如下:
{
"main": "dist/psd-html.cjs.js",
"browser": "dist/psd-html.browser.cjs.js",
"cdn": "dist/psd-html.browser.umd.min.js",
"unpkg": "dist/psd-html.browser.umd.min.js"
}
-
main
: nodejs 環境載入的 js -
browser
: browser 環境載入的 js -
cdn
: 部分 cdn 服務載入的 js -
unpkg
: unpkg cdn 服務載入的 js (主要使用 UMD 規範打包)
html-measure 互動
佈局定位
將 psd 匯出成整個圖片,利用每一個圖層的定位和大小來自動標註。
其他
2 個 div,相對與同一個父級的絕對定位,如何判斷他們是否相交?
..........
正面直接判斷是很費力的,要考慮各種情況,這時候需要逆向思維,考慮不相交的情況。這時候就簡單了
不相交只要滿足下面四種情況之一就可以
function isIntersect(node1, node2) {
const rect1 = node1.getBoundingClientRect()
const rect2 = node2.getBoundingClientRect()
return !(
rect1.right < rect2.left ||
rect1.left > rect2.right ||
rect1.bottom < rect2.top ||
rect1.top > rect2.bottom
)
}
measure-export(-cli)
輸入 psd / html 匯出 meas-ui
靜態資源,流程如圖(區分 prod 和 dev 環境)
.svg)
Todo
- [ ] 提供 chrome 外掛:當瀏覽器開啟 psd 時候,渲染測量尺寸 UI