aui-slide.js 12 KB

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