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.

362 lines
11 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

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