shopify Liquid 商品360旋转拖拽查看功能

屏幕录制2021-07-01 下午1.gif

po语法真麻烦

需求 只引入一个js文件 产品页使用和推荐页复用

liquid 引入 文件 并传入变量
产品页

{% include 'media-360', path360: product.metafields.custom_fields.path_360, featured_media: featured_media, height: height,preview_image:preview_image , type:"product",size:"medium",total:"72" ,interval:'1',seconds:"10"  %}

推荐页

{% include 'media-360',path360:path360,preview_image:img_url,height:250 ,productUrl:product.url , size:"small",total:"72",interval:"2",seconds:"12",type:"collection" %}

media-360.liquid


{% if type == "collection" %} 360 {% else %} {% endif %} {% include "media-360-loading" %}

支持media360的js文件 逻辑实现

const sources = {};// key:产品 {{folderName}} value:{  key:索引 value:Image元素src为请求的blob图片}

function media360Load(e, type) {
    const container = e.parentElement;
    const size = container.scrollWidth;
    const canvas = createCanvas({ width: size, height: size, });
    container.appendChild(canvas);
    const canvasContext = canvas.getContext("2d");
    const path360 = container.getAttribute("data-360-path");
    const size360 = container.getAttribute("data-360-size");//medium or small
    const total = Number(container.getAttribute("data-360-total"));
    const interval = Number(container.getAttribute("data-360-interval"));
    const seconds = container.getAttribute("data-360-seconds");
    const timeout = Math.round(seconds * 1000 / total);
    const folderName = path360.split('/').pop();
    sources[folderName] = {};//初始化对象
    const filename360Prefix = `${folderName}-${size360}-`;
    const progressBar = container.querySelector('div .load-progress-bar');
    const requestFailIndex = [];
    let timer = null;
    let currentIndex = 1;
    let prevMoveOrigin = 0;
    const onProductPage = type === 'product'
    let moveCount = 0;// collection 切换12个px次才动一次 否则浏览太快


    if (onProductPage) {
        //开始加载全部数据加载完后再播放并添加拖拽效果
        requestAllSources({ handleRequestComplete, urlPrefix: `${path360}/${filename360Prefix}`, interval, total, key: folderName, progressBar, requestFailIndex });
    } else if (type === 'collection') {
        //hover后再加载数据 然后移除hover监听
        function mouseenter() {
            //开始加载全部数据加载完后再播放并添加拖拽效果
            requestAllSources({ handleRequestComplete, urlPrefix: `${path360}/${filename360Prefix}`, interval, total, key: folderName, progressBar, requestFailIndex });
            //移除hover监听
            container.removeEventListener('mouseenter', mouseenter);
        }
        container.addEventListener('mouseenter', mouseenter);
    }

    //开始播放
    function startPaly(index) {
        // clearTimeout(timer);
        const sourceIndex = index <= total ? index : 1;
        drawSource(canvasContext, sources[folderName][sourceIndex], size);
        currentIndex = index;
        timer = setTimeout(() => {
            startPaly(sourceIndex + interval);
        }, timeout)
    }
    //请求完成后需要的操作
    function handleRequestComplete() {
        //开始播放
        startPaly(1);
        //添加拖拽效果
        addDragListener();
        //请求失败的 再次请求
        requestSourceAgain();
        //collection 360水印去掉 product 鼠标样式改变
        if (!onProductPage) {
            const watermark = container.querySelector(".collection-watermark");
            container.removeChild(watermark);
            canvas.style['cursor'] = "ew-resize"
        } else {
            canvas.style["cursor"] = "grab";
        }
    }

    //再次请求请求失败的资源
    function requestSourceAgain() {
        requestFailIndex.forEach((index) => {
            requestImageBlob(index)
                .then(({ data }) => {
                    generateImage(data).onload = ({ path: [image] }) => {
                        sources[folderName][index] = image;
                    };
                })
        })
    }

    function addDragListener() {
        if (onProductPage) {
            // 添加监听
            canvas.addEventListener("mousedown", starDrag);
            canvas.addEventListener("mouseup", stopDrag);
            canvas.addEventListener("mouseleave", stopDrag);
            // 移动端事件
            canvas.addEventListener("touchstart", starDrag);
            canvas.addEventListener("touchend", stopDrag);
            canvas.addEventListener("touchleave", stopDrag);
        } else {
            canvas.addEventListener("mouseenter", starDrag);
            canvas.addEventListener("mousemove", mouseMove);
            canvas.addEventListener("mouseleave", stopDrag);
        }


    }

    function starDrag(e) {
        e.preventDefault();
        // 阻止默认行为, 用意移动端阻止mouse事件
        const distance = e.clientX || e.touches[0].clientX;
        // 停止自动播放
        clearTimeout(timer);
        timer = null;
        // 记录当前位置,决定播放方向
        prevMoveOrigin = distance;
        // 添加移动事件
        canvas.addEventListener("touchmove", mouseMove);
        canvas.addEventListener("mousemove", mouseMove);
        if (onProductPage) {
            canvas.style['cursor'] = "grabbing";
        }
    }


    function mouseMove(e) {
        e.preventDefault();
        if (!onProductPage) {
            moveCount += 1;
            if (moveCount < 12) return;
            moveCount = 0;
        }
        if (timer) { clearTimeout(timer); timer = null; }
        const distance = e.clientX || e.touches[0].clientX;
        const nextSourcesIndex = computedNextSourcesIndex(
            distance,
            prevMoveOrigin,
            currentIndex,
        );
        drawSource(canvasContext, sources[folderName][nextSourcesIndex], size);
        currentIndex = nextSourcesIndex;
        prevMoveOrigin = distance;
    }


    function stopDrag() {
        canvas.removeEventListener("mousemove", mouseMove);
        canvas.removeEventListener("touchmove", mouseMove);
        // 从当前位置开启自动播放
        startPaly(currentIndex);
        if (onProductPage) {
            canvas.style['cursor'] = "grab";
        }
    }


    function computedNextSourcesIndex(
        clientX,
        prevClientX,
        currentSourceIndex,
    ) {
        let nextIndex = currentSourceIndex;
        if ((clientX - prevClientX) > 0) {
            nextIndex = currentSourceIndex - interval;
        } else if ((clientX - prevClientX) < 0) {
            nextIndex = currentSourceIndex + interval;
        }

        const allowValue = nextIndex <= total && nextIndex >= 1;

        return allowValue ? nextIndex : nextIndex < 1 ? (total + 1 - interval) : 1;
    }
    //collection 添加 点击跳转product页面
    if (!onProductPage) {
        const link = document.createElement('a');
        container.appendChild(link);
        link.setAttribute('href', container.getAttribute("data-product-url"));
        container.addEventListener('click', () => {
            link.click();
        })
    }
}

function requestAllSources({ handleRequestComplete, urlPrefix, interval, total, key, progressBar, requestFailIndex }) {
    for (let index = 1; index <= total; index += interval) {
        requestImageBlob(urlPrefix, index)
            .then(({ data }) => {
                generateImage(data).onload = ({ path: [image] }) => {
                    sources[key][index] = image;
                    oneRequestComplete(key, total, progressBar, handleRequestComplete, interval);
                };
            })
            .catch(err => {
                console.error('request err - ' + index, err);
                sources[key][index] = sources[key][index - 1];
                requestFailIndex.push(index);
                oneRequestComplete(key, total, progressBar, handleRequestComplete, interval);
            });

    }
}

// 每次请求完一个资源后需要判断是否是最后一个
function oneRequestComplete(key, total, progressBar, handleRequestComplete, interval) {
    const { length } = Object.keys(sources[key]);
    const intervalLength = length * interval;
    progressBarProgress(progressBar, intervalLength, total);
    if (intervalLength == total) {
        // console.log("request complete", sources[key]);
        progressBar.style['height'] = '0';
        progressBar.style['opacity'] = '0';
        handleRequestComplete();
    }
}

// 加载进度条进度变化
function progressBarProgress(progressBar, length, total) {
    const progress = ((length / total) % total) * 100;
    progressBar.style["width"] = `${progress}%`;
}

//生成sources需要存储的 保存了blob图片的img元素
function generateImage(bold) {
    const image = new Image();
    const imgSrc = window.URL.createObjectURL(bold);
    image.src = imgSrc;
    return image;
}

function createCanvas(canvasProperties) {
    const canvas = document.createElement("canvas");
    for (const [property, value] of Object.entries(canvasProperties)) {
        canvas[property] = value;
    }
    return canvas;
}

function requestImageBlob(urlPrefix, index) {
    return axios.get(`${urlPrefix}${index}.jpg?`, { responseType: 'blob' })
}

// canvas绘制图片
function drawSource(canvasContext, image, size) {
    try {
        canvasContext.drawImage(image, 0, 0, size, size);
    } catch (error) {
        console.log("draw source err:", error)
    }
}

https://kalosgem.com/

你可能感兴趣的:(shopify Liquid 商品360旋转拖拽查看功能)