图片查看 ImagesViewer
项目中需要有图片的浏览功能。以前都是去网上找现成的插件,但是突然心血来潮,想自己写一个,于是乎把以前的代码拿来组合一下,在修修改改就完成了一个简单的版本。
话不多说,先上代码,再说问题。
2 var eventNames = {
3 touchstart: "touchstart",
4 touchmove: "touchmove",
5 touchend: "touchend",
6 touchcancel: "touchcancel"
7 };
8
9 var isTouchable = function () {
10 var iosDevices = ['iphone', 'ipad', 'ipod'];
11 var touchDevices = ['android', 'phone', 'blackbery'].concat(iosDevices);
12 var appVersion = navigator.appVersion.toLowerCase();
13 for (var i = 0; i < touchDevices.length; i++) {
14 if (appVersion.indexOf(touchDevices[i]) > -1) {
15 return true;
16 }
17 }
18 return false;
19 };
20
21 if (window.ImagesScroller) {
22 return;
23 }
24
25 window.ImagesScroller = function (wrapperSelector) {
26 this.$wrap = $(wrapperSelector);
27 this.$ul = this.$wrap.find("ul");
28 this.itemWidth = this.$wrap.width();
29 //this.itemHeight = this.$wrap.height();
30 this.itemWidth = this.itemWidth;
31 var $lis = this.$wrap.find("ul li");
32 $lis.width(this.itemWidth);
33 $lis.height(this.itemHeight);
34 this.count = $lis.length;
35 this.$ul.width(this.itemWidth * this.count);
36 this.$ul.height(this.itemWidth);
37 this.currentIndex = 0;
38 this._isMoving = false;
39 this.speed = 200;
40 this.onNext = null;
41 this.onPrev = null;
42 this.onChange = null;
43 this.onItemClick = null;
44 this.sensitivity = 2; // 1-9
45 this._isTouchable = isTouchable();
46 this._touchStartPosition = null;
47 this._touchEndPosition = null;
48 this._isHorizontal = null;
49 };
50
51 ImagesScroller.prototype = {
52 init: function () {
53 var me = this;
54 me.bindEvents();
55 },
56 bindEvents: function () {
57 var me = this;
58 if (me._isTouchable) {
59 me._bindTouchEvents();
60 } else {
61 me._enableMouseDrag();
62 }
63 },
64 _bindTouchEvents: function () {
65 var me = this;
66 me.$ul[0].addEventListener(eventNames.touchstart, function (e) {
67 me._isHorizontal = null;
68 me._touchStartPosition = me._getTouchPosition(e);
69 });
70 me.$ul[0].addEventListener(eventNames.touchmove, function (e) {
71 me._touchEndPosition = me._getTouchPosition(e);
72 if (me._isHorizontal == null) {
73 try {
74 var x = Math.abs(me._touchEndPosition.x - me._touchStartPosition.x);
75 var y = Math.abs(me._touchEndPosition.y - me._touchStartPosition.y);
76 me._isHorizontal = (x >= y);
77 } catch(e) {
78
79 }
80 }
81 if (me._isHorizontal == true) {
82 e.preventDefault();
83 me._move();
84 }
85 });
86 me.$ul[0].addEventListener(eventNames.touchend, function (e) {
87 if (me._isHorizontal == true) {
88 e.preventDefault();
89 me._touchEnd();
90 }
91 me._isHorizontal = null;
92 });
93 },
94 _enableMouseDrag: function () {
95 var me = this;
96 me.$ul.mousedown(function (e) {
97 e.stopPropagation();
98 me._touchStartPosition = me._getTouchPosition(e);
99 });
100 me.$ul.mousemove(function (e) {
101 e.stopPropagation();
102 me._touchEndPosition = me._getTouchPosition(e);
103 me._move();
104 });
105 me.$ul.mouseup(function (e) {
106 e.stopPropagation();
107 me._touchEnd();
108 });
109
110 me.$ul.mouseout(function(e) {
111 e.stopPropagation();
112 me._touchEnd();
113 });
114 },
115 _move: function () {
116 var me = this;
117 if (me._isMoving) {
118 return;
119 }
120 if (me._touchStartPosition && me._touchEndPosition) {
121 var left = -(me.itemWidth * me.currentIndex);
122 var offset = me._touchEndPosition.x - me._touchStartPosition.x;
123 me.$ul.css("left", (left + offset) + "px");
124 }
125 },
126 _touchEnd: function () {
127 var me = this;
128 if (me._touchStartPosition && me._touchEndPosition) {
129 var needOffset = me.itemWidth * me.sensitivity / 10;
130 var offset = me._touchEndPosition.x - me._touchStartPosition.x;
131 if (Math.abs(offset) >= needOffset) {
132 if (offset > 0) {
133 me.prev();
134 } else {
135 me.next();
136 }
137 } else {
138 me._restore();
139 me._itemClick(offset);
140 }
141 } else {
142 me._itemClick(null);
143 }
144 me._touchStartPosition = me._touchEndPosition = null;
145 },
146 toIndex: function (index) {
147 var me = this;
148 var oldIndex = me.currentIndex;
149 if (me._isMoving) {
150 return;
151 }
152 if (index >= me.count) {
153 index = me.count - 1;
154 }
155 if (index < 0) {
156 index = 0;
157 }
158 me.currentIndex = index;
159 var left = -(me.itemWidth * index);
160 me._isMoving = true;
161 $(me.$ul).animate({
162 left: left
163 }, me.speed, function () {
164 me._isMoving = false;
165 me.onChange && me.onChange();
166 if (oldIndex < me.currentIndex) {
167 me.onNext && me.onNext();
168 } else if (oldIndex > me.currentIndex) {
169 me.onPrev && me.onPrev();
170 }
171 });
172 },
173 next: function () {
174 var me = this;
175 me.toIndex(me.currentIndex + 1);
176 },
177 prev: function () {
178 var me = this;
179 me.toIndex(me.currentIndex - 1);
180 },
181 _itemClick: function (offset) {
182 var me = this;
183 if (Math.abs(offset) <= 2) {
184 me.onItemClick && me.onItemClick();
185 }
186 },
187 _bindClick: function (selector, func) {
188 var me = this;
189 if (me._isTouchable == false) {
190 $(selector).click(function (e) {
191 if ($(this).hasClass("disabled")) {
192 return;
193 }
194 func.call(this, e);
195 });
196 return;
197 }
198
199 var isMoving = false;
200 var startTime = null;
201 $(selector).bind(eventNames.touchstart, function (e) {
202 e.stopPropagation();
203 isMoving = false;
204 startTime = new Date();
205 $(this).addClass("touching");
206 });
207 $(selector).bind(eventNames.touchmove, function (e) {
208 e.stopPropagation();
209 isMoving = true;
210 });
211 $(selector).bind(eventNames.touchend, function (e) {
212 e.stopPropagation();
213 var $me = $(this);
214 if ($me.hasClass("disabled")) {
215 return;
216 }
217 $me.removeClass("touching");
218 var duration = new Date() - startTime;
219 if (!isMoving && duration < 1000) {
220 $me.addClass("clicking");
221 func.call(this, e);
222 setTimeout(function () {
223 $me.removeClass("clicking");
224 }, 500);
225 }
226 });
227 },
228 _restore: function () {
229 var me = this;
230 me.toIndex(me.currentIndex);
231 },
232 _getTouchPosition: function (event) {
233 try {
234 var touch = event.targetTouches[0];
235 if (touch == undefined) {
236 return null;
237 }
238 return {
239 x: touch.pageX,
240 y: touch.pageY
241 };
242 } catch (ex) {
243 return {
244 x: event.clientX,
245 y: event.clientY
246 };
247 }
248 }
249 };
250
251 })();
遇到的问题:
1、 性能问题。在某些手机浏览器中(比如腾讯的QQ浏览器,微信自带的浏览器,主要是移动设备),图片切换的时候很卡。Chrome、Safari和大部分手机浏览器中都能正常的执行。但这确确实实是一个问题。猜想是没有阻止事件传播。于是加了e.stopPropagation(),但是没有解决,也没有发现问题的所在。纠结了很久,然后漫无目的的试了一下e.preventDefault(),没想到这个方法就可以了。赶紧看了一下他们之间的差别。我就不讲了,直接献上链接:http://blog.csdn.net/woshixuye/article/details/7422985。
2、 在移动设备端,由于监听了touch事件,并阻止了默认的行为。因而在想上下滚动页面内容的时候,当你touch在图片上的时候,页面无法滑动的。后面换了一个思路,在start的时候不阻止事件,而是在move的时候,先判定滑动方向,在阻止事件。
3、图片拖动问题。主要是在PC端,鼠标拖动图片的时候,浏览器就直接把图片拖出来了,新建一个窗口打开图片或者搜索图片的信息。后面在img标签上加了一个 draggable="false",可以解决Chrome的拖动问题。但是在IE10以下的浏览器和Firefox中,还是有这个问题,我尝试了ondrag 和onselect的相关事件来阻止拖动,然而却发现没什么用。现在也没有能够解决这个问题。还好项目主要是针对移动端。如果大家有什么方法的话,不妨传授一下,感激不尽。 //todo
当然,光有js肯定是不行的,还需要html和css的配合。下面是html代码:
2 <html xmlns="http://www.w3.org/1999/xhtml">
3 <head>
4 <title>ImagesScroller Test</title>
5 <style type="text/css">
6 body {
7 margin: 0;
8 padding: 0;
9 }
10 div.content {
11 text-align: center;
12 padding-top: 100px;
13 padding-bottom: 1000px;
14 }
15 div.imagescrollerwrapper {
16 overflow: hidden;
17 background: #ccc;
18 margin: auto;
19 width: 40%;
20 }
21 ul.pictures-wrapper {
22 display: block;
23 padding: 0;
24 margin: 0;
25 height: 150px;
26 overflow: hidden;
27 position: relative;
28 list-style-type: none;
29 }
30 ul.pictures-wrapper li {
31 float: left;
32 display: block;
33 padding: 0;
34 margin: 0;
35 vertical-align: baseline;
36 }
37 ul.pictures-wrapper li img {
38 width: 100%;
39 height: 100%;
40 }
41 </style>
42 <script src="https://cdn.bootcss.com/jquery/2.1.1/jquery.min.js"></script>
43 <script src="ImagesScroller.js"></script>
44 <script type="text/javascript">
45 $(function() {
46 var viewer = new ImagesScroller("#divPictureScroller");
47 viewer.onChange = function () {
48 $("#divImageIndexInfo").html((viewer.currentIndex + 1) + " / " + viewer.count);
49 };
50 viewer.init();
51 });
52 </script>
53 </head>
54 <body>
55 <div class="content">
56 <div class="imagescrollerwrapper" id="divPictureScroller">
57 <ul class="pictures-wrapper">
58 <li>
59 <img draggable="false" alt="Image01" title="Image01" src="http://img4.duitang.com/uploads/item/201408/15/20140815022116_AahUY.thumb.700_0.png">
60 </li>
61 <li>
62 <img draggable="false" alt="Image02" title="Image02" src="http://tupian.qqjay.com/u/2012/1018/13_193427_10.jpg">
63 </li>
64 <li>
65 <img draggable="false" alt="Image03" title="Image03" src="http://img4.duitang.com/uploads/item/201202/24/20120224124613_ndzQh.jpg">
66 </li>
67 <li>
68 <img draggable="false" alt="Image04" title="Image04" src="http://pic4.zhongsou.com/image/4805cee61cdc2021563.jpg">
69 </li>
70 </ul>
71 </div>
72 <div id="divImageIndexInfo">
73 1 / 4
74 </div>
75 </div>
76 </body>
77 </html>
代码还有很多需要优化的,比如自动轮播,图片的循环,切换效果... 代码也有一些问题,但是现在没什么时间,等以后有时间再慢慢来完善吧...
希望大家多多把你们的意见或建议和我分享。
demo下载地址:https://files.cnblogs.com/files/AaronAndJoe/ImageViewer.rar【链接失效,可以直接copy代码使用】