po語法真麻煩
需求 只引入一個js文件 產(chǎn)品頁使用和推薦頁復(fù)用
liquid 引入 文件 并傳入變量
產(chǎn)品頁
{% 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" %}
推薦頁
<div style="z-index:9;">
{% include 'media-360',path360:path360,preview_image:img_url,height:250 ,productUrl:product.url , size:"small",total:"72",interval:"2",seconds:"12",type:"collection" %}
</div>
media-360.liquid
<style>
.watermark {
position: absolute;
top:0;
left:0;
}
.preview_image{
width: 100%;
height: 100%;
position:absolute;
z-index:-1;
}
.collection-watermark{
position: absolute;
bottom:0;
right:0;
width: 50px;
height:50px;
opacity:0.3;
padding:10px;
}
</style>
<div
class="product-single__media-wrapper js"
data-product-single-media-wrapper
data-media-id="product-template-360view"
style="max-width:{{ height }}px; max-height:{{ height }}px;position:relative;z-index:999;"
tabindex="-1"
data-360-size="{{size}}"
data-360-path="{{ path360 }}"
data-360-total="{{total}}"
data-360-interval="{{interval}}"
data-360-seconds="{{seconds}}"
data-product-url="{{ productUrl }}"
>
{% if type == "collection" %}
<img
onload="media360Load(this,'{{ type }}')"
class="grid-view-item__image lazyload preview_image"
alt=""
data-src="{{ preview_image }}"
data-widths="[180, 360, 540, 720, 900, 1080, 1296, 1512, 1728, 2048]"
data-aspectratio="{{ preview_image.aspect_ratio }}"
data-sizes="auto"
data-image>
<img class="collection-watermark"
src="{{ '360-black.svg' | asset_url }}"
alt="360">
{% else %}
<img
class="preview_image"
onload="media360Load(this,'{{ type }}')"
src="{{ preview_image }}"
alt="">
{% endif %}
{% include "media-360-loading" %}
</div>
支持media360的js文件 邏輯實(shí)現(xiàn)
const sources = {};// key:產(chǎn)品 {{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) {
//開始加載全部數(shù)據(jù)加載完后再播放并添加拖拽效果
requestAllSources({ handleRequestComplete, urlPrefix: `${path360}/${filename360Prefix}`, interval, total, key: folderName, progressBar, requestFailIndex });
} else if (type === 'collection') {
//hover后再加載數(shù)據(jù) 然后移除hover監(jiān)聽
function mouseenter() {
//開始加載全部數(shù)據(jù)加載完后再播放并添加拖拽效果
requestAllSources({ handleRequestComplete, urlPrefix: `${path360}/${filename360Prefix}`, interval, total, key: folderName, progressBar, requestFailIndex });
//移除hover監(jiān)聽
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 鼠標(biāo)樣式改變
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) {
// 添加監(jiān)聽
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();
// 阻止默認(rèn)行為, 用意移動端阻止mouse事件
const distance = e.clientX || e.touches[0].clientX;
// 停止自動播放
clearTimeout(timer);
timer = null;
// 記錄當(dāng)前位置锈津,決定播放方向
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);
// 從當(dāng)前位置開啟自動播放
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 添加 點(diǎn)擊跳轉(zhuǎn)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();
}
}
// 加載進(jìn)度條進(jìn)度變化
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)
}
}