最近接手了王总的一个.NET目,做着还挺有感觉,之前学过的知识又重拾起来了,收获很大!今天做的是前端的一个功能,要实现图片的滚动效果。之前没有做过类似的,所以查阅了很多资料,最终拼凑出来了,给大家分享一下。。
因为是一个动态效果,所以首先要做一个JS
(function( $ ) {
$.fn.promptumenu = function(options) {
// Here goes
var settings = $.extend({
'columns': 3,
'rows': 4,
'direction': 'horizontal',
'width': 'auto',
'height': 'auto',
'duration': 500,
'pages': true,
'showPage': true,
'inertia': 200
}, options);
return this.each(function(){
var $this = $(this);
var properties;
var cursor = {
x:0,
y:1,
page:1
};
var cells = {
'width': 0,
'height': 0,
'pages': 1,
'current_page': 1
};
var methods = {
//navigating to a specific page
go_to: function(index, easing, webkit){
if (easing === undefined){
easing = 'swing';
}
if(webkit === undefined){
webkit = false;
}
var anim, anim_css;
if(settings.direction == 'vertical'){
anim = {'top': (index - 1) * properties.height * (-1)};
anim_css = {'-webkit-transform': 'translate3d(0px, ' + ((index - 1) * properties.height * (-1)) + 'px, 0px)'};
} else {
anim = {'left': (index - 1) * properties.width * (-1)};
anim_css = {'-webkit-transform': 'translate3d(' + ((index - 1) * properties.width * (-1)) + 'px, 0px, 0px)'};
}
if(webkit){
$this.css({
'-webkit-transition-property': '-webkit-transform',
'-webkit-transition-duration': settings.duration + 'ms',
'-webkit-transition-timing-function': 'ease-out'
});
$this.css(anim_css);
$this.data('ppos', (index - 1) * properties.width * (-1));
}
if(navigator.userAgent.indexOf("Firefox")>0){
$this.animate(anim, settings.duration, easing);
}
if(!webkit && navigator.userAgent.indexOf("Firefox")<=0){
$this.animate(anim, settings.duration, easing);
}
$this.parent('.promptumenu_window').find('.promptumenu_nav a.active').removeClass('active');
$this.parent('.promptumenu_window').find('.promptumenu_nav a:nth-child(' + (index) + ')').addClass('active');
cells.current_page = index;
},
next_page: function(){
methods.go_to(cells.current_page + 1);
},
prev_page: function(){
methods.go_to(cells.current_page - 1);
}
};
if($this.data('promptumenu')){
//This element already has promptumenu set up
console.error('You are calling promptumenu for an element more than twice. Please have a look.');
} else {
//this element hasn't been initialized yet, so we set it up
$this.data('promptumenu', true);
$this.data('ppos', 0);
//take in mind the original css properties of the element, so we can preserve it's position.
properties = {
'width': (settings.width == 'auto') ? $this.width() : settings.width,
'height': (settings.height == 'auto') ? $this.height() : settings.height,
'margin': $this.css('margin'),
'position': ($this.css('position') == 'absolute') ? 'absolute' : 'relative',
'top': $this.css('top'),
'right': $this.css('right'),
'bottom': $this.css('bottom'),
'left': $this.css('left'),
'padding': 0,
'display': 'block',
'overflow': 'hidden'
};
cells.width = properties.width / settings.columns;
cells.height = properties.height / settings.rows;
$this.wrap('');
$this.parent('.promptumenu_window').css(properties);
$this.css({
'display': 'block',
'position': 'absolute',
'list-style': 'none',
'overflow': 'visible',
'height': 'auto',
'width': 'auto',
'top': 0,
'left': 10,
'margin': 0,
'padding': 0
});
//and set up each child element
$this.children('li').css({
'display': 'block',
'position': 'absolute',
'margin': 0
});
var lengths = $this.children('li').length;
$this.children('li').each(function(i){
var $li = $(this);
$li.css({"width":settings.width / settings.columns+"px"});
//Moving like a typewriter
cursor.x += 1;
//if we reach the end of columns, add a new line and reset typewriter
if(cursor.x > settings.columns){
cursor.x = 1;
cursor.y += 1;
}
//if we reach the end of the page, turn the page
if(cursor.y > settings.rows){
cursor.x = 1;
cursor.y = 1;
cursor.page += 1;
}
//attach each li information about it's position in the list
$li.data('layout', $.extend({},cursor));
if(settings.direction == 'vertical'){
// Lay the pages in a vertical order
$li.css({
'top': Math.round((cursor.y * cells.height - cells.height/2) - ($li.height()/2) + (cursor.page - 1) * properties.height),
'left': Math.round((cursor.x * cells.width - cells.width/2) - ($li.width()/2))
});
//this might be a silly approach.. but.. if the list contains an image.. I want to
//reposition the li.. because before we didn't know the dimensions of image
$li.find('img').bind('load', function(){
var cursor = $li.data('layout');
$li.css({
'top': Math.round((cursor.y * cells.height - cells.height/2) - ($li.height()/2) + (cursor.page - 1) * properties.height),
'left': Math.round((cursor.x * cells.width - cells.width/2) - ($li.width()/2))
});
});
} else {
//Math.round((cursor.x * cells.width - cells.width/2) - ($li.width()/2) + (cursor.page - 1) * properties.width)
var li_left = cells.width*i;
//Lay the pages in a horizontal order
$li.css({
'top': Math.round((cursor.y * cells.height - cells.height/2) - ($li.height()/2)),
'left': li_left
});
//the same approach for images for the horizontal order
$li.find('img').bind('load', function(){
var cursor = $li.data('layout');
$li.css({
'top': Math.round((cursor.y * cells.height - cells.height/2) - ($li.height()/2)),
'left': li_left
});
});
}
});
cells.pages = cursor.page;
$this.data('promptumenu_page_count', cells.pages);
//and append the navigation buttons for each page
if(cells.pages > 1 && settings.pages == true && settings.showPage == true){
var page_links = 'Page 1';
for(i = 2; i <= cells.pages; i++){
page_links = page_links + 'Page ' + i + '';
}
$this.parent('div.promptumenu_window').append(' ');
//bind the nav buttons to navigate to the specific page
$this.parent('div.promptumenu_window').find('.promptumenu_nav a').bind('click.promptumenu', function(){
methods.go_to($(this).index() + 1);
});
}
//Make the list size appropriate, so that it could be dragged
//(or else users will be able to drag only by clicking the icons, but clicking
// on background will not activate dragging)
if(settings.direction == 'vertical'){
$this.css({
'width': properties.width,
'height': properties.height * cells.pages
});
} else {
$this.css({
'width': properties.width * cells.pages,
'height': properties.height
});
}
//Binding all the drag movements
$this.bind('mousedown.promptumenu', function(mdown){
mdown.preventDefault();
$this.stop(true, false);
var init_pos = $this.position();
var click = {
'x': mdown.pageX,
'y': mdown.pageY
};
var delta = {
'x': 0,
'y': 0
};
var mmove_event = new Array();
//bind the mousemove to moving the list
$(document).bind('mousemove.promptumenu', function(mmove){
mmove.preventDefault();
var date = new Date();
var this_event = {
'time': date.getTime(),
'x': mmove.pageX,
'y': mmove.pageY
};
//I want to get the average of the last 6 mousemove events before mouseup
while(mmove_event.length > 4){
mmove_event.shift();
}
if(settings.direction == 'vertical'){
delta.y = mmove.pageY - click.y;
$this.css('top', init_pos.top + delta.y);
} else {
delta.x = mmove.pageX - click.x;
$this.css('left', init_pos.left + delta.x);
//$this.css('-webkit-transform', 'translate3d(' + (init_pos.left + delta.x) + 'px, 0, 0)');
}
mmove_event.push(this_event);
});
//bind the mouseup to unbinding and animating to the appropriate page
$(document).bind('mouseup.promptumenu', function(mup){
mup.preventDefault();
$(document).unbind('.promptumenu');
var date = new Date();
var delta_start = mmove_event[0];
if(delta_start==undefined)
{
return;
}
var delta_end = {
'time': date.getTime(),
'x': mup.pageX,
'y': mup.pageY
};
var event_delta = {
'time': (delta_end.time - delta_start.time),
'x': (delta_end.x - delta_start.x),
'y': (delta_end.y - delta_start.y)
};
var speed = {
'x': event_delta.x/event_delta.time,
'y': event_delta.y/event_delta.time
};
//console.log(mmove_event);
//console.log('The time delta is: ' + (delta_end.time - delta_start.time));
//console.log('The y_speed was: ' + (event_delta.y/event_delta.time));
//And now we can animate the list with the appropriate distance and speed
if(settings.direction == 'vertical'){
var pos = init_pos.top + delta.y + speed.y * settings.inertia;
//check if the user hasn't dragged over the end..
if(pos < ((-1) * properties.height * (cells.pages - 1))){
pos = (-1) * properties.height * (cells.pages - 1);
} else if(pos > 0){
pos = 0;
}
//if the pages are being displayed, we want to snap to the specific page
if(settings.pages){
var snap_to_page = Math.round((- pos) / properties.height);
methods.go_to(snap_to_page + 1, 'inertia');
} else {
$this.animate({
'top': pos
}, Math.abs(speed.y * settings.inertia), 'inertia');
}
} else {
var pos = init_pos.left + delta.x + speed.x * settings.inertia;
//check if the user hasn't dragged over the end..
if(pos < ((-1) * properties.width * (cells.pages - 1))){
pos = (-1) * properties.width * (cells.pages - 1);
} else if(pos > 0){
pos = 0;
}
//if the pages are being displayed, we want to snap to the specific page
if(settings.pages){
var snap_to_page = Math.round((- pos) / properties.width);
methods.go_to(snap_to_page + 1, 'inertia');
} else {
$this.animate({
'left': pos
}, Math.abs(speed.x * settings.inertia), 'inertia');
}
}
});
});
try {
//And here we do basically the same again to bind swiping on mobile devices like iPhone, iPad, android, etc
var tinit_pos, tclick, tdelta;
var tmove_event = new Array();
var touchmove = function(tmove){
tmove.preventDefault();
var date = new Date();
var this_event = {
'time': date.getTime(),
'x': tmove.touches[0].pageX,
'y': tmove.touches[0].pageY
};
//I want to get the average of the last 6 mousemove events before mouseup
while(tmove_event.length > 4){
tmove_event.shift();
}
if(settings.direction == 'vertical'){
tdelta.y = tmove.touches[0].pageY - tclick.y;
//$this.css('top', tinit_pos.top + tdelta.y);
$this.css('-webkit-transform', 'translate3d(0px, ' + (tinit_pos + tdelta.y) + 'px, 0px)');
} else {
tdelta.x = tmove.touches[0].pageX - tclick.x;
//$this.css('left', tinit_pos.left + tdelta.x);
$this.css('-webkit-transform', 'translate3d(' + (tinit_pos + tdelta.x) + 'px, 0px, 0px)');
}
tmove_event.push(this_event);
};
var touchend = function(tend){
tend.preventDefault();
document.removeEventListener('touchmove', touchmove, false);
document.removeEventListener('touchend', touchend, false);
var date = new Date();
var delta_start = tmove_event[0];
//alert(tend.touches[0].pageX);
if(delta_start==undefined)
{
return;
}
var delta_end = tmove_event[tmove_event.length-1];
var event_delta = {
'time': (delta_end.time - delta_start.time),
'x': (delta_end.x - delta_start.x),
'y': (delta_end.y - delta_start.y)
};
var speed = {
'x': event_delta.x/event_delta.time,
'y': event_delta.y/event_delta.time
};
//alert('speed_x: ' + speed.x + '\nspeed_y: ' + speed.y);
//And now we can animate the list with the appropriate distance and speed
if(settings.direction == 'vertical'){
if(isNaN(speed.y)){
speed.y = 2;
}
$this.css({
'-webkit-transition-duration': Math.abs(speed.y * settings.inertia * 3) + 'ms',
'-webkit-transition-timing-function': 'ease-out'
});
var pos = tinit_pos + tdelta.y + speed.y * settings.inertia;
//check if the user hasn't dragged over the end..
if(pos < ((-1) * properties.height * (cells.pages - 1))){
pos = (-1) * properties.height * (cells.pages - 1);
} else if(pos > 0){
pos = 0;
}
//if the pages are being displayed, we want to snap to the specific page
if(settings.pages){
var snap_to_page = Math.round((- pos) / properties.height);
methods.go_to(snap_to_page + 1, 'inertia', true);
} else {
$this.css('-webkit-transform', 'translate3d(0px, ' + pos + 'px, 0px)');
$this.data('ppos', pos);
}
} else {
//alert('init pos: ' + tinit_pos + '\ndelta x: ' + tdelta.x + '\nspeed: ' + speed.x);
//if user swipes very fast, sometimes not enough touchmove events get caught, and speed is NaN
if(isNaN(speed.x)){
speed.x = 2;
}
$this.css({
'-webkit-transition-duration': Math.abs(speed.y * settings.inertia * 3) + 'ms',
'-webkit-transition-timing-function': 'ease-out'
});
var pos = tinit_pos + tdelta.x + speed.x * settings.inertia;
//check if the user hasn't dragged over the end..
if(pos < ((-1) * properties.width * (cells.pages - 1))){
pos = (-1) * properties.width * (cells.pages - 1);
} else if(pos > 0){
pos = 0;
}
//if the pages are being displayed, we want to snap to the specific page
if(settings.pages){
var snap_to_page = Math.round((- pos) / properties.width);
methods.go_to(snap_to_page + 1, 'inertia', true);
} else {
$this.css('-webkit-transform', 'translate3d(' + pos + 'px, 0px, 0px)');
$this.data('ppos', pos);
//alert(pos);
}
}
};
//touch start event
$this[0].addEventListener('touchstart', function(tstart){
//alert('touchstart');
//disable the mouse events
$this.unbind('.promptumenu');
//tstart.preventDefault();
$this.stop(true, false);
$this.css({
'-webkit-transition-duration': '0ms'
});
var date = new Date();
tinit_pos = $this.data('ppos');
tclick = {
'x': tstart.touches[0].pageX,
'y': tstart.touches[0].pageY,
'time': date.getTime()
};
tdelta = {
'x': 0,
'y': 0
};
tmove_event = new Array();
//and we can now bind the touch move event
document.addEventListener('touchmove', touchmove, false);
//and the touch end event
document.addEventListener('touchend', touchend, false);
document.addEventListener('touchcancel', touchend, false);
}, false);
} catch(error) {
//apparently this browser wont support swiping
//alert(error);
}
}
});
};
})( jQuery );
//Easing for inertia when dragging
jQuery.extend(jQuery.easing, {
inertia: function (x, t, b, c, d) {
return c*((t=t/d-1)*t*t + 1) + b;
}
});
$(function(){
$('ul.promptu-menu').promptumenu({width:400, height:100, rows: 1, columns: 4, direction: 'horizontal', pages: true});
$('ul.promptu-menu2').promptumenu({width:360, height:100, rows: 1, columns: 4, direction: 'horizontal', pages: false});
});
然后在aspx页面添加图片和引用JS,这样就达到了咱们想要的效果。。
总结
刚开始不懂没关系,但一定要去研究它,点滴积累,聚沙成塔。。