放大器組件

前言

隨手打開一個電商網站(如淘寶),查看商品的時候, 把鼠標放到圖片上都可以看到圖片的更多細節(jié),像把圖片局部放大了一樣(效果如下GIF)。這篇文章就是講述這個放大器的實現(xiàn)。


放大器

原理

在左邊的盒子中放入圖片的 縮略圖 ,右邊的盒子只有在鼠標放上去的時候顯示,并且放置的是對應圖片的大圖,這個大圖只在右邊盒子中顯示出局部。

鼠標放在左邊縮略圖的時候,會顯示出一個遮罩層(mask), 這個 mask 覆蓋縮略圖的位置,會在右邊的盒子中“局部放大”顯示。更確切的說是只顯示右邊圖片的局部。

初始原理圖

圖中 藍色區(qū)域 代表遮罩層, 綠色方框 代表放大圖的原始大小,而 紅色方框 就是我們看到的局部放大部分。 注意,這里有個比例顯示要求:遮罩層大小 / 縮略圖大小 = 放大部分 / 圖片原始大小

當鼠標在左邊縮略圖中移動時,會帶著這個遮罩層移動。獲取遮罩層(mask)在小圖中的位置,然后改變對應大圖在右邊盒子中局部顯示的位置

當遮罩層向下移動的時候,這個大圖向上等比例移動,就會顯示對應的局部放大區(qū)域。只要把溢出的部分隱藏(overflow:hidden)即可達到放大效果。


移動mask & 比例顯示

圖中黑色箭頭是一個比例示例: 比如遮罩層mask 100px, 放大顯示區(qū)域=縮略圖顯示區(qū)域=200px, 原圖大小400px (寬高同理)

我前言的時候有說到這個放大器的時候,提到了一個“像”字,為何那么說?

因為這個左邊的縮略圖片,與右邊的圖片并非同一張圖片。同一張圖片放大之后查看局部是會變模糊的,而淘寶等電商網站放大圖仍是清晰的,這是因為右邊的放大圖是左邊這個縮略圖的高清放大版。你看請求或者在網絡狀態(tài)不佳的情況下加載都可以知道加載了兩個不同大小的圖。

這樣做的目的應該是為了加載網頁的時候更快展現(xiàn)商品,而要查看細節(jié)的話需要另行加載。

實現(xiàn)

我用JS與jquery都實現(xiàn)了一遍, jquery代碼約60行,整體實現(xiàn)還是比較簡單的。這里就講解一下主要代碼及思路,具體細節(jié)歡迎訪問我的GitHub上查看。

html與css部分比較簡單,就是有兩個小點需要注意,等下說。
(img標簽貌似在簡書的code中打不出,自行意會正確寫法吧)

<div class="box">
    <div class="small">
         <!-- ![](img/123-mini.jpg) -->
          <div class="mask hide"></div>
    </div>
    <div class="big hide">
        ![](img/123-large.jpg)
    </div>
</div>

縮略圖的部分 可以使用<img />標簽, 也可用background,或者直接引入背景圖片。不過要注意這個盒子的大小要由CSS指定,并且要讓圖片顯示完整。我使用background: url("...")來放小圖,是因為background-size控制背景圖大小比較方便。

而大圖部分,最好使用標簽展示,這樣方便控制 顯示出來的位置。使用背景圖就要控制background-position,實現(xiàn)起來相對麻煩些(具體實現(xiàn)我還沒試過)。

定義類: class="hide" 即默認該元素是隱藏的。用類來體現(xiàn)顯示 / 隱藏,方便JS控制樣式。

我這里沒有寫下面的列表部分,因為這個比較簡單,而且與放大器功能也無關。

css

這部分也比較簡單, 簡單敘述一下定位和hover效果的問題:

  • 遮罩層和big盒子部分應該設置為 絕對定位 且起始是 隱藏 的,父元素 相對定位。這樣子可以讓遮罩層在父元素中移動。
  • 其中 .small.big 兩個對應的元素,要注意圖片大小和之前提過的比例顯示相符。

遮罩層的顯示,我這里參考了 《css secrets》 里面的點陣代碼,與淘寶的實現(xiàn)有點不同,先貼代碼再說:

.mask { 
    width: 205px;
    height: 205px; 
    /* background-image: url('maskHover.png'); */
    background-image: radial-gradient(rgba(124,165,236, 0.4) 30%, transparent 0),
                    radial-gradient(rgba(124,165,236, 0.4) 30%, transparent 0);
    background-size: 3px 3px;
    background-position: 0 0, 3px 3px;
    position: absolute;
    top: 0;
    left: 0;
    cursor: move; 
}

注釋的那行是淘寶的實現(xiàn)方式,比較簡單粗暴:引用一張背景圖,把我從 background-imagebackground-position 部分的代碼都省略了。

授人以魚不如授人以漁,如何獲取這個圖片: 隨手打開淘寶網站的一個商品頁面,然后鼠標放到縮略圖上的時候審查元素,會看到一個 span 標簽及其css樣式,然后就會看到 background: url(...) ,這個url里面 // 代表該url協(xié)議與當前網站協(xié)議相同,即背景圖片網址為:
https://gtms01.alicdn.com/tps/i4/T12pdtXaldXXXXXXXX-2-2.png

打開這個網址的時候是一片黑的,不要緊,下載過來引用進去就是一樣的效果了。


獲取mask背景圖

好了,魚和漁都有了, 下面可以開始JS了。

JS

這里省略 顯示 / 隱藏 盒子&mask 的JS內容,直接到渲染遮罩層區(qū)域及移動的部分:

先獲取遮罩層的左上角的位置,這是為了能夠用JS來控制這個盒子的位置然后加到頁面中去,這是因為遮罩層的大小已經固定了,只要定好一個點的位置,那么它在縮略圖中的區(qū)域就是固定下來的。

獲取遮罩層左上角坐標的步驟:

  • 獲取鼠標在縮略圖區(qū)域中的坐標(鼠標在瀏覽器中的位置 - 盒子距離瀏覽器頂部的位置): localX & localY
  • 再用 localX & localY , 減去遮罩層的寬高的一半。
    因為我們的遮罩層是跟隨鼠標移動的,所以要先獲取鼠標的坐標再去計算遮罩層的位置。
    獲取mask坐標
let maskX = localX - $(".mask").outerWidth(true) / 2;
let maskY = localY - $(".mask").outerHeight(true) / 2;

然后把遮罩層加到頁面上,但在這之前要做一個是否溢出的判斷。

即判斷我們獲取的這個 maskX 的坐標是否在這個盒子里面:如果溢出,就改變左上角的坐標使得盒子與邊界部分重疊。這時候就實現(xiàn):到達邊界的時候,鼠標可以在遮罩層的靠近邊界區(qū)域隨意移動而遮罩層不動。 (完成了 遮罩層在縮略圖區(qū)域中大小不會改變 的需求)

邊界處理:

    // 判斷mask是否越界, 1\2個if判斷是否左右溢出
    // 3\4 if判斷 是否上下溢出
    if(maskX < 0) {
        maskX = 0;
    }
    if(maskX > $(".small").outerWidth(true) - $(".mask").outerWidth(true)){
        maskX = $(".small").outerWidth(true) - $(".mask").outerWidth(true);
    }
    if(maskY < 0) {
        maskY = 0;
    }
    if(maskY > $(".small").outerHeight(true) - $(".mask").outerHeight(true)){
        maskY = $(".small").outerHeight(true) - $(".mask").outerHeight(true);
    }

// 改變mask的位置, 把遮罩層加到頁面上 
$('.mask').css({ 
    left: maskX + "px",  
     top: maskY + "px" 
})

最后也就是最關鍵的一部分: 等比例移動大圖

要先獲得這個比例(ratio):大圖的寬度 / 縮略圖顯示的寬度 = 圖片移動的距離 / 遮罩層mask移動的距離

    let ratio = parseInt($(".big img").css("width")) / $(".small").outerWidth(true); 

    // 確定圖片移動的距離
    let imgX = ratio * maskX;
    let imgY = ratio * maskY; 

    // 改變圖片顯示的左上角的位置 來移動圖片
    $(".big img").css({
        marginTop: -imgY + "px",
        marginLeft: -imgX + "px"
    })    

獲取完整代碼請點擊文章末尾處鏈接

順帶一提一個在線工具來調整圖片尺寸,這樣展示的時候比較方便:美圖秀秀網頁版

調整圖片尺寸使用

效果展示及源碼

預覽地址
源碼地址

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,431評論 6 544
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 99,637評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,555評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,900評論 1 318
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,629評論 6 412
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,976評論 1 328
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,976評論 3 448
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 43,139評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發(fā)現(xiàn)了一具尸體,經...
    沈念sama閱讀 49,686評論 1 336
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,411評論 3 358
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,641評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,129評論 5 364
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 44,820評論 3 350
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,233評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,567評論 1 295
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,362評論 3 400
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,604評論 2 380

推薦閱讀更多精彩內容