微信小程序的image組件中,有一個(gè)mode屬性,其設(shè)置如下:
mode 有 13 種模式,其中 4 種是縮放模式,9 種是裁剪模式。
| 模式 | 值 | 說明 |
|---|---|---|
| 縮放 | scaleToFill. | 不保持縱橫比縮放圖片,使圖片的寬高完全拉伸至填滿 image 元素 |
| 縮放 | aspectFit | 保持縱橫比縮放圖片,使圖片的長邊能完全顯示出來。也就是說,可以完整地將圖片顯示出來。 |
| 縮放 | aspectFill | 保持縱橫比縮放圖片,只保證圖片的短邊能完全顯示出來。也就是說,圖片通常只在水平或垂直方向是完整的,另一個(gè)方向?qū)?huì)發(fā)生截取。 |
| 縮放 | widthFix | 寬度不變,高度自動(dòng)變化,保持原圖寬高比不變 |
| 裁剪 | top | 不縮放圖片,只顯示圖片的頂部區(qū)域 |
| 裁剪 | bottom | 不縮放圖片,只顯示圖片的底部區(qū)域 |
| 裁剪 | center | 不縮放圖片,只顯示圖片的中間區(qū)域 |
| 裁剪 | left | 不縮放圖片,只顯示圖片的左邊區(qū)域 |
| 裁剪 | right | 不縮放圖片,只顯示圖片的右邊區(qū)域 |
| 裁剪 | top left | 不縮放圖片,只顯示圖片的左上邊區(qū)域 |
| 裁剪 | top right | 不縮放圖片,只顯示圖片的右上邊區(qū)域 |
| 裁剪 | bottom left | 不縮放圖片,只顯示圖片的左下邊區(qū)域 |
| 裁剪 | bottom right | 不縮放圖片,只顯示圖片的右下邊區(qū)域 |
原圖

scaleToFill
不保持縱橫比縮放圖片,使圖片完全適應(yīng)

aspectFit
保持縱橫比縮放圖片,使圖片的長邊能完全顯示出來(圖片可完整顯示,背景區(qū)域有留空)

aspectFill
保持縱橫比縮放圖片,只保證圖片的短邊能完全顯示出來(圖片被剪裁,丟失部分內(nèi)容)

為什么要仿造一個(gè)微信小程序的aspectFitImg算法?
在微信小程序頁面開發(fā)時(shí),以繪制公司logo為例,
我希望得到的顯示效果如下:
(Logo和公司名稱在視覺上完美左對(duì)齊)
對(duì)于公司Logo這樣的圖案,是必須完整顯示并保持比例的,任何對(duì)內(nèi)容的剪裁或比例失調(diào)都是無法令人接受的。

為實(shí)現(xiàn)這個(gè)效果,我們通常的做法是:直接指定圖片元素的顯示模式為aspectFit模式,然后將公司Logo和公司名稱左對(duì)齊。
但是這樣會(huì)產(chǎn)生排版上的瑕疵,例如:
假設(shè)圖片的缺省占位寬高為:100px * 40px;
但是從網(wǎng)絡(luò)加載的圖片實(shí)際只有40px * 40px
那么實(shí)際圖片的水平中心點(diǎn)將在占位寬度(100px)的水平正中間對(duì)齊顯示,看起來就好像實(shí)際圖片左邊被留出了30px的寬度,即:(100-40)/2,而這種情況不是我們想要的,因?yàn)槲覀兿胍氖菑囊曈X上看,圖片和底下的元素應(yīng)該可以左對(duì)齊,而不是僅從CSS的視角來看兩個(gè)元素是左對(duì)齊的;
此時(shí),肉眼看見的效果如下:
logo圖片占位和公司名稱在CSS的層面左對(duì)齊,但是從視覺上來看,logo和公司名稱并沒有左對(duì)齊;

在微信小程序中,我解決這個(gè)問題的方法是:
(1)首先,在CSS中使用默認(rèn)的占位寬高來設(shè)定圖片的顯示屬性,打比方:{100px,40px},并設(shè)置數(shù)據(jù)綁定屬性;
(2)從網(wǎng)絡(luò)下載圖片,然后根據(jù){100,40}這個(gè)初始限定來計(jì)算將實(shí)際圖片(可能是400px * 400px)縮放到剛好能塞進(jìn)這個(gè)占位框中時(shí)圖片應(yīng)該被顯示的尺寸,即(40px * 40px);
(3)使用微信小程序中css屬性綁定的機(jī)制來修改占位框的寬度和高度;即將{100px * 40px}動(dòng)態(tài)修改為 {40px * 40px};
在微信小程序中設(shè)置css屬性綁定、下載圖片并獲取圖片的寬高信息等都有現(xiàn)成的方法和完善的API說明文檔,不再言表,僅列出那個(gè)aspectFitImg的方法。
/**
* imgSourceWidth,imgSourceHeight : 圖片的原始高度;
* fitWidth,fitHeight: 圖片保持比例縮放后,要能夠塞進(jìn)這個(gè)大小范圍內(nèi);
* 返回對(duì)象為適配處理后的圖片尺寸,該尺寸是剛剛好可以裝到fitWidth和fitHeight中的,不多一個(gè)像素,也不少一個(gè)像素,并且保持原始的圖片寬高顯示比例;
* 返回示例:{width:100,height:100}
* 如果計(jì)算失敗,返回null
*/
function aspectFitImg(imgSourceWidth, imgSourceHeight, fitWidth, fitHeight) {
if (isNull(imgSourceWidth) || isNull(imgSourceHeight) || isNull(fitWidth) || isNull(fitHeight)) {
return null;
}
if (imgSourceWidth > fitWidth) {
let d = imgSourceWidth / fitWidth;
let th = imgSourceHeight / d;
return this.aspectFitImg(fitWidth, th, fitWidth, fitHeight);
} else if (imgSourceHeight > fitHeight) {
let d = imgSourceHeight / fitHeight;
let tw = imgSourceWidth / d;
return this.aspectFitImg(tw, fitHeight, fitWidth, fitHeight);
} else if (imgSourceWidth <= fitWidth && imgSourceHeight <= fitHeight) {
return { width: imgSourceWidth, height: imgSourceHeight };
} else {
return this.aspectFitImg(imgSourceWidth, imgSourceWidth, fitWidth, fitHeight);
}
}
浪費(fèi)了30分鐘修改文章,午飯要加個(gè)雞腿獎(jiǎng)勵(lì)一下自己..