hybridstart
Version:
A hybrid application development framework
308 lines (301 loc) • 10.1 kB
JavaScript
/*
* name: scroll-col.js
* version: v4.2.4
* update: 微信浏览器内无法滑动bug
* date: 2016-04-01
*/
define('scroll-col', function(require, exports, module) {
seajs.importStyle('.scroll{position:relative;overflow:hidden}\
.scroll_wrap{position:relative;width:100%;height:100%;}\
.scroll_c{float:left;top:0;left:0;height:100%;z-index:1}.scroll_nav{position:absolute;z-index:8}\
.arrs{position:absolute;cursor:pointer;z-index:9;-webkit-user-select:none;user-select:none}\
.arrs.unable{cursor:default}', module.uri);
require('easing');
var $ = window.$ || require('jquery');
var def = {
direct: 'left', // 自动播放方向,可选left | right
mode: '', // 特殊模式,可选 hero(全屏三图滚动) | unloop(不循环)
num: 99, // 显示个数
auto: true, // 自动播放
interval: 5e3, // 自动播放间隔
animate: 'swing', // 滚动效果,来自jquery.easing
duration: 640, // 滚动速度
step: 1, // 每次滚动个数
wrap: 'ul', // 滚动包裹元素
cell: 'li', // 滚动元素
prev: null, // 向左按钮,默认添加 '.arr_prev'
next: null, // 向右按钮,默认添加 '.arr_next'
handletouch: false, //是否屏蔽元素的触屏默认事件
callback: function(a) {}, // 回调 @param (nowStep)
ext: function(a, b, c) {} // 扩展 @param (this, showNumber, allStep)
};
$.fn.scrollCol = function(config) {
//FireFox有时会把window传进来
if ($.isWindow($(this).get(0))) return;
return $(this).each(function(i, e) {
var $this = $(e).addClass('scroll').fadeIn(160),
opt = $.extend({}, def, config || {}),
wrap = $this.find(opt.wrap).addClass('scroll_wrap'),
cells = wrap.find(opt.cell).addClass('scroll_c').width($this.find(opt.cell).width()),
cellWidth = cells.outerWidth(),
maxShow = Math.floor($this.width() / cellWidth),
showNumber = opt.num > maxShow ? maxShow : opt.num,
marginRight = (showNumber === 1) ? $this.width() - cellWidth : (Math.floor(($this.width() - cellWidth * showNumber) / (showNumber - 1) * 10) / 10),
cellOuterWidth = cellWidth + marginRight,
wrapLeft = 0,
wrapWidth,
scrollCore,
goNext,
goPrev,
allStep,
nowStep = 1,
onTouch,
$arrs,
$navs,
timer;
//已经初始化
if ($this.data('scrollinit')) {
return;
}
//滚不开
if (!showNumber) {
return console.log('滚动元素宽度超过容器宽度,无法滚动');
}
//处理步幅
if (opt.step > showNumber) {
opt.step = showNumber;
console.log('步幅(setp)达到上限,已调整为' + showNumber);
}
//添加按钮
if ($(opt.prev).length || $(opt.next).length) {
$arrs = $(opt.prev).add(opt.next);
} else {
if (!$this.children('.arr_prev').length && !$this.children('.arr_next').length) {
$this.append('<a href="###" class="arrs arr_prev" /><a href="###" class="arrs arr_next" />');
}
opt.prev = '.arr_prev';
opt.next = '.arr_next';
$arrs = $this.children('.arrs');
}
//预处理
switch (opt.mode) {
case 'unloop':
wrapWidth = cellOuterWidth * cells.length;
break;
case 'hero':
opt.step = 1;
showNumber = 3;
marginRight = 0;
cellOuterWidth = cellWidth;
wrapLeft = ($this.width() - cellWidth * 3) / 2;
wrapWidth = cellOuterWidth * (showNumber + opt.step);
break;
default:
wrapWidth = cellOuterWidth * (showNumber + opt.step);
}
//触屏事件
var movedStart,
moveDistance,
_startX,
_startY,
_moveX,
_moveY,
moveEnd = function(event) {
var e = event.originalEvent.touches[0];
onTouch = false;
wrap.css('transform', 'translate3d(0,0,0)');
e = null;
};
wrap.bind({
'touchstart': function(event) {
var e = event.originalEvent.touches[0];
_startX = e.pageX;
_startY = e.pageY;
if ($this.find(':animated').length) {
return;
}
onTouch = true;
movedStart = e.pageX;
e = null;
},
'touchmove': function(event) {
var e = event.originalEvent.touches[0],
_isDirect;
_moveX = Math.abs(e.pageX - _startX);
_moveY = Math.abs(e.pageY - _startY);
if(_isDirect === void(0)){
_isDirect = _moveY < _moveX;
};
if(opt.handletouch || _isDirect){
event.preventDefault();
};
moved = (e.pageX - movedStart) / 2;
wrap.css('transform', 'translate3d(' + moved + 'px,0,0)');
if (Math.abs(moved) > $this.width() / 5) {
onTouch = false;
wrap.css({
'transform': 'translate3d(0,0,0)',
'left': moved + 'px'
});
moved > 0 ? goPrev() : goNext();
}
},
'touchend': moveEnd,
'touchcancel': moveEnd
});
//初始样式
cells.css('margin-right', marginRight)
.each(function(i, e) {
i >= showNumber && (opt.mode !== 'unloop') && $(e).hide();
});
wrap.css({
'left': wrapLeft,
'width': wrapWidth
});
//总步数和当前步数
if (opt.mode === 'unloop') {
allStep = Math.ceil(cells.length - showNumber) / opt.step + 1;
} else {
allStep = Math.ceil((cells.length) / opt.step);
}
//添加导航
(function() {
var _links = '';
for (i = 0; i < allStep; i++) {
_links += ("<a" + (!!i ? "" : " class='on '") + ">" + (i + 1) + "</a>");
}
$this.children('.scroll_nav').remove()
.end().append('<div class="scroll_nav">' + _links + '</div>');
$navs = $this.find('.scroll_nav').children('a');
_links = null;
})();
//运行条件检测
if (cells.length < showNumber + opt.step) {
$arrs.addClass('unable');
typeof(opt.ext) === 'function' && opt.ext($this, showNumber, allStep);
console.log('$("' + $this.attr('class') + '") has no enough cells to scroll.');
return $this;
}
/*
* @ opt.step
* @ unloop模式
*/
scrollCore = function(i, unloop) {
$navs.eq(nowStep - 1).addClass('on').siblings().removeClass('on');
if (unloop) {
$this.children(opt.wrap).stop(1).animate({
left: -Math.abs(i) * (nowStep - 1) * cellOuterWidth
}, {
duration: opt.duration,
easing: opt.animate
});
} else {
if (i > 0) {
for (var o = 0; o < i; o++) {
$this.find(opt.wrap).find(opt.cell).eq(showNumber + o).show();
}
wrap.stop(1).animate({
left: -cellOuterWidth * i + wrapLeft
}, {
duration: opt.duration,
easing: opt.animate,
complete: function() {
for (var o = 0,absI = Math.abs(i); o < absI; o++) {
$this.find(opt.wrap).find(opt.cell).eq(0).hide().appendTo($this.children(opt.wrap))
}
$this.children(opt.wrap).css('left', wrapLeft);
}
});
} else if (i < 0) {
for (var o = 0, absI = Math.abs(i); o < absI; o++) {
$this.find(opt.wrap).find(opt.cell).eq(-1).show().prependTo($this.children(opt.wrap))
}
wrap.css('left', cellOuterWidth * i + wrapLeft).stop(1).animate({
left: wrapLeft
}, {
duration: opt.duration,
easing: opt.animate,
complete: function() {
for (var o = 0, absI = Math.abs(i); o < absI; o++) {
$this.find(opt.wrap).find(opt.cell).eq(showNumber + o).hide();
}
}
});
}
}
typeof(opt.callback) === 'function' && opt.callback(nowStep);
};
goNext = function() {
if ($this.find(':animated').length || onTouch) {
return;
}
nowStep < allStep ? ++nowStep : nowStep = 1;
scrollCore(opt.step, opt.mode == 'unloop');
};
goPrev = function() {
if ($this.find(':animated').length || onTouch) {
return;
}
nowStep > 1 ? --nowStep : nowStep = allStep;
scrollCore(-opt.step, opt.mode == 'unloop');
};
//绑定事件
$arrs.on('click', function(e) {
e.preventDefault();
if ($(this).is(opt.next)) {
goNext();
}
if ($(this).is(opt.prev)) {
goPrev();
}
});
$navs.on('click', function(e) {
e.preventDefault();
if ($this.find(':animated').length || onTouch) {
return;
}
/* 实现滚动最短寻址
* _direct:目标方向
* _forwardStep: 直线距离
* _backStep:绕行距离
* _solutionDirect:方案方向,直线1绕行-1
* _newStep:最短步数
*/
var _direct = $(this).index() + 1 > nowStep ? 1 : -1;
var _forwardStep = Math.abs($(this).index() + 1 - nowStep);
var _backStep = nowStep - (($(this).index() + 1) - cells.length);
if (_direct < 0) {
_backStep = ($(this).index() + 1) - (nowStep - cells.length);
}
var _solutionDirect = _forwardStep > _backStep ? -1 : 1;
var _newStep = _solutionDirect > 0 ? _solutionDirect * _direct * _forwardStep : _solutionDirect * _direct * _backStep;
nowStep = $(this).index() + 1;
scrollCore(_newStep * opt.step, opt.mode == 'unloop');
_direct = _forwardStep = _backStep = _solutionDirect = _newStep = null;
});
//标记
$this.data('scrollinit', true).parent().on('DOMNodeRemoved',function(e){
if($(e.target).is($this)){
//DOM移除后释放全局变量
timer && clearInterval(timer);
}
});
//执行扩展
typeof(opt.ext) === 'function' && opt.ext($this, showNumber, allStep);
//自动播放
if (opt.auto) {
timer = setInterval(function() {
(opt.direct == 'left') ? goNext(): goPrev()
}, opt.interval);
$this.hover(function() {
window.clearInterval(timer);
}, function() {
window.clearInterval(timer);
timer = window.setInterval(function() {
(opt.direct == 'left') ? goNext(): goPrev()
}, opt.interval);
});
}
});
};
});