記錄-JS簡單實現購物車圖片局部放大預覽效果

来源:https://www.cnblogs.com/smileZAZ/archive/2023/04/20/17337784.html
-Advertisement-
Play Games

這裡給大家分享我在網上總結出來的一些知識,希望對大家有所幫助 一、實現效果 二、代碼實現 代碼不多,先看一下 HTML 裡面結構很簡單,初始化 MagnifyingGlass 對象來關聯一個 IMG 標簽來實現放大。 <!DOCTYPE html> <html> <head> <meta chars ...


這裡給大家分享我在網上總結出來的一些知識,希望對大家有所幫助

一、實現效果

屏幕錄製2023-02-18 下午8.21.50.gif

二、代碼實現

代碼不多,先看一下 HTML 裡面結構很簡單,初始化 MagnifyingGlass 對象來關聯一個 IMG 標簽來實現放大。

<!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>
    //針對某個標簽進行圖片放大處理
    let magnifyingGlass = new MagnifyingGlass(document.getElementById('clothes'))
</script>

</html>

再看一下 MagnifyingGlass

class MagnifyingGlass {

    // 需要放大的圖片
    imgEl
    // 放大預覽視圖
    magnifyingGlassView
    // 區域小圖
    smallCanvas
    // 保存原圖的像素值
    originalPiexls = []
    // 截流定時器
    interceptionTimer = null

    constructor(el){
        if(el.tagName == 'IMG'){
            this.imgEl = el
            this.listenerImgLoadSucceeded()
        }
    }
    
    // 監聽圖片載入完成
    async listenerImgLoadSucceeded(){
        if(!this.imgEl.complete){
            await new Promise((resolve)=>{
            this.imgEl.onload = resolve
        })
    }
    
    // 添加滑鼠事件
    this.addMouseEvent()
        // 創建一個放大預覽視圖
        this.createMagnifyingGlassView()
    }

    // 創建一個放大預覽視圖
    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)
    }

    // 添加滑鼠事件
    addMouseEvent(){
        // 添加滑鼠滑過事件
        this.addMouseMoveToImageEl()
        // 滑鼠滑出事件
        this.addMouseLeaveToImageEl()
    }

    // 添加滑鼠滑過事件
    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);
    }

    // 滑鼠滑出事件
    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標簽載入完成後保存像素值
            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()
        //如果像素為空,不進行操作
        if(this.originalPiexls.length == 0){
            return
        }
        //獲取待放大IMG的寬度,用來計算像素
        let imageWidth = this.imgEl.offsetWidth
        //獲取當前滑鼠點的範圍
        let diffusionLength = 100
        //滑鼠觸點
        let mouseX = event.clientX
        let mouseY = event.clientY
        //規定區域的上下、左右寬度
        let sepX = parseInt(diffusionLength)
        let sepY = parseInt(diffusionLength)
        // 需要開始的點
        let startPoint = {x:(mouseX - parseInt(sepX / 2.0)),y:(mouseY - parseInt(sepY / 2.0))}
        // 需要結束的點
        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){
                    // 超過寬度部分需要進行其他色值填充
                    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)
        // 當前範圍內需要放大的像素
        smallCtx.putImageData(finallyImageData,0,0,0,0,diffusionLength,diffusionLength)
        let url = this.smallCanvas.toDataURL('image/jpeg',1)
        
        //將小圖繪製到200*200的預覽圖上
        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);
    }
}

上面的就是全部邏輯,實現方法肯定不是最優的,但是其中可以聯想到通過像素點的操作實現任意效果。

三、獲取像素信息跨域問題怎麼解決?

可以啟動一個 node 本地服務,首先見一個包含 index.jspackage.json 的入口文件的文件夾。

package.json 內容如下:

{
    "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 內容如下:

var express = require('express')
var app = express()
var http = require('http').Server(app)
//公共頁面訪問設置
app.use(express.static('www'))
//開啟服務
http.listen(3000,function(){
    console.log('開始了')
})

終端執行 npm install 後再執行啟動服務命令 node ./index.js:

三、獲取像素信息跨域問題怎麼解決?

image.png

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

image.png

這樣跨域問題就解決了。

本文轉載於:

https://juejin.cn/post/7201437314693906491

如果對您有所幫助,歡迎您點個關註,我會定時更新技術文檔,大家一起討論學習,一起進步。

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • Redis是基於記憶體存儲的資料庫,如果遇到服務重啟或者崩潰,記憶體中的數據將會被清空。所以為了確保數據安全性和可靠性,我們需要將記憶體中的數據持久化到磁碟上。 持久化不僅可以防止由於系統故障、重啟或者其他原因導致的數據丟失。還可以用於備份、數據恢復和遷移等操作。 ...
  • 背景介紹 最近學習OpenHarmony應用開發, SDK版本是3.2.9.2 Beta4,IDE版本是3.1.0.200。參考官方文檔,做了個Demo應用,調試、運行非常順利。啟動應用後,狀態欄和導航欄占用的高度過高,顯得很奇怪,嘗試修改一下系統應用。 摸石頭過河 因為沒做過移動端開發,最初以為狀 ...
  • HUAWEI Wear Engine面向手機和穿戴設備的應用與服務開發者,提供華為穿戴設備開放能力。 開發者通過調用Wear Engine開放能力,可以實現手機上的生態應用與服務給華為穿戴設備發消息、發通知、傳輸數據,並獲取穿戴設備狀態、讀取感測器數據等,也可以實現華為穿戴設備上的生態應用與服務給手 ...
  • 前言 平時開發中遇到這樣那樣的命令需要記下來,一般做法是這樣。 新建記事本 將需要記下的關鍵命令保存。 每次需要使用時,粘貼複製即可。 好像沒什麼毛病!直到遇到了 Cmder。。。 當看到同事分析問題時在 Cmder 里命令快捷鍵刷刷一頓操作,覺得挺厲害滴。感覺這同事技術好牛,快捷鍵用這麼好。後來才 ...
  • OpenTiny 組件庫建設者、開源社區負責人 Kagol 與前端楊村長聯合直播,盛情邀請你一同共同揭秘:OpenTiny 的落地實踐之路。 就在周五晚8點,前端村長直播間,等你來撩~ ...
  • 註冊及開發配置 註冊:微信公眾平臺 註冊後在開發管理-開發設置中複製AppID(小程式ID); 開發工具:推薦官方 微信開發者工具 微信官方文檔: 微信開放文檔 新建第一個項目 在微信開發者工具中新建項目 打開並登錄微信開發者工具,新建一個小程式項目。appID填入你剛剛複製的id,後端服務可選中不 ...
  • 在Vue.js 3中,使用Axios與Vue.js 2.x中類似,但是需要進行一些修改和更新,下麵是Vue.js 3中Axios的定義和使用方式: 首先,你需要安裝Axios和Vue.js 3.x,可以使用npm或yarn等包管理工具安裝: npm install axios vue@next 然後 ...
  • JavaScript 簡寫語法 1、簡寫的閉包自執行函數(Immediately Invoked Function Expression (IIFE)) 使用括弧將函數定義包裹起來,再在末尾加上另一對括弧,即可創建一個自執行函數。例如: (() => { console.log("Hello, wo ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...