You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

406 lines
13 KiB

4 years ago
/**
* 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);