JavaScript實現(xiàn)購物車圖片局部放大預(yù)覽效果
一、實現(xiàn)效果

二、代碼實現(xiàn)
代碼不多,先看一下 HTML 里面結(jié)構(gòu)很簡單,初始化 MagnifyingGlass 對象來關(guān)聯(lián)一個 IMG 標(biāo)簽來實現(xiàn)放大。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
</head>
<style type="text/css">
*{
padding: 0;
margin: 0;
}
.clothes {
width: auto;
height: auto;
}
</style>
<body>
<div>
<img id="clothes" class="clothes" src="./clothes.jpg" alt="">
</div>
</body>
<script src="./magnifyingGlass.js"></script>
<script>
//針對某個標(biāo)簽進(jìn)行圖片放大處理
let magnifyingGlass = new MagnifyingGlass(document.getElementById('clothes'))
</script>
</html>
再看一下 MagnifyingGlass
class MagnifyingGlass {
// 需要放大的圖片
imgEl
// 放大預(yù)覽視圖
magnifyingGlassView
// 區(qū)域小圖
smallCanvas
// 保存原圖的像素值
originalPiexls = []
// 截流定時器
interceptionTimer = null
constructor(el){
if(el.tagName == 'IMG'){
this.imgEl = el
this.listenerImgLoadSucceeded()
}
}
// 監(jiān)聽圖片加載完成
async listenerImgLoadSucceeded(){
if(!this.imgEl.complete){
await new Promise((resolve)=>{
this.imgEl.onload = resolve
})
}
// 添加鼠標(biāo)事件
this.addMouseEvent()
// 創(chuàng)建一個放大預(yù)覽視圖
this.createMagnifyingGlassView()
}
// 創(chuàng)建一個放大預(yù)覽視圖
createMagnifyingGlassView(){
if(this.magnifyingGlassView){
this.magnifyingGlassView.remove()
}
this.magnifyingGlassView = document.createElement('canvas')
this.magnifyingGlassView.style.cssText = 'position: fixed;background:aliceblue;left:0;top:0;pointer-events:none;display:none'
this.magnifyingGlassView.setAttribute('width',`${200}px`)
this.magnifyingGlassView.setAttribute('height',`${200}px`)
let body = document.getElementsByTagName('body')[0]
body.appendChild(this.magnifyingGlassView)
}
// 添加鼠標(biāo)事件
addMouseEvent(){
// 添加鼠標(biāo)滑過事件
this.addMouseMoveToImageEl()
// 鼠標(biāo)滑出事件
this.addMouseLeaveToImageEl()
}
// 添加鼠標(biāo)滑過事件
addMouseMoveToImageEl(){
this.imgEl.onmousemove = (event)=>{
let x = event.clientX + this.getElementPosition(this.imgEl).left + 20
let y = event.clientY + this.getElementPosition(this.imgEl).top + 20
let position = { x, y }
// 截流
this.interceptionFunc(()=>{
// 修改放大視圖位置
this.changeMagnifyingGlassViewPosition(position)
// 獲取需要放大的像素
this.getNeedMasgnifyingGlassPiexl({clientX: (event.clientX - this.getElementPosition(this.imgEl).left),clientY: (event.clientY - this.getElementPosition(this.imgEl).top)})
})
}
}
//截流
interceptionFunc(cb){
if(this.interceptionTimer){
return
}
this.interceptionTimer = setTimeout(() => {
cb()
this.interceptionTimer = null
}, 20);
}
// 鼠標(biāo)滑出事件
addMouseLeaveToImageEl(){
this.imgEl.onmouseleave = ()=>{
// 移除放大框
this.magnifyingGlassView.style.display = 'none'
}
}
// 修改放大視圖位置
changeMagnifyingGlassViewPosition(position){
this.magnifyingGlassView.style.left = position.x + 'px'
this.magnifyingGlassView.style.top = position.y + 'px'
this.magnifyingGlassView.style.display = 'block'
}
// 獲取元素在屏幕的位置
getElementPosition(element){
var top = element.offsetTop
var left = element.offsetLeft
var currentParent = element.offsetParent;
while (currentParent !== null) {
top += currentParent.offsetTop
left += currentParent.offsetLeft
currentParent = currentParent.offsetParent
}
return {top,left}
}
// 保存原像素(操作像素點時候用)
async getOriginalPiexls(){
if(this.originalPiexls.length == 0){
var image = new Image();
image.src = this.imgEl.src;
// 等待IMG標(biāo)簽加載完成后保存像素值
await new Promise((resolve)=>{
image.onload = resolve
})
let width = image.width
let height = image.height
let canvas = document.createElement('canvas')
canvas.setAttribute('width',`${width}px`)
canvas.setAttribute('height',`${height}px`)
var ctx = canvas.getContext("2d")
ctx.fillStyle = ctx.createPattern(image, 'no-repeat');
ctx.fillRect(0, 0, width, height);
try {
//保存像素
this.originalPiexls = ctx.getImageData(0,0,width,height)
} catch (error) {
console.log(error)
}
}
}
// 獲取需要放大的像素
async getNeedMasgnifyingGlassPiexl(event){
//獲取原始像素
this.getOriginalPiexls()
//如果像素為空,不進(jìn)行操作
if(this.originalPiexls.length == 0){
return
}
//獲取待放大IMG的寬度,用來計算像素
let imageWidth = this.imgEl.offsetWidth
//獲取當(dāng)前鼠標(biāo)點的范圍
let diffusionLength = 100
//鼠標(biāo)觸點
let mouseX = event.clientX
let mouseY = event.clientY
//規(guī)定區(qū)域的上下、左右寬度
let sepX = parseInt(diffusionLength)
let sepY = parseInt(diffusionLength)
// 需要開始的點
let startPoint = {x:(mouseX - parseInt(sepX / 2.0)),y:(mouseY - parseInt(sepY / 2.0))}
// 需要結(jié)束的點
let endPoint = {x:(mouseX + parseInt(sepX / 2.0)),y:(mouseY + parseInt(sepY / 2.0))}
// 最終要展示的像素集合(乘以4是單一像素值寬度)
let finallyOriginalPiexls = new Uint8ClampedArray(sepX * sepY * 4)
let currentIndex = 0
//操作像素
for(let i = startPoint.y;i < endPoint.y;i++){
for(let j = startPoint.x; j < endPoint.x;j++){
for(let k = 0;k < 4;k++){
let index = (i * imageWidth + j) * 4 + k
if(index > 0 && index < this.originalPiexls.data.length){
// 超過寬度部分需要進(jìn)行其他色值填充
if(j < imageWidth){
finallyOriginalPiexls[currentIndex] = this.originalPiexls.data[index]
} else {
finallyOriginalPiexls[currentIndex] = 199
}
} else {
finallyOriginalPiexls[currentIndex] = 199
}
currentIndex += 1
}
}
}
//先繪制一個100*100單位長的小圖
if(!this.smallCanvas){
this.smallCanvas = document.createElement('canvas')
this.smallCanvas.setAttribute('width',`${diffusionLength}px`)
this.smallCanvas.setAttribute('height',`${diffusionLength}px`)
}
let smallCtx = this.smallCanvas.getContext("2d")
//初始化ImageData
let finallyImageData = new ImageData(finallyOriginalPiexls,sepX,sepY)
// 當(dāng)前范圍內(nèi)需要放大的像素
smallCtx.putImageData(finallyImageData,0,0,0,0,diffusionLength,diffusionLength)
let url = this.smallCanvas.toDataURL('image/jpeg',1)
//將小圖繪制到200*200的預(yù)覽圖上
var image = new Image();
image.src = url;
await new Promise((resolve)=>{
image.onload = resolve
})
var magnifyingGlassCtx = this.magnifyingGlassView.getContext("2d")
magnifyingGlassCtx.drawImage(image, 0,0,200,200);
}
}上面的就是全部邏輯,實現(xiàn)方法肯定不是最優(yōu)的,但是其中可以聯(lián)想到通過像素點的操作實現(xiàn)任意效果。
三、獲取像素信息跨域問題怎么解決
可以啟動一個 node 本地服務(wù),首先見一個包含 index.js 和 package.json 的入口文件的文件夾。
package.json 內(nèi)容如下:
{
"name": "youname",
"version": "1.0.0",
"description": "description",
"main": "index.js",
"scripts": {
"test": "node ./index.js"
},
"author": "wsl",
"license": "ISC",
"dependencies": {
"express": "^4.17.3",
"express-static": "^1.2.6",
"http": "^0.0.1-security"
}
}index.js 內(nèi)容如下:
var express = require('express')
var app = express()
var http = require('http').Server(app)
//公共頁面訪問設(shè)置
app.use(express.static('www'))
//開啟服務(wù)
http.listen(3000,function(){
console.log('開始了')
})終端執(zhí)行 npm install 后再執(zhí)行啟動服務(wù)命令 node ./index.js:

注意將前端文件放在目錄里 www 文件夾下

這樣跨域問題就解決了。
四、總結(jié)與思考
圖像就是像素的集合,一個像素又有RGBA四個值,那么,操作像素是不是就能實現(xiàn)很多有趣的效果呢?這里計算 img 位置其實還需要考慮窗口的滾動距離,代碼拙劣,大神勿笑,如果能對大家有所幫助,深感欣慰!
到此這篇關(guān)于JavaScript實現(xiàn)購物車圖片局部放大預(yù)覽效果的文章就介紹到這了,更多相關(guān)JavaScript圖片局部放大預(yù)覽內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
轉(zhuǎn)換json格式的日期為Javascript對象的函數(shù)
項目中碰到了用jQuery從后臺獲取的json格式的日期的字符串,需要將此字符串轉(zhuǎn)換成JavaScript的日期對象,記在此處,以備后用。2010-07-07
javascript html實現(xiàn)網(wǎng)頁版日歷代碼
這篇文章主要介紹了javascript html實現(xiàn)網(wǎng)頁版日歷代碼,需要的朋友可以參考下2016-03-03
基于Taro的微信小程序模板消息-獲取formId功能模塊封裝實踐
這篇文章主要介紹了基于Taro的微信小程序模板消息-獲取formId功能模塊封裝實踐,小程序提供了一種能力-模板消息,基于微信的通知渠道,我們?yōu)殚_發(fā)者提供了可以高效觸達(dá)用戶的模板消息能力,以便實現(xiàn)服務(wù)的閉環(huán)并提供更佳的體驗,需要的朋友可以參考下2019-07-07
如何使用pace.js美化你的網(wǎng)站加載進(jìn)度條詳解
Pace.js是一個非常有意思的js插件,可以自動的監(jiān)聽頁面的加載數(shù)據(jù),并且能夠定制加載條,下面這篇文章主要給大家介紹了關(guān)于使用pace.js如何美化你的網(wǎng)站加載進(jìn)度條的相關(guān)資料,需要的朋友可以參考下2022-02-02
JS使用面向?qū)ο蠹夹g(shù)實現(xiàn)的tab選項卡效果示例
這篇文章主要介紹了JS使用面向?qū)ο蠹夹g(shù)實現(xiàn)的tab選項卡效果,結(jié)合具體實例形式分析了js面向?qū)ο蠹夹g(shù)與tab選項卡功能的具體實現(xiàn)技巧,需要的朋友可以參考下2017-02-02
javascript getElementByTagName的使用
javascript getElementByTagName當(dāng)鼠標(biāo)放上去時將超鏈接的顏色設(shè)為藍(lán)色的。2009-06-06
使用TypeScript實現(xiàn)一個類型安全的EventBus示例詳解

