qiaowei | f044a74 | 2019-07-10 16:04:20 +0800 | [diff] [blame^] | 1 | /** |
| 2 | * aui-slide.js 轮播组件 |
| 3 | * @author 流浪男 |
| 4 | * http://www.auicss.com |
| 5 | * @todo more things to abstract, e.g. Loading css etc. |
| 6 | * Licensed under the MIT license. |
| 7 | * http://www.opensource.org/licenses/mit-license.php |
| 8 | */ |
| 9 | (function(window) { |
| 10 | "use strict"; |
| 11 | |
| 12 | var translateVal, |
| 13 | firstTouchX, |
| 14 | firstTouchY, |
| 15 | touchXDelta, |
| 16 | handleTranslateVal; |
| 17 | var touchStartTime; //开始触摸事件 |
| 18 | var offsetX, |
| 19 | offsetY, |
| 20 | isScrolling; |
| 21 | // CLASS 组装 |
| 22 | var CLASS_SLIDER_NODE = "aui-slide-node", |
| 23 | CLASS_SLIDE_PAGE_WRAP = "aui-slide-page-wrap", |
| 24 | CLASS_SLIDE_PAGE = "aui-slide-page", |
| 25 | CLASS_SLIDE_PAGE_ACTIVE = "aui-slide-page-active", |
| 26 | CLASS_SLIDE_PAGE_DOT = "aui-slide-page-dot", |
| 27 | CLASS_SLIDE_PAGE_LINE = "aui-slide-page-line"; |
| 28 | |
| 29 | var __SLIDER_NODE = "."+CLASS_SLIDER_NODE, |
| 30 | __SLIDE_PAGE_WRAP = "."+CLASS_SLIDE_PAGE_WRAP, |
| 31 | __SLIDE_PAGE = "."+CLASS_SLIDE_PAGE, |
| 32 | __SLIDE_PAGE_ACTIVE = "."+CLASS_SLIDE_PAGE_ACTIVE; |
| 33 | |
| 34 | auiSlide.prototype.options = { |
| 35 | container:'', |
| 36 | width:'auto', |
| 37 | height:'auto', |
| 38 | speed: 300, //滑动速速 |
| 39 | autoPlay: 0, //自动播放 |
| 40 | pageShow: true, //是否显示分页器 |
| 41 | pageStyle: 'dot', |
| 42 | dotPosition: 'center', |
| 43 | friction:1, //阻力 |
| 44 | loop:true, |
| 45 | currentPage:false, |
| 46 | PageCount:false |
| 47 | }; |
| 48 | auiSlide.prototype._init = function(options) { |
| 49 | extend(this.options, options); |
| 50 | if(!this.options.container){ |
| 51 | return; |
| 52 | } |
| 53 | this.index = 0; //索引值 |
| 54 | this.continuous = true;//用于判断长度为2时的特殊处理 |
| 55 | this.container = this.options.container; |
| 56 | // console.log(this.options.loop); |
| 57 | this.loop = this.options.loop; |
| 58 | this.speed = this.options.speed; |
| 59 | this.container.style.position = "relative"; |
| 60 | this.container.style.width = this.options.width+"px"; |
| 61 | this.container.style.height = this.options.height+"px"; |
| 62 | |
| 63 | var element = this.container.children[0]; |
| 64 | this.slideWrap = element; |
| 65 | this.slideNodeList = this.slideWrap.querySelectorAll(__SLIDER_NODE); |
| 66 | if(!element || !this.slideNodeList){ |
| 67 | return; |
| 68 | } |
| 69 | // this.options.pageCount(this.slideNodeList.length); |
| 70 | this.slideWrapWidth = this.slideWrap.offsetWidth; |
| 71 | this.slideNodeListLength = this.slideNodeList.length; |
| 72 | |
| 73 | if (this.slideNodeListLength == 2) { //当长度为2时作特殊处理 |
| 74 | element.appendChild(this.slideWrap.children[0].cloneNode(true)); |
| 75 | element.appendChild(this.slideWrap.children[1].cloneNode(true)); |
| 76 | this.slideWrap = element; |
| 77 | this.slideNodeList = this.slideWrap.querySelectorAll(__SLIDER_NODE); |
| 78 | this.slideNodeListLength = this.slideNodeList.length; |
| 79 | this.continuous = false; |
| 80 | } |
| 81 | for (var i = 0; i < this.slideNodeListLength; i++) { |
| 82 | this.slideNodeList[i] && (this.slideNodeList[i].style.webkitTransform = this.slideNodeList[i].style.transform = "translate3d("+(this.slideWrapWidth*i)+"px,0,0)"); |
| 83 | } |
| 84 | |
| 85 | if(this.slideNodeListLength > 1) { |
| 86 | if(this.options.pageShow){ |
| 87 | this.createPagination(0); |
| 88 | this.setPageDotPosition(); |
| 89 | } |
| 90 | if(this.options.autoPlay > 500 && this.loop){ |
| 91 | this.autoPlay(0); |
| 92 | } |
| 93 | this.slideWrap.addEventListener('touchstart', this.touchStart.bind(this), false); |
| 94 | this.slideWrap.addEventListener('touchmove', this.touchMove.bind(this), false); |
| 95 | this.slideWrap.addEventListener('touchend', this.touchEnd.bind(this), false); |
| 96 | } |
| 97 | }; |
| 98 | // 当分页器为圆点时位置设置 |
| 99 | auiSlide.prototype.setPageDotPosition = function(){ |
| 100 | var self = this; |
| 101 | var pageDotPosition = self.options.dotPosition; |
| 102 | this.container.querySelector(__SLIDE_PAGE_WRAP).style.textAlign = pageDotPosition; |
| 103 | }; |
| 104 | // 自动播放 |
| 105 | auiSlide.prototype.autoPlay = function (index) { |
| 106 | var self = this; |
| 107 | setInterval(function(){ |
| 108 | self.slideTo(self.getCircle(self.index-1), -self.slideWrapWidth, 0); |
| 109 | self.slideTo(self.getCircle(self.index+2), self.slideWrapWidth, 0); |
| 110 | self.slideTo(self.index, -self.slideWrapWidth, self.options.speed); |
| 111 | self.slideTo(self.getCircle(self.index+1), 0, self.options.speed); |
| 112 | self.index = self.getCircle(self.index+1); |
| 113 | self.setPaginationActive(self.index); |
| 114 | }, self.options.autoPlay) |
| 115 | }; |
| 116 | // 设置当前分页 |
| 117 | auiSlide.prototype.setPaginationActive = function(index){ |
| 118 | var self = this; |
| 119 | if(self.options.currentPage){ |
| 120 | self.options.currentPage(index); |
| 121 | } |
| 122 | if(!this.container.querySelector(__SLIDE_PAGE_WRAP)){ |
| 123 | return; |
| 124 | } |
| 125 | var pageList = this.container.querySelectorAll(__SLIDE_PAGE); |
| 126 | if(this.container.querySelector(__SLIDE_PAGE+__SLIDE_PAGE_ACTIVE)){ |
| 127 | this.container.querySelector(__SLIDE_PAGE+__SLIDE_PAGE_ACTIVE).classList.remove(CLASS_SLIDE_PAGE_ACTIVE); |
| 128 | } |
| 129 | if(!this.continuous){ |
| 130 | if(this.index == 3){ |
| 131 | pageList[1].classList.add(CLASS_SLIDE_PAGE_ACTIVE); |
| 132 | }else if(this.index==2){ |
| 133 | pageList[0].classList.add(CLASS_SLIDE_PAGE_ACTIVE); |
| 134 | }else{ |
| 135 | pageList[this.index].classList.add(CLASS_SLIDE_PAGE_ACTIVE); |
| 136 | } |
| 137 | }else{ |
| 138 | pageList[this.index].classList.add(CLASS_SLIDE_PAGE_ACTIVE); |
| 139 | } |
| 140 | |
| 141 | }; |
| 142 | // 创建分页器 |
| 143 | auiSlide.prototype.createPagination = function(index){ |
| 144 | var self = this; |
| 145 | var pageWrap = this.container.querySelector(__SLIDE_PAGE_WRAP); |
| 146 | if(!pageWrap){ |
| 147 | return; |
| 148 | } |
| 149 | pageWrap.innerHTML = ''; |
| 150 | var pageShowHtml = ''; |
| 151 | switch (self.options.pageStyle) { |
| 152 | case "dot":// 原点 |
| 153 | if (!this.continuous) { |
| 154 | for (var i = 0; i < 2; i++) { |
| 155 | pageShowHtml += '<span class="'+CLASS_SLIDE_PAGE+' '+CLASS_SLIDE_PAGE_DOT+'"></span>'; |
| 156 | } |
| 157 | }else{ |
| 158 | for (var i = 0; i < this.slideNodeListLength; i++) { |
| 159 | pageShowHtml += '<span class="'+CLASS_SLIDE_PAGE+' '+CLASS_SLIDE_PAGE_DOT+'"></span>'; |
| 160 | } |
| 161 | } |
| 162 | pageWrap.innerHTML = pageShowHtml; |
| 163 | self.setPaginationActive(0); |
| 164 | break; |
| 165 | case "line":// 线条 |
| 166 | if (!this.continuous) { |
| 167 | for (var i = 0; i < 2; i++) { |
| 168 | pageShowHtml += '<span class="'+CLASS_SLIDE_PAGE+' '+CLASS_SLIDE_PAGE_LINE+'" style="width:50%"></span>'; |
| 169 | } |
| 170 | }else{ |
| 171 | for (var i = 0; i < this.slideNodeListLength; i++) { |
| 172 | pageShowHtml += '<span class="'+CLASS_SLIDE_PAGE+' '+CLASS_SLIDE_PAGE_LINE+'" style="width:'+(100/this.slideNodeListLength)+'%"></span>'; |
| 173 | } |
| 174 | } |
| 175 | pageWrap.innerHTML = pageShowHtml; |
| 176 | self.setPaginationActive(0); |
| 177 | break; |
| 178 | } |
| 179 | }; |
| 180 | // 总页数 |
| 181 | auiSlide.prototype.pageCount = function() { |
| 182 | var self = this; |
| 183 | return self.slideNodeList.length; |
| 184 | }; |
| 185 | auiSlide.prototype.touchStart = function(event) { |
| 186 | touchStartTime = new Date() * 1; |
| 187 | firstTouchX = parseInt(event.changedTouches[0].pageX); |
| 188 | firstTouchY = parseInt(event.changedTouches[0].pageY); |
| 189 | isScrolling = undefined; |
| 190 | }; |
| 191 | auiSlide.prototype.touchMove = function(event) { |
| 192 | var touchMoveObj = event.changedTouches[0], |
| 193 | touchX = parseInt(touchMoveObj.pageX); |
| 194 | touchXDelta = touchX - firstTouchX; |
| 195 | handleTranslateVal = touchXDelta/this.options.friction; |
| 196 | // 滑动位移 |
| 197 | offsetX = parseInt(touchMoveObj.pageX) - firstTouchX; |
| 198 | offsetY = parseInt(touchMoveObj.pageY) - firstTouchY; |
| 199 | var direction = this.getDirection(offsetX,offsetY); |
| 200 | if ( typeof isScrolling == 'undefined') { |
| 201 | isScrolling = !!( isScrolling || Math.abs(offsetX) < Math.abs(offsetY) ); |
| 202 | } |
| 203 | if(!isScrolling){ |
| 204 | event.preventDefault(); |
| 205 | if(!this.loop){ //不循环 |
| 206 | if(!this.continuous && this.index==1 && direction=='left'){ |
| 207 | return; |
| 208 | } |
| 209 | if(!this.continuous && this.index==0 && direction=='right'){ |
| 210 | return; |
| 211 | } |
| 212 | if(this.index == this.slideNodeList.length-1){ |
| 213 | if(handleTranslateVal <= 0){ |
| 214 | return; |
| 215 | } |
| 216 | this.setTranslate(this.getCircle(this.index-1), handleTranslateVal - this.slideWrapWidth, 0); |
| 217 | }else if(this.index == 0){ |
| 218 | if(handleTranslateVal >= 0){ |
| 219 | return; |
| 220 | } |
| 221 | this.setTranslate(this.getCircle(this.index+1), this.slideWrapWidth, 0); |
| 222 | } |
| 223 | } |
| 224 | |
| 225 | this.setTranslate(this.getCircle(this.index-1), handleTranslateVal - this.slideWrapWidth, 0); |
| 226 | this.setTranslate(this.index, handleTranslateVal , 0); |
| 227 | this.setTranslate(this.getCircle(this.index+1), handleTranslateVal + this.slideWrapWidth, 0); |
| 228 | |
| 229 | } |
| 230 | }; |
| 231 | auiSlide.prototype.touchEnd = function(event) { |
| 232 | var touchEndObj = event.changedTouches[0]; |
| 233 | var touchEndX = parseInt(touchEndObj.pageX) - firstTouchX; |
| 234 | var touchEndY = parseInt(touchEndObj.pageY) - firstTouchY; |
| 235 | var touchEndxy = { |
| 236 | x: touchEndObj.pageX || 0, |
| 237 | y: touchEndObj.pageY || 0 |
| 238 | }; |
| 239 | var moveDirection = this.getDirection(touchEndX,touchEndY); //滑动方向 |
| 240 | var boundary = this.slideWrapWidth/4; |
| 241 | var duration = (new Date() * 1) - touchStartTime; |
| 242 | var isValid = Number(duration) < 250 && Math.abs(offsetX) > 20 || Math.abs(offsetX) > boundary; |
| 243 | if (isScrolling) { |
| 244 | return; |
| 245 | } |
| 246 | if(isValid){ |
| 247 | if(offsetX < 0){ |
| 248 | if(!this.loop && this.index == this.slideNodeList.length-1){ |
| 249 | return; |
| 250 | } |
| 251 | |
| 252 | if(!this.loop && !this.continuous && this.index==1){ |
| 253 | return; |
| 254 | } |
| 255 | |
| 256 | if(offsetX < -boundary && moveDirection == 'left'){ |
| 257 | // left |
| 258 | this.slideTo(this.getCircle(this.index-1), -this.slideWrapWidth, 0); |
| 259 | this.slideTo(this.getCircle(this.index+2), this.slideWrapWidth, 0); |
| 260 | this.slideTo(this.index, -this.slideWrapWidth, this.speed); |
| 261 | this.slideTo(this.getCircle(this.index+1), 0, this.speed); |
| 262 | this.index = this.getCircle(this.index+1); |
| 263 | }else{ |
| 264 | // this.slideTo(this.getCircle(this.index-1), -this.slideWrapWidth, this.speed); |
| 265 | this.slideTo(this.index, 0, this.speed); |
| 266 | this.slideTo(this.getCircle(this.index+1), this.slideWrapWidth, this.speed); |
| 267 | } |
| 268 | }else if(offsetX > 0){ |
| 269 | if(!this.loop && this.index == 0){ |
| 270 | return; |
| 271 | } |
| 272 | if(!this.loop && !this.continuous && this.index==0){ |
| 273 | return; |
| 274 | } |
| 275 | if(offsetX > boundary && moveDirection == 'right'){ |
| 276 | // right |
| 277 | this.slideTo(this.getCircle(this.index+1), this.slideWrapWidth, 0); |
| 278 | this.slideTo(this.getCircle(this.index-2), -this.slideWrapWidth, 0); |
| 279 | this.slideTo(this.index, this.slideWrapWidth, this.speed); |
| 280 | this.slideTo(this.getCircle(this.index-1), 0, this.speed); |
| 281 | this.index = this.getCircle(this.index-1); |
| 282 | }else{ |
| 283 | // this.slideTo(this.getCircle(this.index-1), -this.slideWrapWidth, this.speed); |
| 284 | this.slideTo(this.index, 0, this.speed); |
| 285 | this.slideTo(this.getCircle(this.index+1), this.slideWrapWidth, this.speed); |
| 286 | } |
| 287 | } |
| 288 | }else{ |
| 289 | if(offsetX){ |
| 290 | this.slideTo(this.getCircle(this.index-1), -this.slideWrapWidth, this.speed); |
| 291 | this.slideTo(this.index, 0, this.speed); |
| 292 | this.slideTo(this.getCircle(this.index+1), this.slideWrapWidth, this.speed); |
| 293 | } |
| 294 | |
| 295 | } |
| 296 | this.setPaginationActive(this.index); |
| 297 | }; |
| 298 | auiSlide.prototype.setTranslate = function (index,dist,speed){ |
| 299 | if(this.slideNodeList[index]){ |
| 300 | this.slideNodeList[index].style.webkitTransitionDuration = |
| 301 | this.slideNodeList[index].style.transitionDuration = speed + 'ms'; |
| 302 | this.slideNodeList[index].style.webkitTransform = |
| 303 | this.slideNodeList[index].style.transform = "translate3d("+dist+"px,0,0)"; |
| 304 | } |
| 305 | }; |
| 306 | auiSlide.prototype.slideTo = function (index, dist, speed) { |
| 307 | this.setTranslate(index, dist, speed); |
| 308 | // index = dist; |
| 309 | }; |
| 310 | auiSlide.prototype.getCircle = function (index) { |
| 311 | return (this.slideNodeListLength + (index % this.slideNodeListLength)) % this.slideNodeListLength; |
| 312 | }; |
| 313 | auiSlide.prototype.getDirection = function(x, y) { |
| 314 | if (x === y) { return '';} |
| 315 | if (Math.abs(x) >= Math.abs(y)) { |
| 316 | return x > 0 ? 'right' : 'left'; |
| 317 | } else { |
| 318 | return y > 0 ? 'down' : 'up'; |
| 319 | } |
| 320 | } |
| 321 | function extend (a, b) { |
| 322 | for (var key in b) { |
| 323 | if (b.hasOwnProperty(key)) { |
| 324 | a[key] = b[key]; |
| 325 | } |
| 326 | } |
| 327 | return a; |
| 328 | } |
| 329 | function auiSlide (options) { |
| 330 | this._init(options); |
| 331 | } |
| 332 | window.auiSlide = auiSlide; |
| 333 | })(window); |