;(function ($, window) {
let ele = null,
exzoom_img_box = null,
boxwidth = null,
boxheight = null,
exzoom_img_ul_outer = null,//用于限制 ul 宽度,又不影响放大镜区域
exzoom_img_ul = null,
exzoom_img_ul_position = 0,//循环图片区域的边距,用于移动时跟随光标
exzoom_img_ul_width = 0,//循环图片区域的最大宽度
exzoom_img_ul_max_margin = 0,//循环图片区域的最大外边距,应该是图片数量减一乘以boxwidth
exzoom_nav = null,
exzoom_nav_inner = null,
navhightclass = "current",//当前图片的类,
exzoom_navspan = null,
navheightwithborder = null,
images = null,
exzoom_prev_btn = null,//导航上一张图片
exzoom_next_btn = null,//导航下一张图片
imgnum = 0,//图片的数量
imgindex = 0,//当前图片的索引
imgarr = [],//图片属性的数字
exzoom_zoom = null,
exzoom_main_img = null,
exzoom_zoom_outer = null,
exzoom_preview = null,//预览区域
exzoom_preview_img = null,//预览区域的图片
autoplayinterval = null,//用于控制自动播放的间隔时间
startx = 0,//移动光标的起始坐标
starty = 0,//移动光标的起始坐标
endx = 0,//移动光标的终止坐标
endy = 0,//移动光标的终止坐标
g = {},//全局变量
defaults = {
"navwidth": 60,//列表每个宽度,该版本中请把宽高填写成一样
"navheight": 60,//列表每个高度,该版本中请把宽高填写成一样
"navitemnum": 5,//列表显示个数
"navitemmargin": 7,//列表间隔
"navborder": 1,//列表边框,没有边框填写0,边框在css中修改
"autoplay": true,//是否自动播放
"autoplaytimeout": 2000,//播放间隔时间
};
let methods = {
init: function (options) {
let opts = $.extend({}, defaults, options);
ele = this;
exzoom_img_box = ele.find(".exzoom_img_box");
exzoom_img_ul = ele.find(".exzoom_img_ul");
exzoom_nav = ele.find(".exzoom_nav");
exzoom_prev_btn = ele.find(".exzoom_prev_btn");//缩略图导航上一张按钮
exzoom_next_btn = ele.find(".exzoom_next_btn");//缩略图导航下一张按钮
//todo 以后可以分开宽度和高度的限制
boxheight = boxwidth = ele.outerwidth(); //在小屏幕中,有 padding 的情况下,计算不准,需要手动指定 ele 的宽度
// console.log("boxwidth::" + boxwidth);
// console.log("ele.parent().width()::" + ele.parent().width());
// console.log("ele.parent().outerwidth()::" + ele.parent().outerwidth());
// console.log("ele.parent().innerwidth()::" + ele.parent().innerwidth());
//todo 缩略图导航的高度和宽度可以改为根据 导航栏宽度 和 navitemnum 计算出来,但是对于不同尺寸的不好处理
g.navwidth = opts.navwidth;
g.navheight = opts.navheight;
g.navborder = opts.navborder;
g.navitemmargin = opts.navitemmargin;
g.navitemnum = opts.navitemnum;
g.autoplay = opts.autoplay;
g.autoplaytimeout = opts.autoplaytimeout;
images = exzoom_img_box.find("img");
imgnum = images.length;//图片的数量
checkloadedallimages(images)//检查图片是否健在完成,全部加载完成的会执行初始化
},
prev: function () { //上一张图片
moveleft()
},
next: function () { //下一张图片
moveright();
},
setimg: function () { //设置大图
let url = arguments[0];
getimagesize(url, function (width, height) {
exzoom_preview_img.attr("src", url);
exzoom_main_img.attr("src", url);
//todo 未测试
//判断已有的图片数量是否合最初的一致,不是的话就先删除最后一个
if (exzoom_img_ul.find("li").length === imgnum + 1) {
exzoom_img_ul.find("li:last").remove();
}
exzoom_img_ul.append('
' +
'
');
let image_prop = copute_image_prop(url, width, height);
previewimg(image_prop);
});
},
};
$.fn.extend({
"exzoom": function (method, options) {
if (arguments.length === 0 || (typeof method === 'object' && !options)) {
if (this.length === 0) {
// alert("调用 jquery.exzomm 时的选择器为空");
$.error('selector is empty when call jquery.exzomm');
} else {
return methods.init.apply(this, arguments);
}
} else if (methods[method]) {
return methods[method].apply(this, array.prototype.slice.call(arguments, 1));
} else {
// alert("调用了 jquery.exzomm 中不存在的方法");
$.error('method ' + method + 'does not exist on jquery.exzomm');
}
}
});
/**
* 初始化
*/
function init() {
exzoom_img_box.append("");
exzoom_nav.append("");
exzoom_img_ul_outer = exzoom_img_box.find(".exzoom_img_ul_outer");
exzoom_nav_inner = exzoom_nav.find(".exzoom_nav_inner");
//把 exzoom_img_ul 移动到 exzoom_img_ul_outer 里
exzoom_img_ul_outer.append(exzoom_img_ul);
//循环所有图片,计算尺寸,添加缩略图导航
for (let i = 0; i < imgnum; i++) {
imgarr[i] = copute_image_prop(images.eq(i));//记录图片的尺寸属性等
console.log(imgarr[i]);
let li = exzoom_img_ul.find("li").eq(i);
li.css("width", boxwidth);//设置图片上级的 li 元素的宽度
li.find("img").css({
"margin-top": imgarr[i][5],
"width": imgarr[i][3]
});
}
//缩略图导航
exzoom_navspan = exzoom_nav.find("span");
navheightwithborder = g.navborder * 2 + g.navheight;
g.exzoom_navwidth = (navheightwithborder + g.navitemmargin) * g.navitemnum;
g.exzoom_nav_innerwidth = (navheightwithborder + g.navitemmargin) * imgnum;
exzoom_navspan.eq(imgindex).addclass(navhightclass);
exzoom_nav.css({
"height": navheightwithborder + "px",
"width": boxwidth - exzoom_prev_btn.width() - exzoom_next_btn.width(),
});
exzoom_nav_inner.css({
"width": g.exzoom_nav_innerwidth + "px"
});
exzoom_navspan.css({
"margin-left": g.navitemmargin + "px",
"width": g.navwidth + "px",
"height": g.navheight + "px",
});
//设置滚动区域的宽度
exzoom_img_ul_width = boxwidth * imgnum;
exzoom_img_ul_max_margin = boxwidth * (imgnum - 1);
exzoom_img_ul.css("width", exzoom_img_ul_width);
//添加放大镜
exzoom_img_box.append(`
`);
exzoom_zoom = exzoom_img_box.find(".exzoom_zoom");
exzoom_main_img = exzoom_img_box.find(".exzoom_main_img");
exzoom_zoom_outer = exzoom_img_box.find(".exzoom_zoom_outer");
exzoom_preview = exzoom_img_box.find(".exzoom_preview");
exzoom_preview_img = exzoom_img_box.find(".exzoom_preview_img");
//设置大图和预览图区域
exzoom_img_box.css({
"width": boxheight + "px",
"height": boxheight + "px",
});
exzoom_img_ul_outer.css({
"width": boxheight + "px",
"height": boxheight + "px",
});
exzoom_preview.css({
"width": boxheight + "px",
"height": boxheight + "px",
"left": boxheight + 5 + "px",//添加个边距
});
previewimg(imgarr[imgindex]);
autoplay();//自动播放
bindingevent();//绑定事件
}
/**
* 检测图片是否加载完成
* @param images
*/
function checkloadedallimages(images) {
let timer = setinterval(function () {
let loaded_images_counter = 0;
let all_images_num = images.length;
images.each(function () {
if (this.complete) {
loaded_images_counter++;
}
});
if (loaded_images_counter === all_images_num) {
clearinterval(timer);
init();
}
}, 100)
}
/**
* 获取光标坐标,如果是 touch 事件,只处理第一个
*/
function getcursorcoords(event) {
let e = event || window.event;
let coords_data = e, //记录坐标的数据,默认为 event 本身,移动端的 touch 会修改
x,//x 轴
y;//y 轴
if (e["touches"] !== undefined) {
if (e["touches"].length > 0) {
coords_data = e["touches"][0];
}
}
x = coords_data.clientx || coords_data.pagex;
y = coords_data.clienty || coords_data.pagey;
return {'x': x, 'y': y}
}
/**
* 检查移动端触摸滑动的位置
*/
function checknewpositionlimit(new_position) {
if (-new_position > exzoom_img_ul_max_margin) {
//限制向右的范围
new_position = -exzoom_img_ul_max_margin;
imgindex = 0;//向右超出范围的回到第一个
} else if (new_position > 0) {
//限制向左的范围
new_position = 0;
}
return new_position
}
/**
* 绑定各种事件
*/
function bindingevent() {
//移动端大图区域的 touchend 事件
exzoom_img_ul.on("touchstart", function (event) {
let coords = getcursorcoords(event);
startx = coords.x;
starty = coords.y;
let left = exzoom_img_ul.css("left");
exzoom_img_ul_position = parseint(left);
window.clearinterval(autoplayinterval);//停止自动播放
});
//移动端大图区域的 touchmove 事件
exzoom_img_ul.on("touchmove", function (event) {
let coords = getcursorcoords(event);
let new_position;
endx = coords.x;
endy = coords.y;
//只跟随光标移动
new_position = exzoom_img_ul_position + endx - startx;
new_position = checknewpositionlimit(new_position);
exzoom_img_ul.css("left", new_position);
});
//移动端大图区域的 touchend 事件
exzoom_img_ul.on("touchend", function (event) {
//触屏滑动,根据移动方向按倍数对齐元素
console.log(endx < startx);
if (endx < startx) {
//向左滑动
moveright();
} else if (endx > startx) {
//向右滑动
moveleft();
}
autoplay();//恢复自动播放
});
//大屏幕在放大区域点击,判断向左还是向右移动
exzoom_zoom_outer.on("mousedown", function (event) {
let coords = getcursorcoords(event);
startx = coords.x;
starty = coords.y;
let left = exzoom_img_ul.css("left");
exzoom_img_ul_position = parseint(left);
});
exzoom_zoom_outer.on("mouseup", function (event) {
let offset = ele.offset();
if (startx - offset.left < boxwidth / 2) {
//在放大镜的左半部分点击
moveleft();
} else if (startx - offset.left > boxwidth / 2) {
//在放大镜的右半部分点击
moveright();
}
});
//进入 exzoom 停止自动播放
ele.on("mouseenter", function () {
window.clearinterval(autoplayinterval);//停止自动播放
});
//离开 exzoom 开始自动播放
ele.on("mouseleave", function () {
autoplay();//恢复自动播放
});
//大屏幕进入大图区域
exzoom_zoom_outer.on("mouseenter", function () {
exzoom_zoom.css("display", "block");
exzoom_preview.css("display", "block");
});
//大屏幕在大图区域移动
exzoom_zoom_outer.on("mousemove", function (e) {
let width_limit = exzoom_zoom.width() / 2,
max_x = exzoom_zoom_outer.width() - width_limit,
max_y = exzoom_zoom_outer.height() - width_limit,
current_x = e.pagex - exzoom_zoom_outer.offset().left,
current_y = e.pagey - exzoom_zoom_outer.offset().top,
move_x = current_x - width_limit,
move_y = current_y - width_limit;
if (current_x <= width_limit) {
move_x = 0;
}
if (current_x >= max_x) {
move_x = max_x - width_limit;
}
if (current_y <= width_limit) {
move_y = 0;
}
if (current_y >= max_y) {
move_y = max_y - width_limit;
}
exzoom_zoom.css({"left": move_x + "px", "top": move_y + "px"});
exzoom_preview_img.css({
"left": -move_x * exzoom_preview.width() / exzoom_zoom.width() + "px",
"top": -move_y * exzoom_preview.width() / exzoom_zoom.width() + "px"
});
});
//大屏幕离开大图区域
exzoom_zoom_outer.on("mouseleave", function () {
exzoom_zoom.css("display", "none");
exzoom_preview.css("display", "none");
});
//大屏幕光宝进入放大预览区域
exzoom_preview.on("mouseenter", function () {
exzoom_zoom.css("display", "none");
exzoom_preview.css("display", "none");
});
//缩略图导航
exzoom_next_btn.on("click", function () {
moveright();
});
exzoom_prev_btn.on("click", function () {
moveleft();
});
exzoom_navspan.hover(function () {
imgindex = $(this).index();
move(imgindex);
});
}
/**
* 聚焦在导航图片上,左右移动都会调用
* @param direction: 方向,right | left,必填
*/
function move(direction) {
if (typeof direction === "undefined") {
alert("exzoom 中的 move 函数的 direction 参数必填");
}
//如果超出图片数量了,返回第一张
if (imgindex > imgarr.length - 1) {
imgindex = 0;
}
//设置高亮
exzoom_navspan.eq(imgindex).addclass(navhightclass).siblings().removeclass(navhightclass);
//判断缩略图导航是否需要重新设置偏移量
let exzoom_nav_width = exzoom_nav.width();
let nav_item_width = g.navitemmargin + g.navwidth + g.navborder * 2; // 单个导航元素的宽度
let new_nav_offset = 0;
//直接对比当前索引的图片占据的宽度和exzoom的宽度的差作为偏移量即可
let temp = nav_item_width * (imgindex + 1);
if (temp > exzoom_nav_width) {
new_nav_offset = boxwidth - temp;
}
exzoom_nav_inner.css({
"left": new_nav_offset
});
//切换大图
let new_position = -boxwidth * imgindex;
//在 animate 方法前先调用 stop() ,避免反应迟钝
new_position = checknewpositionlimit(new_position);
exzoom_img_ul.stop().animate({"left": new_position}, 500);
//处理放大区域
previewimg(imgarr[imgindex]);
}
/**
* 导航向右
*/
function moveright() {
imgindex++;//先增加 index,后面判断范围
if (imgindex > imgnum) {
imgindex = imgnum;
}
move("right");
}
/**
* 导航向左
*/
function moveleft() {
imgindex--;//先减少 index,后面判断范围
if (imgindex < 0) {
imgindex = 0;
}
move("left");
}
/**
* 自动播放
*/
function autoplay() {
if (g.autoplay) {
autoplayinterval = window.setinterval(function () {
if (imgindex >= imgnum) {
imgindex = 0;
}
imgindex++;
move("right");
}, g.autoplaytimeout);
}
}
/**
* 预览图片
*/
function previewimg(image_prop) {
if (image_prop === undefined) {
return
}
exzoom_preview_img.attr("src", image_prop[0]);
exzoom_main_img.attr("src", image_prop[0])
.css({
"width": image_prop[3] + "px",
"height": image_prop[4] + "px"
});
exzoom_zoom_outer.css({
"width": image_prop[3] + "px",
"height": image_prop[4] + "px",
"top": image_prop[5] + "px",
"left": image_prop[6] + "px",
"position": "relative"
});
exzoom_zoom.css({
"width": image_prop[7] + "px",
"height": image_prop[7] + "px"
});
exzoom_preview_img.css({
"width": image_prop[8] + "px",
"height": image_prop[9] + "px"
});
}
/**
* 获得图片的真实尺寸
* @param url
* @param callback
*/
function getimagesize(url, callback) {
let img = new image();
img.src = url;
// 如果图片被缓存,则直接返回缓存数据
if (typeof callback !== "undefined") {
if (img.complete) {
callback(img.width, img.height);
} else {
// 完全加载完毕的事件
img.onload = function () {
callback(img.width, img.height);
}
}
} else {
return {
width: img.width,
height: img.height
}
}
}
/**
* 计算图片属性
* @param image : jquery 对象或 图片url地址
* @param width : image 为图片url地址时指定宽度
* @param height : image 为图片url地址时指定高度
* @returns {array}
*/
function copute_image_prop(image, width, height) {
let src;
let res = [];
if (typeof image === "string") {
src = image;
} else {
src = image.attr("src");
let size = getimagesize(src);
width = size.width;
height = size.height;
}
res[0] = src;
res[1] = width;
res[2] = height;
let img_scale = res[1] / res[2];
if (img_scale === 1) {
res[3] = boxheight;//width
res[4] = boxheight;//height
res[5] = 0;//top
res[6] = 0;//left
res[7] = boxheight / 2;
res[8] = boxheight * 2;//width
res[9] = boxheight * 2;//height
exzoom_nav_inner.append(`
`);
} else if (img_scale > 1) {
res[3] = boxheight;//width
res[4] = boxheight / img_scale;
res[5] = (boxheight - res[4]) / 2;
res[6] = 0;//left
res[7] = res[4] / 2;
res[8] = boxheight * 2 * img_scale;//width
res[9] = boxheight * 2;//height
let top = (g.navheight - (g.navwidth / img_scale)) / 2;
exzoom_nav_inner.append(`
`);
} else if (img_scale < 1) {
res[3] = boxheight * img_scale;//width
res[4] = boxheight;//height
res[5] = 0;//top
res[6] = (boxheight - res[3]) / 2;
res[7] = res[3] / 2;
res[8] = boxheight * 2;//width
res[9] = boxheight * 2 / img_scale;
let top = (g.navwidth - (g.navheight * img_scale)) / 2;
exzoom_nav_inner.append(`
`);
}
return res;
}
// 闭包结束
})(jquery, window);