Files
OMS/app/desktop/statics/js_mini/image-magnifier.js
2025-12-28 23:13:25 +08:00

367 lines
14 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* 图片放大镜组件 - 完整版
* 基于 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);
}
});
}
});
})();