mirror of
https://gitee.com/ShopeX/OMS
synced 2026-04-05 06:45:32 +08:00
367 lines
14 KiB
JavaScript
367 lines
14 KiB
JavaScript
|
||
|
||
/**
|
||
* 图片放大镜组件 - 完整版
|
||
* 基于 MooTools 的 Tips 和 Asset.image,支持智能缩放和动态尺寸调整
|
||
*/
|
||
|
||
(function(){
|
||
'use strict';
|
||
|
||
// 检查 MooTools 依赖 - 更宽松的检查
|
||
if (typeof Class === 'undefined') {
|
||
console.error('ImageMagnifier: 需要 MooTools Core 支持');
|
||
return;
|
||
}
|
||
|
||
// 图片放大镜类
|
||
var ImageMagnifier = new Class({
|
||
|
||
// 默认配置
|
||
options: {
|
||
maxWidth: 600, // 最大显示宽度
|
||
maxHeight: 600, // 最大显示高度
|
||
maxScale: 3, // 最大放大倍数
|
||
offset: {x: 30, y: -20}, // 位置偏移
|
||
className: 'magnifier-tip', // 自定义样式类
|
||
showDelay: 0, // 显示延迟(ms)
|
||
hideDelay: 0, // 隐藏延迟(ms)
|
||
fixed: false, // 是否固定位置
|
||
fade: true, // 是否使用淡入淡出
|
||
onShow: null, // 显示回调
|
||
onHide: null, // 隐藏回调
|
||
onLoad: null // 图片加载完成回调
|
||
},
|
||
|
||
// 初始化
|
||
initialize: function(element, options) {
|
||
this.element = $(element);
|
||
this.options = Object.merge(this.options, options || {});
|
||
this.tip = null;
|
||
this.isActive = false;
|
||
|
||
this._createTip();
|
||
this._attachEvents();
|
||
this._addStyles();
|
||
},
|
||
|
||
// 创建提示框
|
||
_createTip: function() {
|
||
// 检查是否有 Tips 支持,如果没有则使用简化版本
|
||
if (typeof Tips !== 'undefined') {
|
||
this.tip = new Tips(this.element, {
|
||
className: this.options.className,
|
||
showDelay: this.options.showDelay,
|
||
hideDelay: this.options.hideDelay,
|
||
fixed: this.options.fixed,
|
||
fade: this.options.fade,
|
||
onShow: this._onShow.bind(this),
|
||
onHide: this._onHide.bind(this),
|
||
text: function() { return ' '; }
|
||
});
|
||
} else {
|
||
// 简化版本:直接绑定鼠标事件
|
||
this._createSimpleTip();
|
||
}
|
||
},
|
||
|
||
// 创建简化版提示框
|
||
_createSimpleTip: function() {
|
||
this.tip = {
|
||
element: null,
|
||
show: function() { this.element.style.display = 'block'; },
|
||
hide: function() { this.element.style.display = 'none'; },
|
||
detach: function() {
|
||
if (this.element && this.element.parentNode) {
|
||
this.element.parentNode.removeChild(this.element);
|
||
}
|
||
}
|
||
};
|
||
|
||
// 创建提示框元素
|
||
this.tip.element = new Element('div', {
|
||
'class': this.options.className,
|
||
'style': 'position:fixed;z-index:999999;display:none;background:transparent;border:none;padding:0;max-width:' + this.options.maxWidth + 'px;max-height:' + this.options.maxHeight + 'px;overflow:hidden;box-shadow:0 4px 20px rgba(0,0,0,0.15);border-radius:6px;pointer-events:none;'
|
||
});
|
||
|
||
document.body.appendChild(this.tip.element);
|
||
|
||
// 绑定显示/隐藏事件
|
||
this.element.addEvent('mouseenter', this._onShow.bind(this));
|
||
this.element.addEvent('mouseleave', this._onHide.bind(this));
|
||
this.element.addEvent('mousemove', this._updatePosition.bind(this));
|
||
},
|
||
|
||
// 显示事件处理
|
||
_onShow: function(tip, element) {
|
||
this.isActive = true;
|
||
element = element || this.element;
|
||
element.addClass('magnifier-active');
|
||
|
||
var imgSrc = element.get('rel') || element.get('data-src') || element.src;
|
||
|
||
if (this.tip.element) {
|
||
// 简化版本
|
||
this.tip.element.store('tip:imgsource', imgSrc);
|
||
this._loadImage(imgSrc, this.tip.element);
|
||
this.tip.show();
|
||
} else if (tip) {
|
||
// Tips 版本
|
||
tip.setStyle('display', 'block').store('tip:imgsource', imgSrc);
|
||
var tipContent = tip.getElement('.tip-text');
|
||
if (!tipContent) {
|
||
tipContent = new Element('div', {'class': 'tip-text'}).inject(tip.getElement('.tip') || tip);
|
||
}
|
||
tipContent.set('html', ' ').addClass('loading');
|
||
this._loadImage(imgSrc, tipContent);
|
||
}
|
||
|
||
// 触发显示回调
|
||
if (this.options.onShow) {
|
||
this.options.onShow.call(this, tip || this.tip, element);
|
||
}
|
||
},
|
||
|
||
// 隐藏事件处理
|
||
_onHide: function(tip, element) {
|
||
this.isActive = false;
|
||
element = element || this.element;
|
||
if (element) element.removeClass('magnifier-active');
|
||
|
||
if (this.tip.hide) {
|
||
this.tip.hide();
|
||
}
|
||
|
||
// 触发隐藏回调
|
||
if (this.options.onHide) {
|
||
this.options.onHide.call(this, tip || this.tip, element);
|
||
}
|
||
},
|
||
|
||
// 加载图片
|
||
_loadImage: function(imgSrc, container) {
|
||
if (typeof Asset !== 'undefined' && Asset.image) {
|
||
// 使用 Asset.image 加载
|
||
Asset.image(imgSrc, {
|
||
onload: function() {
|
||
if (this.src != container.retrieve('tip:imgsource')) return;
|
||
|
||
// 计算智能缩放尺寸
|
||
var zoomedSize = this._calculateZoomSize(this.width, this.height);
|
||
|
||
container.empty().adopt(this).removeClass('loading');
|
||
this.setStyles({
|
||
'width': zoomedSize.width + 'px',
|
||
'height': zoomedSize.height + 'px',
|
||
'max-width': '100%',
|
||
'max-height': '100%',
|
||
'object-fit': 'contain'
|
||
});
|
||
|
||
// 触发加载完成回调
|
||
if (this.options.onLoad) {
|
||
this.options.onLoad.call(this, this, zoomedSize);
|
||
}
|
||
}.bind(this),
|
||
onerror: function() {
|
||
container.set('html', '图片加载失败').removeClass('loading');
|
||
}
|
||
});
|
||
} else {
|
||
// 简化版本:直接创建图片元素
|
||
var img = new Element('img', {
|
||
'src': imgSrc,
|
||
'style': 'max-width:100%;max-height:100%;width:auto;height:auto;object-fit:contain;border-radius:6px;'
|
||
});
|
||
|
||
container.empty().adopt(img);
|
||
|
||
// 图片加载完成后计算尺寸
|
||
img.addEvent('load', function() {
|
||
var zoomedSize = this._calculateZoomSize(img.width, img.height);
|
||
img.setStyles({
|
||
'width': zoomedSize.width + 'px',
|
||
'height': zoomedSize.height + 'px'
|
||
});
|
||
|
||
if (this.options.onLoad) {
|
||
this.options.onLoad.call(this, img, zoomedSize);
|
||
}
|
||
}.bind(this));
|
||
}
|
||
},
|
||
|
||
// 计算智能缩放尺寸
|
||
_calculateZoomSize: function(originalWidth, originalHeight) {
|
||
var maxW = this.options.maxWidth;
|
||
var maxH = this.options.maxHeight;
|
||
var maxScale = this.options.maxScale;
|
||
|
||
// 计算缩放比例
|
||
var scaleX = maxW / originalWidth;
|
||
var scaleY = maxH / originalHeight;
|
||
var scale = Math.min(scaleX, scaleY, maxScale);
|
||
|
||
// 限制最大缩放倍数
|
||
if (scale > maxScale) {
|
||
scale = maxScale;
|
||
}
|
||
|
||
return {
|
||
width: Math.round(originalWidth * scale),
|
||
height: Math.round(originalHeight * scale)
|
||
};
|
||
},
|
||
|
||
// 绑定事件
|
||
_attachEvents: function() {
|
||
// 鼠标移动时更新位置
|
||
this.element.addEvent('mousemove', function(e) {
|
||
if (this.isActive && this.tip) {
|
||
this._updatePosition(e);
|
||
}
|
||
}.bind(this));
|
||
},
|
||
|
||
// 更新位置
|
||
_updatePosition: function(event) {
|
||
if (!this.tip) return;
|
||
|
||
var tipElement = this.tip.tip || this.tip.element;
|
||
if (!tipElement) return;
|
||
|
||
var offset = this.options.offset;
|
||
|
||
tipElement.setStyles({
|
||
'left': (event.pageX + offset.x) + 'px',
|
||
'top': (event.pageY + offset.y) + 'px'
|
||
});
|
||
},
|
||
|
||
// 添加样式
|
||
_addStyles: function() {
|
||
// 检查是否已经添加了样式
|
||
if (document.getElementById('image-magnifier-styles')) return;
|
||
|
||
var styleElement = new Element('style', {
|
||
'id': 'image-magnifier-styles',
|
||
'html': `
|
||
.magnifier-tip { position: fixed !important; z-index: 999999 !important; background: transparent !important; border: none !important; padding: 0 !important; max-width: 600px !important; max-height: 600px !important; overflow: hidden !important; box-shadow: 0 4px 20px rgba(0,0,0,0.15) !important; border-radius: 6px !important; pointer-events: none !important; }
|
||
.magnifier-tip img { max-width: 100% !important; max-height: 100% !important; width: auto !important; height: auto !important; object-fit: contain !important; border-radius: 6px !important; display: block !important; }
|
||
.magnifier-active { opacity: 0.8 !important; transition: opacity 0.2s ease-in-out !important; cursor: zoom-out !important; }
|
||
img[rel], img[data-src], img.zoomable { cursor: zoom-in !important; transition: opacity 0.2s ease-in-out !important; }
|
||
img[rel]:hover, img[data-src]:hover, img.zoomable:hover { opacity: 0.9 !important; }
|
||
`
|
||
});
|
||
|
||
document.head.appendChild(styleElement);
|
||
},
|
||
|
||
// 更新配置
|
||
updateOptions: function(newOptions) {
|
||
Object.merge(this.options, newOptions);
|
||
|
||
// 重新创建提示框
|
||
if (this.tip) {
|
||
this.tip.detach();
|
||
}
|
||
this._createTip();
|
||
this._attachEvents();
|
||
},
|
||
|
||
// 销毁
|
||
destroy: function() {
|
||
if (this.tip) {
|
||
this.tip.detach();
|
||
this.tip = null;
|
||
}
|
||
this.element.removeClass('magnifier-active');
|
||
this.isActive = false;
|
||
},
|
||
|
||
// 强制隐藏
|
||
hideTips: function() {
|
||
if (this.tip && this.tip.hide) {
|
||
this.tip.hide();
|
||
}
|
||
}
|
||
});
|
||
|
||
// 静态方法:批量应用
|
||
ImageMagnifier.applyToElements = function(selector, options) {
|
||
var elements = $$(selector);
|
||
var magnifiers = [];
|
||
|
||
elements.each(function(element) {
|
||
magnifiers.push(new ImageMagnifier(element, options));
|
||
});
|
||
|
||
return magnifiers;
|
||
};
|
||
|
||
// 导出到全局
|
||
window.ImageMagnifier = ImageMagnifier;
|
||
|
||
// 保持向后兼容的全局函数
|
||
var magnifierTip = null;
|
||
var offsetX = 30;
|
||
var offsetY = -20;
|
||
|
||
// 显示放大镜 - 全局函数,可在HTML中直接调用
|
||
function showImageMagnifier(event, element) {
|
||
if (magnifierTip) {
|
||
magnifierTip.remove();
|
||
magnifierTip = null;
|
||
}
|
||
|
||
magnifierTip = document.createElement('div');
|
||
magnifierTip.className = 'magnifier-tip';
|
||
magnifierTip.style.cssText = 'position:fixed;z-index:999999;background:transparent;border:none;padding:0;max-width:400px;max-height:300px;overflow:hidden;box-shadow:0 4px 12px rgba(0,0,0,0.15);border-radius:4px;pointer-events:none;';
|
||
|
||
var magnifiedImg = document.createElement('img');
|
||
magnifiedImg.src = element.getAttribute('rel') || element.src || element.getAttribute('data-src');
|
||
magnifiedImg.style.cssText = 'max-width:400px;max-height:300px;width:auto;height:auto;object-fit:contain;border-radius:4px;';
|
||
|
||
magnifierTip.appendChild(magnifiedImg);
|
||
document.body.appendChild(magnifierTip);
|
||
|
||
updateImageMagnifierPosition(event);
|
||
}
|
||
|
||
// 隐藏放大镜 - 全局函数,可在HTML中直接调用
|
||
function hideImageMagnifier() {
|
||
if (magnifierTip) {
|
||
magnifierTip.remove();
|
||
magnifierTip = null;
|
||
}
|
||
}
|
||
|
||
// 更新放大镜位置 - 全局函数,可在HTML中直接调用
|
||
function updateImageMagnifierPosition(event) {
|
||
if (!magnifierTip) return;
|
||
magnifierTip.style.left = (event.pageX + offsetX) + 'px';
|
||
magnifierTip.style.top = (event.pageY + offsetY) + 'px';
|
||
}
|
||
|
||
// 导出全局函数
|
||
window.showImageMagnifier = showImageMagnifier;
|
||
window.hideImageMagnifier = hideImageMagnifier;
|
||
window.updateImageMagnifierPosition = updateImageMagnifierPosition;
|
||
|
||
// 自动初始化:为所有带有 rel 或 data-src 属性的图片添加放大镜
|
||
document.addEvent('domready', function() {
|
||
var autoImages = $$('img[rel], img[data-src]');
|
||
if (autoImages.length > 0) {
|
||
console.log('ImageMagnifier: 自动为', autoImages.length, '张图片添加放大镜功能');
|
||
autoImages.forEach(function(img) {
|
||
if (!img.hasClass('magnifier-initialized')) {
|
||
img.addClass('magnifier-initialized');
|
||
new ImageMagnifier(img);
|
||
}
|
||
});
|
||
}
|
||
});
|
||
|
||
})();
|
||
|