Home » Code » 四大旗舰盲评前端效果

四大旗舰盲评前端效果

接上篇《WordPress后台表格数据展示类WP_Table_List的使用》,上篇主要是后台的一些增删改,这一篇来说说前台的查看效果。

很明显,需要4张同屏查看才能很好的看出差别,还需要对图片进行100%放大,随意移动等。首先创建一个遮罩,在它的上边摆4张照片,一开始四个角各一张,这对宽度大于高度的图片是比较好的同时查看方式。但有的图片可能是高度大于宽度,这时就是水平摆4张更好了,因此需要按钮快速切换两种排列方式。快速放大到100%的按钮,放到每张图片右上解即可,快速缩小呢?缩小到多少?感觉没有必要,直接选择排列方式恢复即可。另外,如果不想一下子放大到100%,可以双击放大,每次放大一点儿,如50px。当然,还得有个退出遮罩的按钮。

实现这个效果的过程遇到的一个难点是正方形四个角各一张排列时候如何确定4张图片的left&top&width&height,因为要移动肯定是要绝对定位并设置好这4个值的,图片真实的大小有可能比1/4的屏幕大,或者小,在1/4的角落里,不说垂直居中至少也得水平居中吧。没什么办法,只能是给图片一个父层,父层固定是1/4屏幕大小,图片在里边居中最大宽高100%,这样就省去了计算那4个值,动态定位好后再获取那4个值设置上,简单好多。

另一个难点是判断4张图片都加载完成,因为要展示遮罩层,必须等大图加载完成后再放到那4个位置里边,还得将原始宽高存储起来便于快速100%放大 。之前有写过相关文章,实现起来也不难,这里获得原始宽高就当是加载完成了,事实证明没什么问题。

再有就是代码的组织能力,感觉很弱,一个“类”,封装得不够漂亮。一开始想要如何如何灵活,如何如何尽量的多变量可配置,搞得很难下手,顾虑太多。其实,一开始可以适当的“写死”,将主要的功能都实现后再考虑灵活的事,会更好。

以下是组织了挺久的代码,也只有300出头行,效果嘛,还是比那岩用的问卷星那个要强点的。

;(function(window, document, $) {
	//创建模态框
	var modalItemBoxClass = 'item-box';
	var modalItemBoxSelector = '.' + modalItemBoxClass;
	var MODAL_HTML = '<div id="modal">';
	for (var i = 0; i < 4; i++) {
		MODAL_HTML += '<div class="' + modalItemBoxClass + '"></div>';
	}
	MODAL_HTML += '</div>';

	var $body = $('body');
	var $doc = $(document);
	var $modal = $(MODAL_HTML).appendTo($body),
		$esc = $('<button class="btn btn-danger btn-sm" id="esc">退出</button>').appendTo($modal),
		$resetRect = $('<button class="btn btn-primary btn-sm" id="reset-rect">矩形</button>').appendTo($modal),
		$resetInline = $('<button class="btn btn-primary btn-sm" id="reset-inline">水平</button>').appendTo($modal),
		$modalItemBox = $modal.find(modalItemBoxSelector);

	var $loading = $('<div class="loading" id="loading"><p class="">请求中,请稍候...</p></div>').appendTo($body),
		$mask = $('<div class="mask" id="mask"></div>').appendTo($body);

	//定义所需变量
	var winWidth, //window可视宽
		winHeight, //window可视高
		imgInfo = {}, //4张图片原始宽高
		rectInfo = {}, //4张图片矩形排列时的left&top&width&height
		inlineInfo = {}, //4张图片水平排列时的left&top&width&height
		maxZindex = 100, //最大zIndex
		$activeImgBox, //当前活动图片父层jQ对象
		$activeImg, //当前活动图片jQ对象
		activeImgBox, //当前活动图片父层DOM对象
		activeImg, //当前活动图片DOM对象
		_offsetLeft, //鼠标按下处PageX与目标offsetLeft值之差
		_offsetTop; //鼠标按下处PageY与目标offsetTop值之差

	//为模态框绑定事件
	$modal.on({
		'mouseover': function(e) {
			$(this).css('outline', '1px solid red');
		},
		'mouseout': function(e) {
			$(this).removeAttr('style');
		},
		'mousedown': function(e) {
			$activeImg = $(this);
			activeImg = this;
			$activeImgBox = $activeImg.closest(modalItemBoxSelector);
			activeImgBox = $activeImgBox[0];
			maxZindex++;

			setItemBoxPosition($activeImg, $activeImgBox);

			var offset = $activeImgBox.position();
			_offsetTop = e.pageY - offset.top;
			_offsetLeft = e.pageX - offset.left;
			$doc.on('mousemove', mousemove);
			$doc.on('mouseup', mouseup);
		},
		'dblclick': function(e) {
			var $img = $(this);
			$imgBox = $img.closest(modalItemBoxSelector);
			var scale = $imgBox.width() / $imgBox.height();
			var dw = 50;
			var dh = dw / scale;
			$imgBox.animate({
				'width': '+=' + dw + 'px',
				'height': '+=' + dh + 'px',
			});
		},
		'selectstart': function(e) {
			e.preventDefault();
			e.returnValue = false;
		},
		'dragstart': function(e) {
			e.preventDefault();
			e.returnValue = false;
		}
	},
	'img');

	$modal.on('click', '.zoom',
	function(e) {
		var $btn = $(this);
		var index = parseInt($btn.next().text()) - 1;
		var $box = $btn.closest(modalItemBoxSelector);
		$box.css({
			width: imgInfo[index].width,
			height: imgInfo[index].height,
			zIndex: ++maxZindex,
			left: (winWidth - imgInfo[index].width) / 2,
			top: (winHeight - imgInfo[index].height) / 2,
		});
	});

	$esc.on('click', hideModal);

	$resetRect.on('click', resetRect);

	$resetInline.on('click', resetInline);

	//绝对定位设置left、top值保持不动
	function setItemBoxPosition($img, $box) {
		if (!$box) {
			$box = $img.closest(modalItemBoxSelector);
		}
		var box = $box[0];
		var img = $img[0];
		$box.css({
			'z-index': maxZindex,
			'width': $img.outerWidth() + parseInt($box.css('paddingLeft')) + parseInt($box.css('paddingRight')),
			'height': $img.outerHeight() + parseInt($box.css('paddingTop')) + parseInt($box.css('paddingBottom')),
			'left': img.offsetLeft + box.offsetLeft - parseInt($box.css('paddingLeft')),
			'top': img.offsetTop + box.offsetTop - parseInt($box.css('paddingTop')),
		});
	}

	//鼠标移动图片处理函数
	function mousemove(e) {
		console.log('mousemove');
		$activeImgBox.css({
			'left': e.pageX - _offsetLeft,
			'top': e.pageY - _offsetTop,
		})
	}

	//鼠标松开处理函数
	function mouseup(e) {
		console.log('mouseup');
		$doc.off('mousemove', mousemove);
		$doc.off('mouseup', mouseup);
	}

	//隐藏模态框,重置一些数据
	function hideModal() {
		$mask.fadeOut();
		$modal.fadeOut(function() {
			$modalItemBox.removeAttr('style');
		});
		rectInfo = {};
		inlineInfo = {};
		imgInfo = {};
		winWidth = winHeight = 0;
		maxZindex = 100;
	}

	//重新设置为矩形排列
	function resetRect() {
		$modalItemBox.each(function(index) {
			$(this).css({
				'width': rectInfo[index]['width'],
				'height': rectInfo[index]['height'],
				'left': rectInfo[index]['left'],
				'top': rectInfo[index]['top'],
			})
		})
	}

	//重新设置为水平排列
	function resetInline() {
		if ($.isEmptyObject(inlineInfo)) {
			console.log('resetInfo---do');
			var ow = (winWidth - 76) / 4;
			var h = winHeight;
			$modalItemBox.each(function(index) {
				$(this).css({
					'width': ow,
					'height': h,
					'left': index * ow,
					'top': 0,
				});
			});
			$modal.find('img').each(function(index) {
				var $img = $(this);
				var $box = $img.closest(modalItemBoxSelector);
				var box = $box[0];
				var height = $img.height();
				$box.css('top', (winHeight - height) / 2);
				setItemBoxPosition($img, $box);
				inlineInfo[index] = box.getBoundingClientRect();
			});
		} else {
			console.log('resetInfo---cache');
			$modalItemBox.each(function(index) {
				$(this).css({
					'width': inlineInfo[index]['width'],
					'height': inlineInfo[index]['height'],
					'left': inlineInfo[index]['left'],
					'top': inlineInfo[index]['top'],
				});
			})
		}
	}

	//多张图片大小获取与加载
	function imageLoaded(imgSrcArr, callback) {
		var total = imgSrcArr.length;
		var count = 0;
		for (var i = 0; i < total; i++) { 
			(function(i) {
				var imgObj = new Image();
				imgObj.src = imgSrcArr[i];
				if (imgObj.complete) {
					imgInfo[i] = {
						width: imgObj.width,
						height: imgObj.height
					};
					count++;
				} else {
					imgObj['t'] = setInterval(function() {
						if (imgObj.width || imgObj.height) {
							imgInfo[i] = {
								width: imgObj.width,
								height: imgObj.height
							};
							count++;
							clearInterval(imgObj['t']);
						}
					},
					20);
				}
			})(i);
		}
		var callbackInterval = setInterval(function() {
			if (count >= total) {
				clearInterval(callbackInterval);
				callback();
			}
		},
		50);
	}

	//图片填充模态框
	function renderModal(imageSrcArr) {
		var actionSpan = '<span class="zoom">放大</span>';
		$modalItemBox.each(function(index) {
			$(this).html('<img src="' + imageSrcArr[index] + '" />' + actionSpan + '<span class="num">' + (index + 1) + '</span>');
		});
		imageLoaded(imageSrcArr,
		function() {
			console.log('sbsb');
			$loading.hide();
			$modal.show();
			initModalBoxPosition();
		})
	}

	//图片填充模态 框后定位它们的位置,同时存储矩形排列位置信息
	function initModalBoxPosition() {
		winWidth = document.documentElement.clientWidth;
		winHeight = document.documentElement.clientHeight;
		$modal.css({
			width: winWidth,
			height: winHeight,
		});
		var leftTop = [[0, 0], [winWidth / 2, 0], [0, winHeight / 2], [winWidth / 2, winHeight / 2]];
		$modalItemBox.each(function(index) {
			var $box = $(this);
			$box.css({
				'left': leftTop[index][0],
				'top': leftTop[index][1],
			});

		});
		setTimeout(function() {
			$modal.find('img').each(function(index) {
				console.log(this);
				setItemBoxPosition($(this));
				rectInfo[index] = this.parentElement.getBoundingClientRect();
			})
		},
		300);
	}

	//通过src获取图片的完整src
	function getSrc(dataSrc, imgDom) {
		var baseURI = imgDom.baseURI;
		if (dataSrc.indexOf('http') === 0) {
			//有http
			return dataSrc;
		} else {
			//没有http,拼凑完整地址
			if (dataSrc.indexOf('/') === 0) {
				dataSrc = dataSrc.substring(1);
			}
			return baseURI+'/'+dataSrc;
		}
	}

	//定义类
	function SiDaQiJian(options) {
		var defaults = {
			containerId: '',
			groupSelector: '',
			itemSelector: '',
			originalAttr: '',
			iframe: '',
		};
		var settings = $.extend({}, defaults, options);
		if (!settings.containerId || !settings.groupSelector || !settings.originalAttr || !settings.itemSelector) {
			throw new Error('参数不全');
			return;
		}
		if (settings.iframe) {
			if (!settings.iframe.tagName || settings.iframe.tagName !== 'IFRAME') {
				throw new Error('iframe参数错误');
				return;
			}
			var __win = settings.iframe.contentWindow;
			var iframeDoc = settings.iframe.contentDocument;
			__win.onload = function() {
				var $container = $('#'+settings.containerId, iframeDoc);
				$container.on('click', settings.itemSelector, itemClick);
			}
		} else {
			var __win = window;
			__win.onload = function() {
				var $container = $('#'+settings.containerId, $doc);
				$container.on('click', settings.itemSelector, itemClick);
			}
		}

		function itemClick() {
			$mask.fadeIn();
			$loading.fadeIn();
			var imageSrcArr = $(this).closest(settings.groupSelector).find(settings.itemSelector).map(function() {
				return getSrc(this.getAttribute(settings.originalAttr), this);
			}).toArray();
			renderModal(imageSrcArr);
		}

	}
	window.SiDaQiJian = SiDaQiJian;
})(window, document, jQuery);

至于使用,需要引入一些CSS和上边这个js代码文件,然后在后边实例化即可,如:

new SiDaQiJian({
	containerId: 'box',
	groupSelector: '.row',
	itemSelector: 'img',
	originalAttr: 'data-original'
})

我这里还考虑了iframe,也就是图片是来自iframe,在父窗口引入Js和CSS实现查看的效果。通过iframe参数传递一个的iframe DOM对象即可。

有一个DEMO,可以点击这里查看

Leave a Reply

Your email address will not be published. Required fields are marked *

*

Time limit is exhausted. Please reload CAPTCHA.