hybridstart
Version:
A hybrid application development framework
463 lines (457 loc) • 20.8 kB
JavaScript
/*
* name: slide.js
* version: v4.5.0
* update: add data.attribute
* date: 2017-08-01
*/
define('slide', function(require, exports, module) {
"use strict";
seajs.importStyle('.slide{position:relative;overflow:hidden;}\
.slide img[slide-src]{opacity:0}\
.slide_wrap{position:relative;width:100%}\
.slide_wrap img{max-width: none;}\
.slide_c{position:absolute;top:0;left:0;width:100%;height:100%;overflow:hidden;display:none}\
.slide_effect_toggle .active{display:block}\
.slide_effect_slide .active{position:relative;display:block;margin:auto}\
.slide_effect_slide .slide_prev{left:0;display:block}\
.slide_effect_slide .slide_next{left:auto;right:0;display:block}\
.slide_nav{position:absolute;left:0;bottom:0;width:100%;z-index:8;text-align:center}\
.slide_nav a{display:inline-block;width:0.8em;height:0.8em;border-radius:0.4em;overflow:hidden;text-indent:-99px;background:#fff;margin:0 0.5em 1em;cursor:pointer}\
.slide_nav .on{background:#999;}\
.slide .arrs{position:absolute;cursor:pointer;z-index:9;-webkit-user-select:none;user-select:none}\
.arrs.unable{cursor:default}', module.uri);
var $ = window.$ || require('jquery'),
base = require('base'),
def = {
el: null,
data: null,
wrap: 'ul',
cell: 'li',
effect: 'slide', //切换 slide | fade
direction: 'x', //slide方向
animate: 'ease',
duration: 300,
start: 0,
auto: true,
pause: true, // true | false | (jquery selector)
interval: 5e3,
act: "click",
prevHtml: "",
nextHtml: "",
prev: null,
next: null,
navs: null,
lazyload: true,
handletouch: false,
onSlide: null,
onReady: null
},
getPrev = function(number, _step, slideLength) {
_step = _step || 1;
number = number <= 0 ? slideLength - _step : number - _step;
return number;
},
getNext = function(number, _step, slideLength) {
_step = _step || 1;
number = number >= slideLength - _step ? 0 : number + _step;
return number;
},
setNavs = function($navs, slideLength, current, step) {
var _prev = getPrev(current, step, slideLength),
_next = getNext(current, step, slideLength);
$navs.removeClass('on nav_prev nav_next')
.eq(current).addClass('on')
.end().eq(_prev).addClass("nav_prev")
.end().eq(_next).addClass("nav_next");
};
var Slide = function(config) {
var opt = $.extend({}, def, config || {}),
$this = $(opt.el),
$wrap,
$slides,
slideLength,
timer,
$navs,
$arrs,
originIndex = 0,
width = 0,
H,
efftct,
init,
windowLock = false;
if (!$this.length || $this.data('slide-init')) {
return $this;
}
if ($this.css('height').indexOf('%') > 0) {
H = parseInt($this.parent().css('height')) * ($this.css('height').split('%')[0] / 100);
} else {
H = parseInt($this.outerHeight());
}
//应用数据
var slideNode;
if($.isArray(opt.data)){
$.extend(opt, {
wrap: 'ul',
cell: 'li'
});
slideNode = '<ul>';
$.each(opt.data, function(i, e){
var attribute = '';
if($.isPlainObject(e.attribute)){
var attrName;
for(attrName in e.attribute){
if(e.attribute.hasOwnProperty(attrName)){
attribute += (' ' + attrName + '="' + e.attribute[attrName] + '"');
}
}
}
slideNode += ('<li'+attribute+'><a href="'+ (e.link || 'javascript:;') +'"><img ' + (opt.lazyload ? 'slide-src="' : 'src="') + (e.src || '') + '" alt="'+ (e.alt || '') +'"></a></li>')
});
slideNode += '</ul>';
}
$this.prepend(slideNode);
//运行条件检测
$wrap = $this.find(opt.wrap).eq(0);
$slides = $wrap.find(opt.cell);
slideLength = $slides.length;
if (slideLength <= 1) {
$this.addClass('unable');
$wrap.css({
'height': H
}).addClass('slide_wrap');
$slides.unbind().addClass('slide_c')._loadimg('slide-src').show();
typeof(opt.onReady) === 'function' && opt.onReady($this, $slides, slideLength);
return $this;
}
$this.addClass('slide slide_effect_' + opt.effect);
//初始化
(function() {
var _Target, _Direction, _Distance, _touchAction;
init = function() {
if (opt.effect === 'slide') {
var touchStart,
_distance,
_startX,
_startY,
_moveX,
_moveY,
_isDirect,
moveEnd = function(event) {
var e = event.originalEvent.touches[0];
$this.removeClass('ontouch');
_isDirect = void(0);
if (windowLock || $this.data('moveTrigger')) {
return;
}
if (Math.abs(_distance) > _Distance / 4 || (_touchAction && _touchAction.split)) {
if (_distance < 0 || _touchAction == 'next') {
efftct(getNext(originIndex, 1, slideLength), 1);
} else if (_distance > 0 || _touchAction == 'prev') {
efftct(getPrev(originIndex, 0, slideLength), 0);
}
_touchAction = null;
} else {
$wrap.css('transition', 'all ' + opt.duration / 2 + 'ms ' + opt.animate)._css(_Direction, -_Distance + 'px');
setTimeout(function() {
$wrap.css('transition', 'all 0s');
}, opt.duration);
}
},
_wrapcss = {};
if (opt.direction === 'y') {
_Target = 'height';
_Direction = 'top';
_Distance = H;
} else {
_Target = 'width';
_Direction = 'left';
if ($this.css(_Target).indexOf('%') > 0) {
_Distance = parseInt($this.parent().css(_Target)) * ($this.css('width').split('%')[0] / 100);
} else {
_Distance = parseInt($this.css(_Target));
}
}
_wrapcss.height = H;
_wrapcss[_Target] = _Distance * 3 + 'px';
$slides.css(_Target, _Distance + 'px').addClass('slide_c');
$wrap._css(_Direction, -_Distance + 'px')
.css(_wrapcss)
.addClass('slide_wrap')
.bind({
'touchstart': function(event) {
var e = event.originalEvent.touches[0];
_startX = e.pageX;
_startY = e.pageY;
if (opt.direction === 'y') {
touchStart = _startY;
} else {
touchStart = _startX;
}
opt.auto && clearInterval(timer);
$this.addClass('ontouch').data('moveTrigger', true);
},
'touchmove': function(event) {
var e = event.originalEvent.touches[0];
_moveX = Math.abs(e.pageX - _startX);
_moveY = Math.abs(e.pageY - _startY);
if (_isDirect === void(0)) {
if (opt.direction === 'y') {
_isDirect = _moveY > _moveX;
} else {
_isDirect = _moveY < _moveX;
}
if (opt.handletouch || _isDirect) {
event.preventDefault();
}
return $this.data('moveTrigger', false);
}
if (opt.handletouch || _isDirect) {
event.preventDefault();
}
if (windowLock) {
return $this.data('moveTrigger', false);
}
if (opt.direction === 'y') {
_distance = e.pageY - touchStart;
} else {
_distance = e.pageX - touchStart;
}
$wrap._css(_Direction, -_Distance + _distance + 'px');
if (_distance < 0) {
$slides.eq(getNext(originIndex, 1, slideLength))._loadimg('slide-src');
}
if (_distance > 0) {
$slides.eq(getPrev(originIndex, 1, slideLength))._loadimg('slide-src');
}
},
'touchend': moveEnd,
'touchcancel': moveEnd
});
} else {
$wrap.css({
'height': H
}).addClass('slide_wrap');
$slides.addClass('slide_c');
}
};
//核心方法
efftct = function(current, direct, step, isInit) {
var toggleCellClass = function(current, direct, step) {
var _prev = getPrev(current, step, slideLength),
_next = getNext(current, step, slideLength);
$slides.filter('.active').removeClass('active').end()
.filter('.slide_prev').removeClass('slide_prev').end()
.filter('.slide_next').removeClass('slide_next').end()
.eq(_prev).addClass('slide_prev').end()
.eq(_next).addClass('slide_next').end()
.eq(current)._loadimg('slide-src').addClass('active');
};
windowLock = true;
setNavs($navs, slideLength, current, step);
switch (opt.effect) {
case 'fade':
toggleCellClass(current);
if (isInit) {
$slides.eq(current)._loadimg('slide-src').addClass('active').show();
} else {
$slides.fadeOut(opt.duration)
.eq(current)._loadimg('slide-src').fadeIn(opt.duration * 1.5, function() {
$(this).addClass('active');
});
}
break;
case 'slide':
direct == void(0) && (direct = true);
var wrap_move = direct ? -_Distance * 2 : 0;
if (isInit) {
toggleCellClass(current);
} else {
if(step>1){
if(!direct || (current===0 && step === slideLength-1)){
$slides.filter('.slide_prev').removeClass('slide_prev').end().eq(current).removeClass('slide_next').addClass('slide_prev');
}else{
$slides.filter('.slide_next').removeClass('slide_next').end().eq(current).removeClass('slide_prev').addClass('slide_next');
}
}
$wrap.css('transition', 'all ' + opt.duration + 'ms ' + opt.animate)._css(_Direction, wrap_move + 'px');
setTimeout(function() {
$wrap.css('transition', 'all 0s')._css(_Direction, -_Distance + 'px');
toggleCellClass(current, direct, 1);
}, opt.duration);
}
break;
default:
console.warn('slide():effect参数不合法!');
break;
}
originIndex = current;
$this.data('play', originIndex);
setTimeout(function() {
typeof(opt.onSlide) === 'function' && opt.onSlide($this, $slides, originIndex);
windowLock = false;
}, opt.duration);
};
})();
init();
//添加导航
(function() {
var appendNav = function() {
var _links = '',
i = 0;
for (; i < slideLength; i++) {
_links += ("<a>" + (i + 1) + "</a>");
}
$navs.empty().append(_links);
},
navIllegal = function() {
if ($navs.children('a').length !== slideLength) {
console.log('指定的"slide_navs"数量不匹配,将自动生成"slide_navs".');
return true;
} else {
return false;
}
};
if (opt.navs) {
if ($(opt.navs).length === 1) {
$navs = $(opt.navs);
if ($navs.attr('custom') == void(0) || ($navs.attr('custom') != void(0) && navIllegal())) {
appendNav();
}
} else {
console.log('只能指定唯一的slide_navs容器');
return;
}
} else if ($this.children(".slide_nav").length) {
$navs = $this.children(".slide_nav").eq(0);
if (navIllegal()) {
appendNav();
}
} else {
$navs = $('<div class="slide_nav"></div>');
appendNav();
$this.append($navs);
}
$navs = $navs.children('a');
})();
//添加左右按钮
if ($(opt.prev).length || $(opt.next).length) {
$arrs = $(opt.prev).addClass('arr_prev').add($(opt.next).addClass('arr_next'));
} else {
$this.find(opt.prev).remove()
.end().find(opt.next).remove()
.end().append('<a href="###" class="arrs arr_prev" /><a href="###" class="arrs arr_next" />');
$arrs = $this.children('.arrs');
}
if (opt.prevHtml && opt.prevHtml.split) {
$arrs.filter('.arr_prev').html(opt.prevHtml);
}
if (opt.nextHtml && opt.nextHtml.split) {
$arrs.filter('.arr_next').html(opt.nextHtml);
}
//初始化导航
setNavs($navs, slideLength, opt.start);
//事件绑定
if ($navs.length) {
$navs.on(opt.act, function(e) {
e.preventDefault();
e.stopPropagation();
var index = $(this).index(),
_dir, _step;
if (windowLock || $this.hasClass('ontouch') || index >= slideLength || $(this).hasClass("on")) {
return null;
}
//初始加载
if (index === originIndex) {
originIndex = slideLength - 1;
_dir = 1;
efftct(index, _dir);
return null;
}
_step = index - originIndex;
_dir = _step > 0 ? true : false;
efftct(index, _dir, Math.abs(_step));
});
}
if ($arrs.length) {
$arrs.on('click', function(e) {
e.preventDefault();
if (windowLock || $this.hasClass('ontouch')) {
return null;
}
if ($(this).hasClass('arr_prev')) {
efftct(getPrev(originIndex, 0, slideLength), 0);
}
if ($(this).hasClass('arr_next')) {
efftct(getNext(originIndex, 1, slideLength), 1);
}
});
}
//自动 & 暂停
if (opt.auto) {
timer = setInterval(function() {
efftct(getNext(originIndex, 1, slideLength), 1);
}, opt.interval);
if (opt.pause === true) {
$this.on({
'mouseenter': function() {
clearInterval(timer);
},
'mouseleave': function() {
clearInterval(timer);
timer = setInterval(function() {
efftct(getNext(originIndex, 1, slideLength), 1);
}, opt.interval);
}
});
} else if (opt.pause.split && $(opt.pause).length) {
$(opt.pause).on('click', function(e) {
e.preventDefault();
if ($this.data('slidepause')) {
$this.data('slidepause', false);
$(this).removeClass('pause');
clearInterval(timer);
timer = setInterval(function() {
efftct(getNext(originIndex, 1, slideLength), 1);
}, opt.interval);
} else {
$this.data('slidepause', true);
$(this).addClass('pause');
clearInterval(timer);
}
});
}
}
$this.data('slide-init', 1).fadeIn(300)
.parent().on('DOMNodeRemoved', function(e) {
if ($(e.target).is($this)) {
//DOM移除后释放全局变量
timer && clearInterval(timer);
}
});
//开始
if ($this.data('play')) {
$navs.eq($this.data('play')).trigger(opt.act);
} else {
efftct(opt.start, true, 1, true);
}
//响应式
$(window).bind("orientationchange, resize", function(event) {
if (windowLock) {
return null;
}
windowLock = true;
init();
efftct($this.data('play'), true, 1, true);
setTimeout(function() {
windowLock = false;
}, 0);
});
typeof(opt.onReady) === 'function' && opt.onReady($this, $slides, slideLength);
};
$.fn.slide = function(config) {
return Slide($.extend({
el: this
}, config || {}));
};
module.exports = Slide;
});