/** * snap 重构 * @param {Object} $ * @param {Object} window */ (function($, window) { var CLASS_SLIDER = $.className('slider'); var CLASS_SLIDER_GROUP = $.className('slider-group'); var CLASS_SLIDER_LOOP = $.className('slider-loop'); var CLASS_SLIDER_INDICATOR = $.className('slider-indicator'); var CLASS_ACTION_PREVIOUS = $.className('action-previous'); var CLASS_ACTION_NEXT = $.className('action-next'); var CLASS_SLIDER_ITEM = $.className('slider-item'); var CLASS_ACTIVE = $.className('active'); var SELECTOR_SLIDER_ITEM = '.' + CLASS_SLIDER_ITEM; var SELECTOR_SLIDER_INDICATOR = '.' + CLASS_SLIDER_INDICATOR; var SELECTOR_SLIDER_PROGRESS_BAR = $.classSelector('.slider-progress-bar'); var Slider = $.Slider = $.Scroll.extend({ init: function(element, options) { this._super(element, $.extend(true, { fingers: 1, interval: 0, //设置为0,则不定时轮播 scrollY: false, scrollX: true, indicators: false, scrollTime: 1000, startX: false, slideTime: 0, //滑动动画时间 snap: SELECTOR_SLIDER_ITEM }, options)); if (this.options.startX) { // $.trigger(this.wrapper, 'scrollend', this); } }, _init: function() { this._reInit(); if (this.scroller) { this.scrollerStyle = this.scroller.style; this.progressBar = this.wrapper.querySelector(SELECTOR_SLIDER_PROGRESS_BAR); if (this.progressBar) { this.progressBarWidth = this.progressBar.offsetWidth; this.progressBarStyle = this.progressBar.style; } //忘记这个代码是干什么的了? // this.x = this._getScroll(); // if (this.options.startX === false) { // this.options.startX = this.x; // } //根据active修正startX this._super(); this._initTimer(); } }, _triggerSlide: function() { var self = this; self.isInTransition = false; var page = self.currentPage; self.slideNumber = self._fixedSlideNumber(); if (self.loop) { if (self.slideNumber === 0) { self.setTranslate(self.pages[1][0].x, 0); } else if (self.slideNumber === self.itemLength - 3) { self.setTranslate(self.pages[self.itemLength - 2][0].x, 0); } } if (self.lastSlideNumber != self.slideNumber) { self.lastSlideNumber = self.slideNumber; self.lastPage = self.currentPage; $.trigger(self.wrapper, 'slide', { slideNumber: self.slideNumber }); } self._initTimer(); }, _handleSlide: function(e) { var self = this; if (e.target !== self.wrapper) { return; } var detail = e.detail; detail.slideNumber = detail.slideNumber || 0; var temps = self.scroller.querySelectorAll(SELECTOR_SLIDER_ITEM); var items = []; for (var i = 0, len = temps.length; i < len; i++) { var item = temps[i]; if (item.parentNode === self.scroller) { items.push(item); } } var _slideNumber = detail.slideNumber; if (self.loop) { _slideNumber += 1; } if (!self.wrapper.classList.contains($.className('segmented-control'))) { for (var i = 0, len = items.length; i < len; i++) { var item = items[i]; if (item.parentNode === self.scroller) { if (i === _slideNumber) { item.classList.add(CLASS_ACTIVE); } else { item.classList.remove(CLASS_ACTIVE); } } } } var indicatorWrap = self.wrapper.querySelector($.classSelector('.slider-indicator')); if (indicatorWrap) { if (indicatorWrap.getAttribute('data-scroll')) { //scroll $(indicatorWrap).scroll().gotoPage(detail.slideNumber); } var indicators = indicatorWrap.querySelectorAll($.classSelector('.indicator')); if (indicators.length > 0) { //图片轮播 for (var i = 0, len = indicators.length; i < len; i++) { indicators[i].classList[i === detail.slideNumber ? 'add' : 'remove'](CLASS_ACTIVE); } } else { var number = indicatorWrap.querySelector($.classSelector('.number span')); if (number) { //图文表格 number.innerText = (detail.slideNumber + 1); } else { //segmented controls var controlItems = indicatorWrap.querySelectorAll($.classSelector('.control-item')); for (var i = 0, len = controlItems.length; i < len; i++) { controlItems[i].classList[i === detail.slideNumber ? 'add' : 'remove'](CLASS_ACTIVE); } } } } e.stopPropagation(); }, _handleTabShow: function(e) { var self = this; self.gotoItem((e.detail.tabNumber || 0), self.options.slideTime); }, _handleIndicatorTap: function(event) { var self = this; var target = event.target; if (target.classList.contains(CLASS_ACTION_PREVIOUS) || target.classList.contains(CLASS_ACTION_NEXT)) { self[target.classList.contains(CLASS_ACTION_PREVIOUS) ? 'prevItem' : 'nextItem'](); event.stopPropagation(); } }, _initEvent: function(detach) { var self = this; self._super(detach); var action = detach ? 'removeEventListener' : 'addEventListener'; self.wrapper[action]('slide', this); self.wrapper[action]($.eventName('shown', 'tab'), this); }, handleEvent: function(e) { this._super(e); switch (e.type) { case 'slide': this._handleSlide(e); break; case $.eventName('shown', 'tab'): if (~this.snaps.indexOf(e.target)) { //避免嵌套监听错误的tab show this._handleTabShow(e); } break; } }, _scrollend: function(e) { this._super(e); this._triggerSlide(e); }, _drag: function(e) { this._super(e); var direction = e.detail.direction; if (direction === 'left' || direction === 'right') { //拖拽期间取消定时 var slidershowTimer = this.wrapper.getAttribute('data-slidershowTimer'); slidershowTimer && window.clearTimeout(slidershowTimer); e.stopPropagation(); } }, _initTimer: function() { var self = this; var slider = self.wrapper; var interval = self.options.interval; var slidershowTimer = slider.getAttribute('data-slidershowTimer'); slidershowTimer && window.clearTimeout(slidershowTimer); if (interval) { slidershowTimer = window.setTimeout(function() { if (!slider) { return; } //仅slider显示状态进行自动轮播 if (!!(slider.offsetWidth || slider.offsetHeight)) { self.nextItem(true); //下一个 } self._initTimer(); }, interval); slider.setAttribute('data-slidershowTimer', slidershowTimer); } }, _fixedSlideNumber: function(page) { page = page || this.currentPage; var slideNumber = page.pageX; if (this.loop) { if (page.pageX === 0) { slideNumber = this.itemLength - 3; } else if (page.pageX === (this.itemLength - 1)) { slideNumber = 0; } else { slideNumber = page.pageX - 1; } } return slideNumber; }, _reLayout: function() { this.hasHorizontalScroll = true; this.loop = this.scroller.classList.contains(CLASS_SLIDER_LOOP); this._super(); }, _getScroll: function() { var result = $.parseTranslateMatrix($.getStyles(this.scroller, 'webkitTransform')); return result ? result.x : 0; }, _transitionEnd: function(e) { if (e.target !== this.scroller || !this.isInTransition) { return; } this._transitionTime(); this.isInTransition = false; $.trigger(this.wrapper, 'scrollend', this); }, _flick: function(e) { if (!this.moved) { //无moved return; } var detail = e.detail; var direction = detail.direction; this._clearRequestAnimationFrame(); this.isInTransition = true; // if (direction === 'up' || direction === 'down') { // this.resetPosition(this.options.bounceTime); // return; // } if (e.type === 'flick') { if (detail.deltaTime < 200) { //flick,太容易触发,额外校验一下deltaTime this.x = this._getPage((this.slideNumber + (direction === 'right' ? -1 : 1)), true).x; } this.resetPosition(this.options.bounceTime); } else if (e.type === 'dragend' && !detail.flick) { this.resetPosition(this.options.bounceTime); } e.stopPropagation(); }, _initSnap: function() { this.scrollerWidth = this.itemLength * this.scrollerWidth; this.maxScrollX = Math.min(this.wrapperWidth - this.scrollerWidth, 0); this._super(); if (!this.currentPage.x) { //当slider处于隐藏状态时,导致snap计算是错误的,临时先这么判断一下,后续要考虑解决所有scroll在隐藏状态下初始化属性不正确的问题 var currentPage = this.pages[this.loop ? 1 : 0]; currentPage = currentPage || this.pages[0]; if (!currentPage) { return; } this.currentPage = currentPage[0]; this.slideNumber = 0; this.lastSlideNumber = typeof this.lastSlideNumber === 'undefined' ? 0 : this.lastSlideNumber; } else { this.slideNumber = this._fixedSlideNumber(); this.lastSlideNumber = typeof this.lastSlideNumber === 'undefined' ? this.slideNumber : this.lastSlideNumber; } this.options.startX = this.currentPage.x || 0; }, _getSnapX: function(offsetLeft) { return Math.max(-offsetLeft, this.maxScrollX); }, _getPage: function(slideNumber, isFlick) { if (this.loop) { if (slideNumber > (this.itemLength - (isFlick ? 2 : 3))) { slideNumber = 1; time = 0; } else if (slideNumber < (isFlick ? -1 : 0)) { slideNumber = this.itemLength - 2; time = 0; } else { slideNumber += 1; } } else { if (!isFlick) { if (slideNumber > (this.itemLength - 1)) { slideNumber = 0; time = 0; } else if (slideNumber < 0) { slideNumber = this.itemLength - 1; time = 0; } } slideNumber = Math.min(Math.max(0, slideNumber), this.itemLength - 1); } return this.pages[slideNumber][0]; }, _gotoItem: function(slideNumber, time) { this.currentPage = this._getPage(slideNumber, true); //此处传true。可保证程序切换时,动画与人手操作一致(第一张,最后一张的切换动画) this.scrollTo(this.currentPage.x, 0, time, this.options.scrollEasing); if (time === 0) { $.trigger(this.wrapper, 'scrollend', this); } }, //API setTranslate: function(x, y) { this._super(x, y); var progressBar = this.progressBar; if (progressBar) { this.progressBarStyle.webkitTransform = this._getTranslateStr((-x * (this.progressBarWidth / this.wrapperWidth)), 0); } }, resetPosition: function(time) { time = time || 0; if (this.x > 0) { this.x = 0; } else if (this.x < this.maxScrollX) { this.x = this.maxScrollX; } this.currentPage = this._nearestSnap(this.x); this.scrollTo(this.currentPage.x, 0, time, this.options.scrollEasing); return true; }, gotoItem: function(slideNumber, time) { this._gotoItem(slideNumber, typeof time === 'undefined' ? this.options.scrollTime : time); }, nextItem: function() { this._gotoItem(this.slideNumber + 1, this.options.scrollTime); }, prevItem: function() { this._gotoItem(this.slideNumber - 1, this.options.scrollTime); }, getSlideNumber: function() { return this.slideNumber || 0; }, _reInit: function() { var groups = this.wrapper.querySelectorAll('.' + CLASS_SLIDER_GROUP); for (var i = 0, len = groups.length; i < len; i++) { if (groups[i].parentNode === this.wrapper) { this.scroller = groups[i]; break; } } this.scrollerStyle = this.scroller && this.scroller.style; if (this.progressBar) { this.progressBarWidth = this.progressBar.offsetWidth; this.progressBarStyle = this.progressBar.style; } }, refresh: function(options) { if (options) { $.extend(this.options, options); this._super(); this._initTimer(); } else { this._super(); } }, destroy: function() { this._initEvent(true); //detach delete $.data[this.wrapper.getAttribute('data-slider')]; this.wrapper.setAttribute('data-slider', ''); } }); $.fn.slider = function(options) { var slider = null; this.each(function() { var sliderElement = this; if (!this.classList.contains(CLASS_SLIDER)) { sliderElement = this.querySelector('.' + CLASS_SLIDER); } if (sliderElement && sliderElement.querySelector(SELECTOR_SLIDER_ITEM)) { var id = sliderElement.getAttribute('data-slider'); if (!id) { id = ++$.uuid; $.data[id] = slider = new Slider(sliderElement, options); sliderElement.setAttribute('data-slider', id); } else { slider = $.data[id]; if (slider && options) { slider.refresh(options); } } } }); return slider; }; $.ready(function() { // setTimeout(function() { $($.classSelector('.slider')).slider(); $($.classSelector('.scroll-wrapper.slider-indicator.segmented-control')).scroll({ scrollY: false, scrollX: true, indicators: false, snap: $.classSelector('.control-item') }); // }, 500); //临时处理slider宽度计算不正确的问题(初步确认是scrollbar导致的) }); })(mui, window);