|
|
/**
|
|
|
* Slider (TODO resize)
|
|
|
* @param {type} $
|
|
|
* @param {type} window
|
|
|
* @returns {undefined}
|
|
|
*/
|
|
|
(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 SELECTOR_SLIDER_ITEM = '.' + CLASS_SLIDER_ITEM;
|
|
|
var SELECTOR_SLIDER_INDICATOR = '.' + CLASS_SLIDER_INDICATOR;
|
|
|
var SELECTOR_SLIDER_PROGRESS_BAR = $.classSelector('.slider-progress-bar');
|
|
|
|
|
|
|
|
|
var Slider = function(element, options) {
|
|
|
this.element = element;
|
|
|
this.options = $.extend({
|
|
|
slideshowDelay: 0, //设置为0,则不定时轮播
|
|
|
factor: 1
|
|
|
}, options);
|
|
|
|
|
|
this.init();
|
|
|
};
|
|
|
Slider.prototype.init = function() {
|
|
|
// this.initDuplicate();
|
|
|
this.initEvent();
|
|
|
this.initTimer();
|
|
|
};
|
|
|
Slider.prototype.refresh = function(options) {
|
|
|
var newOptions = $.extend({
|
|
|
slideshowDelay: 0, //设置为0,则不定时轮播
|
|
|
factor: 1
|
|
|
}, options);
|
|
|
if (this.options.slideshowDelay !== newOptions.slideshowDelay) {
|
|
|
this.options.slideshowDelay = newOptions.slideshowDelay;
|
|
|
if (this.options.slideshowDelay) {
|
|
|
this.nextItem();
|
|
|
}
|
|
|
}
|
|
|
};
|
|
|
//TODO 暂时不做自动clone
|
|
|
// Slider.prototype.initDuplicate = function() {
|
|
|
// var self = this;
|
|
|
// var element = self.element;
|
|
|
// if (element.classList.contains(CLASS_SLIDER_LOOP)) {
|
|
|
// var duplicates = element.getElementsByClassName(CLASS_SLIDER_ITEM_DUPLICATE);
|
|
|
// }
|
|
|
// };
|
|
|
Slider.prototype.initEvent = function() {
|
|
|
var self = this;
|
|
|
var element = self.element;
|
|
|
var slider = element.parentNode;
|
|
|
self.translateX = 0;
|
|
|
self.sliderWidth = element.offsetWidth;
|
|
|
self.isLoop = element.classList.contains(CLASS_SLIDER_LOOP);
|
|
|
self.sliderLength = element.querySelectorAll(SELECTOR_SLIDER_ITEM).length;
|
|
|
self.progressBarWidth = 0;
|
|
|
self.progressBar = slider.querySelector(SELECTOR_SLIDER_PROGRESS_BAR);
|
|
|
if (self.progressBar) {
|
|
|
self.progressBarWidth = self.progressBar.offsetWidth;
|
|
|
}
|
|
|
//slider
|
|
|
var isDragable = false;
|
|
|
self.isSwipeable = false;
|
|
|
slider.addEventListener('dragstart', function(event) {
|
|
|
var detail = event.detail;
|
|
|
var direction = detail.direction;
|
|
|
if (direction === 'left' || direction === 'right') { //reset
|
|
|
isDragable = true;
|
|
|
self.translateX = self.lastTranslateX = 0;
|
|
|
self.scrollX = self.getScroll();
|
|
|
self.sliderWidth = element.offsetWidth;
|
|
|
self.isLoop = element.classList.contains(CLASS_SLIDER_LOOP);
|
|
|
self.sliderLength = element.querySelectorAll(SELECTOR_SLIDER_ITEM).length;
|
|
|
if (self.progressBar) {
|
|
|
self.progressBarWidth = self.progressBar.offsetWidth;
|
|
|
}
|
|
|
self.maxTranslateX = ((self.sliderLength - 1) * self.sliderWidth);
|
|
|
event.detail.gesture.preventDefault();
|
|
|
var isStopPropagation = true;
|
|
|
if (!self.isLoop) {
|
|
|
if (direction === 'right' && self.scrollX === 0) {
|
|
|
isStopPropagation = false;
|
|
|
} else if (direction === 'left' && self.scrollX === -self.maxTranslateX) {
|
|
|
isStopPropagation = false;
|
|
|
}
|
|
|
}
|
|
|
isStopPropagation && event.stopPropagation();
|
|
|
}
|
|
|
});
|
|
|
slider.addEventListener('drag', function(event) {
|
|
|
if (isDragable) {
|
|
|
self.dragItem(event);
|
|
|
event.stopPropagation();
|
|
|
}
|
|
|
|
|
|
});
|
|
|
slider.addEventListener('dragend', function(event) {
|
|
|
if (isDragable) {
|
|
|
self.gotoItem(self.getSlideNumber());
|
|
|
isDragable = self.isSwipeable = false;
|
|
|
event.stopPropagation();
|
|
|
}
|
|
|
});
|
|
|
// slider.addEventListener('flick', $.stopPropagation);
|
|
|
slider.addEventListener('swipeleft', function(event) {
|
|
|
if (self.isSwipeable) {
|
|
|
//stop dragend
|
|
|
$.gestures.stoped = true;
|
|
|
self.nextItem();
|
|
|
isDragable = self.isSwipeable = false;
|
|
|
}
|
|
|
event.stopPropagation();
|
|
|
});
|
|
|
slider.addEventListener('swiperight', function(event) {
|
|
|
if (self.isSwipeable) {
|
|
|
//stop dragend
|
|
|
$.gestures.stoped = true;
|
|
|
self.prevItem();
|
|
|
isDragable = self.isSwipeable = false;
|
|
|
}
|
|
|
event.stopPropagation();
|
|
|
});
|
|
|
slider.addEventListener('slide', function(e) {
|
|
|
var detail = e.detail;
|
|
|
detail.slideNumber = detail.slideNumber || 0;
|
|
|
var number = slider.querySelector($.classSelector('.slider-indicator .number span'));
|
|
|
if (number) {
|
|
|
number.innerText = (detail.slideNumber + 1);
|
|
|
}
|
|
|
|
|
|
var indicators = slider.querySelectorAll($.classSelector('.slider-indicator .indicator'));
|
|
|
for (var i = 0, len = indicators.length; i < len; i++) {
|
|
|
indicators[i].classList[i === detail.slideNumber ? 'add' : 'remove']($.className('active'));
|
|
|
}
|
|
|
|
|
|
var controlItems = slider.querySelectorAll($.classSelector('.control-item'));
|
|
|
for (var i = 0, len = controlItems.length; i < len; i++) {
|
|
|
controlItems[i].classList[i === detail.slideNumber ? 'add' : 'remove']($.className('active'));
|
|
|
}
|
|
|
e.stopPropagation();
|
|
|
});
|
|
|
slider.addEventListener($.eventName('shown', 'tab'), function(e) { //tab
|
|
|
self.gotoItem(-(e.detail.tabNumber || 0));
|
|
|
});
|
|
|
//indicator
|
|
|
var indicator = element.parentNode.querySelector(SELECTOR_SLIDER_INDICATOR);
|
|
|
if (indicator) {
|
|
|
indicator.addEventListener('tap', function(event) {
|
|
|
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();
|
|
|
}
|
|
|
});
|
|
|
}
|
|
|
};
|
|
|
Slider.prototype.dragItem = function(event) {
|
|
|
var self = this;
|
|
|
var detail = event.detail;
|
|
|
|
|
|
if (detail.deltaX !== detail.lastDeltaX) {
|
|
|
var translate = (detail.deltaX * self.options.factor + self.scrollX);
|
|
|
self.element.style['-webkit-transition-duration'] = '0';
|
|
|
var min = 0;
|
|
|
var max = -self.maxTranslateX;
|
|
|
if (self.isLoop) {
|
|
|
min = self.sliderWidth;
|
|
|
max = max + min;
|
|
|
}
|
|
|
if (translate > min || translate < max) {
|
|
|
self.isSwipeable = false;
|
|
|
return;
|
|
|
}
|
|
|
if (!self.requestAnimationFrame) {
|
|
|
self.updateTranslate();
|
|
|
}
|
|
|
self.isSwipeable = true;
|
|
|
self.translateX = translate;
|
|
|
}
|
|
|
if (self.timer) {
|
|
|
clearTimeout(self.timer);
|
|
|
}
|
|
|
self.timer = setTimeout(function() {
|
|
|
self.initTimer();
|
|
|
}, 100);
|
|
|
|
|
|
};
|
|
|
Slider.prototype.updateTranslate = function() {
|
|
|
var self = this;
|
|
|
if (self.lastTranslateX !== self.translateX) {
|
|
|
self.setTranslate(self.translateX);
|
|
|
self.lastTranslateX = self.translateX;
|
|
|
}
|
|
|
self.requestAnimationFrame = requestAnimationFrame(function() {
|
|
|
self.updateTranslate();
|
|
|
});
|
|
|
};
|
|
|
Slider.prototype.setTranslate = function(x) {
|
|
|
this.element.style.webkitTransform = 'translate3d(' + x + 'px,0,0)';
|
|
|
this.updateProcess(x);
|
|
|
};
|
|
|
Slider.prototype.updateProcess = function(translate) {
|
|
|
var progressBarWidth = this.progressBarWidth;
|
|
|
if (progressBarWidth) {
|
|
|
translate = Math.abs(translate);
|
|
|
this.setProcess(translate * (progressBarWidth / this.sliderWidth));
|
|
|
}
|
|
|
};
|
|
|
Slider.prototype.setProcess = function(translate) {
|
|
|
var progressBar = this.progressBar;
|
|
|
if (progressBar) {
|
|
|
progressBar.style.webkitTransform = 'translate3d(' + translate + 'px,0,0)';
|
|
|
}
|
|
|
};
|
|
|
/**
|
|
|
* 下一个轮播
|
|
|
* @returns {Number}
|
|
|
*/
|
|
|
Slider.prototype.nextItem = function() {
|
|
|
this.gotoItem(this.getCurrentSlideNumber('next') - 1);
|
|
|
};
|
|
|
/**
|
|
|
* 上一个轮播
|
|
|
* @returns {Number}
|
|
|
*/
|
|
|
Slider.prototype.prevItem = function() {
|
|
|
this.gotoItem(this.getCurrentSlideNumber('prev') + 1);
|
|
|
};
|
|
|
/**
|
|
|
* 滑动到指定轮播
|
|
|
* @param {type} slideNumber
|
|
|
* @returns {undefined}
|
|
|
*/
|
|
|
Slider.prototype.gotoItem = function(slideNumber) {
|
|
|
if (!(slideNumber === 1 && this.getSlideNumber() === slideNumber)) {
|
|
|
slideNumber = slideNumber > 0 ? -slideNumber : slideNumber;
|
|
|
}
|
|
|
var self = this;
|
|
|
var slider = self.element;
|
|
|
var slideLength = self.sliderLength;
|
|
|
if (self.isLoop) { //循环轮播需减去2个过渡元素
|
|
|
slideLength = slideLength - 2;
|
|
|
} else {
|
|
|
slideLength = slideLength - 1;
|
|
|
slideNumber = Math.min(0, slideNumber);
|
|
|
slideNumber = Math.max(slideNumber, -slideLength);
|
|
|
}
|
|
|
if (self.requestAnimationFrame) {
|
|
|
cancelAnimationFrame(self.requestAnimationFrame);
|
|
|
self.requestAnimationFrame = null;
|
|
|
}
|
|
|
var offsetX = Math.max(slideNumber, -slideLength) * slider.offsetWidth;
|
|
|
slider.style['-webkit-transition-duration'] = '.2s';
|
|
|
self.setTranslate(offsetX);
|
|
|
// slider.style.webkitTransform = 'translate3d(' + offsetX + 'px,0,0)';
|
|
|
// self.updateProcess(offsetX);
|
|
|
var fixedLoop = function() {
|
|
|
slider.style['-webkit-transition-duration'] = '0';
|
|
|
slider.style.webkitTransform = 'translate3d(' + (slideNumber * slider.offsetWidth) + 'px,0,0)';
|
|
|
slider.removeEventListener('webkitTransitionEnd', fixedLoop);
|
|
|
};
|
|
|
slider.removeEventListener('webkitTransitionEnd', fixedLoop);
|
|
|
if (self.isLoop) { //循环轮播自动重新定位
|
|
|
if (slideNumber === 1 || slideNumber === -slideLength) {
|
|
|
slideNumber = slideNumber === 1 ? (-slideLength + 1) : 0;
|
|
|
slider.addEventListener('webkitTransitionEnd', fixedLoop);
|
|
|
}
|
|
|
}
|
|
|
$.trigger(slider.parentNode, 'slide', {
|
|
|
slideNumber: Math.abs(slideNumber)
|
|
|
});
|
|
|
this.initTimer();
|
|
|
};
|
|
|
|
|
|
/**
|
|
|
* 计算轮播应该处于的位置(四舍五入)
|
|
|
* @returns {Number}
|
|
|
*/
|
|
|
Slider.prototype.getSlideNumber = function() {
|
|
|
return (Math.round(this.getScroll() / this.sliderWidth));
|
|
|
};
|
|
|
/**
|
|
|
* 当前所处位置
|
|
|
* @param {type} type
|
|
|
* @returns {unresolved}
|
|
|
*/
|
|
|
Slider.prototype.getCurrentSlideNumber = function(type) {
|
|
|
return (Math[type === 'next' ? 'ceil' : 'floor'](this.getScroll() / this.sliderWidth));
|
|
|
};
|
|
|
/**
|
|
|
* 获取当前滚动位置
|
|
|
* @returns {Number}
|
|
|
*/
|
|
|
Slider.prototype.getScroll = function() {
|
|
|
var slider = this.element;
|
|
|
var scroll = 0;
|
|
|
if ('webkitTransform' in slider.style) {
|
|
|
var result = $.parseTranslate(slider.style.webkitTransform);
|
|
|
scroll = result ? result.x : 0;
|
|
|
}
|
|
|
return scroll;
|
|
|
};
|
|
|
/**
|
|
|
* 自动轮播
|
|
|
* @returns {undefined}
|
|
|
*/
|
|
|
Slider.prototype.initTimer = function() {
|
|
|
var self = this;
|
|
|
var slideshowDelay = self.options.slideshowDelay;
|
|
|
if (slideshowDelay) {
|
|
|
var slider = self.element;
|
|
|
var slidershowTimer = slider.getAttribute('data-slidershowTimer');
|
|
|
slidershowTimer && window.clearTimeout(slidershowTimer);
|
|
|
slidershowTimer = window.setTimeout(function() {
|
|
|
if (!slider) {
|
|
|
return;
|
|
|
}
|
|
|
//仅slider显示状态进行自动轮播
|
|
|
if (!!(slider.offsetWidth || slider.offsetHeight)) {
|
|
|
self.nextItem();
|
|
|
//下一个
|
|
|
}
|
|
|
self.initTimer();
|
|
|
}, slideshowDelay);
|
|
|
slider.setAttribute('data-slidershowTimer', slidershowTimer);
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
$.fn.slider = function(options) {
|
|
|
//新增定时轮播 重要:remove该轮播时,请获取data-slidershowTimer然后手动clearTimeout
|
|
|
var slider = null;
|
|
|
this.each(function() {
|
|
|
var sliderGroup = this;
|
|
|
if (this.classList.contains(CLASS_SLIDER)) {
|
|
|
sliderGroup = this.querySelector('.' + CLASS_SLIDER_GROUP);
|
|
|
}
|
|
|
var id = sliderGroup.getAttribute('data-slider');
|
|
|
if (!id) {
|
|
|
id = ++$.uuid;
|
|
|
$.data[id] = slider = new Slider(sliderGroup, options);
|
|
|
sliderGroup.setAttribute('data-slider', id);
|
|
|
} else {
|
|
|
slider = $.data[id];
|
|
|
if (slider && options) {
|
|
|
slider.refresh(options);
|
|
|
}
|
|
|
}
|
|
|
});
|
|
|
return slider;
|
|
|
};
|
|
|
$.ready(function() {
|
|
|
$($.classSelector('.slider-group')).slider();
|
|
|
});
|
|
|
})(mui, window); |