深圳自適應網(wǎng)站開發(fā)頭條廣告入口
背景介紹
最近,公司需要開發(fā)一款在線圖像壓縮工具,其中的一個關鍵功能是讓用戶直觀地比較壓縮前后的圖像效果。因此,我們設計了一個對比組件,它允許用戶通過拖動滑塊,動態(tài)調(diào)整兩張圖像的顯示區(qū)域,從而清晰地看到壓縮前后的差異。
目標效果
- 兩張圖片堆疊放置,一張始終可見,另一張可調(diào)整可見范圍。
- 通過滑塊拖動,控制上層圖片的顯示區(qū)域。
- 適配 PC 和移動端,提供流暢的交互體驗。
效果如圖:
開發(fā)思路
結(jié)構(gòu)設計
- 創(chuàng)建一個外層容器,用于包裹兩張圖片和滑塊。
- 底層圖片(原始圖像)始終可見。
- 頂層圖片(優(yōu)化后圖像)放置在上方,并使用 clip-path 控制其顯示范圍。
- 滑塊(拖動條) 用于調(diào)整頂層圖片的可見區(qū)域。
<div class="image-change-block"><div class="desc-container"><div class="before-desc">BEFORE (827 KB)</div><div class="after-desc">AFTER (94 KB)</div></div><img src="after.jpg" class="new-img" /><div class="clip-container"><img src="before.jpg" class="old-img" /></div><div class="handle-container"><div class="bar-btn" id="barBtn"></div><div class="bar-line" id="barLine"></div></div>
</div>
樣式布局
- 兩張圖片:底層圖片 position: absolute; 覆蓋整個容器,頂層圖片使用 clip-path 或 width 控制顯示區(qū)域。
- 滑塊樣式:自定義 div + 偽元素 作為滑塊,并放在 absolute 位置。
.image-change-block {position: relative;max-width: 44rem;overflow: hidden;border-radius: 1.25rem;
}.desc-container {top: 1.25rem;position: absolute;display: flex;align-items: center;justify-content: space-between;flex-wrap: wrap;width: 100%;padding: 0 1.25rem;gap: 0.3125rem;
}.after-desc,
.before-desc {background-color: #000000;opacity: 0.6;color: #fff;border-radius: 0.25rem;z-index: 10;font-size: var(--global--font-size-sm);padding: 0.3125rem 1.5rem;
}.old-img,
.new-img {width: 100%;height: 100%;object-fit: cover;display: block;
}.clip-container {position: absolute;top: 0;left: 0;width: 100%;height: 100%;overflow: hidden;
}.old-img {position: absolute;top: 0;left: 0;width: 100%;height: 100%;clip-path: inset(0 50% 0 0);transition: clip-path 0.01s ease;
}.handle-container {position: absolute;top: 0;left: 0;height: 100%;width: 100%;pointer-events: none;
}.bar-btn {position: absolute;top: 50%;left: 50%;transform: translate(-50%, -50%);width: 2rem;height: 2rem;border-radius: 50%;pointer-events: all;cursor: ew-resize;z-index: 2;
}.bar-line {position: absolute;top: 0;left: 50%;height: 100%;width: 3px;background-color: var(--theme-green-color);z-index: 1;
}.bar-btn::before {width: 28px;height: 28px;content: "";cursor: ew-resize;background: #00d4c9;position: absolute;left: 50%;top: 50%;transform: translate(-45%, -50%);display: block;border-radius: 50%;box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);z-index: 1;
}.bar-btn::after {content: "";background: var(--theme-green-color);width: 3px;height: 100%;position: absolute;left: 50%;top: 0;box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
}
交互邏輯
封裝一個兼容 PC 和移動端的拖拽對比函數(shù),通過傳入對應的 dom 實現(xiàn)鼠標或手指拖動滑塊時圖像的對比。
initClip({barBtn: document.querySelector(`.bar-btn`),barLine: document.querySelector(`.bar-line`),clipContainer: document.querySelector(`.clip-container`),oldImg: document.querySelector(`.old-img`),
});/*** 初始化通過剪裁實現(xiàn)圖像對比的功能* @param {Object} doms - 包含所需DOM元素的對象* - barBtn: 滑動按鈕元素* - barLine: 滑動線條元素* - clipContainer: 剪裁容器元素* - oldImg: 被剪裁的圖片元素*/
function initClip(doms) {// 解構(gòu)賦值獲取所需的DOM元素const { barBtn, barLine, clipContainer, oldImg } = doms;// 定義變量以跟蹤鼠標或觸摸是否在拖動let isDragging = false;let isMDragging = false;/*** 更新圖片剪裁位置* @param {number} x - 鼠標或觸摸在剪裁容器上的x坐標*/function updateImageClip(x) {// 計算剪裁容器的寬度const containerWidth = clipContainer.offsetWidth;// 計算并限制剪裁的百分比const percent = Math.min(Math.max(x / containerWidth, 0), 1);// 更新圖片的剪裁路徑oldImg.style.clipPath = `inset(0 ${100 - percent * 100}% 0 0)`;// 更新滑動按鈕和線條的位置barBtn.style.left = `${percent * 100}%`;barLine.style.left = `${percent * 100}%`;}// 添加鼠標按下事件監(jiān)聽器到滑動按鈕barBtn.addEventListener("mousedown", (e) => {// 開始拖動并阻止默認行為isDragging = true;e.preventDefault();});// 添加鼠標抬起事件監(jiān)聽器到文檔document.addEventListener("mouseup", () => {// 結(jié)束拖動isDragging = false;});// 添加鼠標移動事件監(jiān)聽器到文檔document.addEventListener("mousemove", (e) => {// 如果正在拖動,則更新圖片剪裁if (isDragging) {const x = e.clientX - clipContainer.getBoundingClientRect().left;updateImageClip(x);}});// 添加點擊事件監(jiān)聽器到剪裁容器clipContainer.addEventListener("click", (e) => {// 點擊時更新圖片剪裁const x = e.clientX - clipContainer.getBoundingClientRect().left;updateImageClip(x);});// 添加觸摸開始事件監(jiān)聽器到滑動按鈕barBtn.addEventListener("touchstart", (e) => {// 開始拖動并阻止默認行為isMDragging = true;e.preventDefault();});// 添加觸摸結(jié)束事件監(jiān)聽器到文檔document.addEventListener("touchend", () => {// 結(jié)束拖動isMDragging = false;});// 添加觸摸移動事件監(jiān)聽器到文檔document.addEventListener("touchmove", (e) => {// 如果正在拖動,則更新圖片剪裁if (isMDragging) {const touch = e.touches[0];const x = touch.clientX - clipContainer.getBoundingClientRect().left;updateImageClip(x);}});
}
總結(jié)
這個滑塊對比組件利用 clip-path 來裁剪圖像,并結(jié)合鼠標和觸摸事件監(jiān)聽,實現(xiàn)了流暢的交互體驗。它不僅適用于圖像壓縮前后的對比,還可以擴展到濾鏡效果、照片修復等其他圖像對比場景。在實際開發(fā)中,我們可以根據(jù) UI 需求,進一步優(yōu)化滑塊的樣式、動畫效果,以及提升移動端的操作體驗。
原文鏈接
圖像滑塊對比功能的開發(fā)記錄