他们如何制作一个页面滚动网站:http://www.creativejin.com/
有效果和滚动。只用鼠标! 他们正在使用gif图像,但他们的位置随着滚动而移动!
这是一个很棒的想法,但我不确定它们是如何制作的,它背后的基础是什么,任何人都能给我一个线索吗?
也许我的答案是overscroll.js,但有人请解释一下吗?
/*jslint onevar: true, strict: true */
/*global window, document, setTimeout, clearTimeout, jQuery */
(function(global, dom, browser, math, wait, cancel, namespace, $, none){
// We want to run this plug-in in strict-mode
// so that we may benefit from any optimizations
// strict execution
'use strict';
// The key used to bind-instance specific data to an object
var datakey = 'overscroll',
// runs feature detection for overscroll
compat = (function(){
var b = $.browser, fallback,
agent = browser.userAgent,
style = dom.createElement(datakey).style,
prefix = b.webkit ? 'webkit' : (b.mozilla ? 'moz' : (b.msie ? 'ms' : (b.opera ? 'o' : ''))),
cssprefix = prefix ? ['-','-'].join(prefix) : '';
compat = { prefix: prefix, overflowScrolling: false };
$.each(prefix ? [prefix, ''] : [prefix], function(i, prefix){
var animator = prefix ? (prefix + 'RequestAnimationFrame') : 'requestAnimationFrame',
scroller = prefix ? (prefix + 'OverflowScrolling') : 'overflowScrolling';
// check to see if requestAnimationFrame is available
if (global[animator] !== none) {
compat.animate = function(callback){
global[animator].call(global, callback);
};
}
// check to see if overflowScrolling is available
if (style[scroller] !== none) {
// Chrome 19 introduced overflow scrolling. Unfortunately, their touch
// implementation is incomplete. Hence, we act like it is not supported
// for chrome. #59
if (agent.indexOf('Chrome') < 0) {
compat.overflowScrolling = cssprefix + 'overflow-scrolling';
}
}
});
// check to see if the client supports touch
compat.touchEvents = 'ontouchstart' in global;
// fallback to set timeout for no animation support
if (!compat.animate) {
compat.animate = function(callback) {
wait(callback, 1000/60);
};
}
// firefox and webkit browsers support native grabbing cursors
if (prefix === 'moz' || prefix === 'webkit') {
compat.cursorGrab = cssprefix + 'grab';
compat.cursorGrabbing = cssprefix + 'grabbing';
// other browsers can user google's assets
} else {
fallback = 'https://mail.google.com/mail/images/2/';
compat.cursorGrab = 'url('+fallback+'openhand.cur), default';
compat.cursorGrabbing = 'url('+fallback+'closedhand.cur), default';
}
return compat;
})(),
// These are all the events that could possibly
// be used by the plug-in
events = {
drag: 'mousemove touchmove',
end: 'mouseup mouseleave click touchend touchcancel',
hover: 'mouseenter mouseleave',
ignored: 'select dragstart drag',
scroll: 'scroll',
start: 'mousedown touchstart',
wheel: 'mousewheel DOMMouseScroll'
},
// These settings are used to tweak drift settings
// for the plug-in
settings = {
captureThreshold: 3,
driftDecay: 1.1,
driftSequences: 22,
driftTimeout: 100,
scrollDelta: 15,
thumbOpacity: 0.7,
thumbThickness: 6,
thumbTimeout: 400,
wheelDelta: 20
},
// These defaults are used to complement any options
// passed into the plug-in entry point
defaults = {
cancelOn: 'select,input,textarea',
direction: 'multi',
dragHold: false,
hoverThumbs: false,
scrollDelta: settings.scrollDelta,
showThumbs: true,
persistThumbs: false,
wheelDelta: settings.wheelDelta,
wheelDirection: 'vertical',
zIndex: 999
},
// Triggers a DOM event on the overscrolled element.
// All events are namespaced under the overscroll name
triggerEvent = function (event, target) {
target.trigger('overscroll:' + event);
},
// Utility function to return a timestamp
time = function() {
return (new Date()).getTime();
},
// Captures the position from an event, modifies the properties
// of the second argument to persist the position, and then
// returns the modified object
capturePosition = function (event, position, index) {
position.x = event.pageX;
position.y = event.pageY;
position.time = time();
position.index = index;
return position;
},
// Used to move the thumbs around an overscrolled element
moveThumbs = function (thumbs, sizing, left, top) {
var ml, mt;
if (thumbs && thumbs.added) {
if (thumbs.horizontal) {
ml = left * (1 + sizing.container.width / sizing.container.scrollWidth);
mt = top + sizing.thumbs.horizontal.top;
thumbs.horizontal.css('margin', mt + 'px 0 0 ' + ml + 'px');
}
if (thumbs.vertical) {
ml = left + sizing.thumbs.vertical.left;
mt = top * (1 + sizing.container.height / sizing.container.scrollHeight);
thumbs.vertical.css('margin', mt + 'px 0 0 ' + ml + 'px');
}
}
},
// Used to toggle the thumbs on and off
// of an overscrolled element
toggleThumbs = function (thumbs, options, dragging) {
if (thumbs && thumbs.added && !options.persistThumbs) {
if (dragging) {
if (thumbs.vertical) {
thumbs.vertical.stop(true, true).fadeTo('fast', settings.thumbOpacity);
}
if (thumbs.horizontal) {
thumbs.horizontal.stop(true, true).fadeTo('fast', settings.thumbOpacity);
}
} else {
if (thumbs.vertical) {
thumbs.vertical.fadeTo('fast', 0);
}
if (thumbs.horizontal) {
thumbs.horizontal.fadeTo('fast', 0);
}
}
}
},
// Defers click event listeners to after a mouseup event.
// Used to avoid unintentional clicks
deferClick = function (target) {
var clicks, key = 'events';
var events = $._data ? $._data(target[0], key) : target.data(key);
if (events && events.click) {
clicks = events.click.slice();
target.off('click').one('click', function(event){
$.each(clicks, function(i, click){
target.click(click);
}); return false;
});
}
},
// Toggles thumbs on hover. This event is only triggered
// if the hoverThumbs option is set
hover = function (event) {
var data = event.data,
thumbs = data.thumbs,
options = data.options,
dragging = event.type === 'mouseenter';
toggleThumbs(thumbs, options, dragging);
},
// This function is only ever used when the overscrolled element
// scrolled outside of the scope of this plugin.
scroll = function (event) {
var data = event.data;
if (!data.flags.dragged) {
moveThumbs(data.thumbs, data.sizing, this.scrollLeft, this.scrollTop);
}
},
// handles mouse wheel scroll events
wheel = function (event) {
// prevent any default wheel behavior
event.preventDefault();
var data = event.data,
options = data.options,
sizing = data.sizing,
thumbs = data.thumbs,
wheel = data.wheel,
flags = data.flags, delta,
original = event.originalEvent;
// stop any drifts
flags.drifting = false;
// calculate how much to move the viewport by
// TODO: let's base this on some fact somewhere...
if (original.wheelDelta) {
delta = original.wheelDelta / (compat.prefix === 'o' ? -120 : 120);
} if (original.detail) {
delta = -original.detail / 3;
} delta *= options.wheelDelta;
// initialize flags if this is the first tick
if (!wheel) {
data.target.data(datakey).dragging = flags.dragging = true;
data.wheel = wheel = { timeout: null };
toggleThumbs(thumbs, options, true);
}
// actually modify scroll offsets
if (options.wheelDirection === 'horizontal') {
this.scrollLeft -= delta;
} else {
this.scrollTop -= delta;
}
if (wheel.timeout) { cancel(wheel.timeout); }
moveThumbs(thumbs, sizing, this.scrollLeft, this.scrollTop);
wheel.timeout = wait(function() {
data.target.data(datakey).dragging = flags.dragging = false;
toggleThumbs(thumbs, options, data.wheel = null);
}, settings.thumbTimeout);
},
// updates the current scroll offset during a mouse move
drag = function (event) {
event.preventDefault();
var data = event.data,
touches = event.originalEvent.touches,
options = data.options,
sizing = data.sizing,
thumbs = data.thumbs,
position = data.position,
flags = data.flags,
target = data.target.get(0);
// correct page coordinates for touch devices
if (compat.touchEvents && touches && touches.length) {
event = touches[0];
}
if (!flags.dragged) {
toggleThumbs(thumbs, options, true);
}
flags.dragged = true;
if (options.direction !== 'vertical') {
target.scrollLeft -= (event.pageX - position.x);
}
if (data.options.direction !== 'horizontal') {
target.scrollTop -= (event.pageY - position.y);
}
capturePosition(event, data.position);
if (--data.capture.index <= 0) {
data.target.data(datakey).dragging = flags.dragging = true;
capturePosition(event, data.capture, settings.captureThreshold);
}
moveThumbs(thumbs, sizing, target.scrollLeft, target.scrollTop);
},
// sends the overscrolled element into a drift
drift = function (target, event, callback) {
var data = event.data, dx, dy, xMod, yMod,
capture = data.capture,
options = data.options,
sizing = data.sizing,
thumbs = data.thumbs,
elapsed = time() - capture.time,
scrollLeft = target.scrollLeft,
scrollTop = target.scrollTop,
decay = settings.driftDecay;
// only drift if enough time has passed since
// the last capture event
if (elapsed > settings.driftTimeout) {
return callback(data);
}
// determine offset between last capture and current time
dx = options.scrollDelta * (event.pageX - capture.x);
dy = options.scrollDelta * (event.pageY - capture.y);
// update target scroll offsets
if (options.direction !== 'vertical') {
scrollLeft -= dx;
} if (options.direction !== 'horizontal') {
scrollTop -= dy;
}
// split the distance to travel into a set of sequences
xMod = dx / settings.driftSequences;
yMod = dy / settings.driftSequences;
triggerEvent('driftstart', data.target);
data.drifting = true;
// animate the drift sequence
compat.animate(function render() {
if (data.drifting) {
var min = 1, max = -1;
data.drifting = false;
if (yMod > min && target.scrollTop > scrollTop || yMod < max && target.scrollTop < scrollTop) {
data.drifting = true;
target.scrollTop -= yMod;
yMod /= decay;
}
if (xMod > min && target.scrollLeft > scrollLeft || xMod < max && target.scrollLeft < scrollLeft) {
data.drifting = true;
target.scrollLeft -= xMod;
xMod /= decay;
}
moveThumbs(thumbs, sizing, target.scrollLeft, target.scrollTop);
compat.animate(render);
} else {
triggerEvent('driftend', data.target);
callback(data);
}
});
},
// starts the drag operation and binds the mouse move handler
start = function (event) {
var data = event.data,
target = data.target,
start = data.start = $(event.target),
flags = data.flags;
// stop any drifts
flags.drifting = false;
// only start drag if the user has not explictly banned it.
if (start.size() && !start.is(data.options.cancelOn)) {
// without this the simple "click" event won't be recognized on touch clients
if (!compat.touchEvents) {
event.preventDefault();
}
target.css('cursor', compat.cursorGrabbing);
target.data(datakey).dragging = flags.dragging = flags.dragged = false;
// apply the drag listeners to the doc or target
if(data.options.dragHold) {
$(document).on(events.drag, data, drag);
} else {
target.on(events.drag, data, drag);
}
data.position = capturePosition(event, {});
data.capture = capturePosition(event, {}, settings.captureThreshold);
triggerEvent('dragstart', target);
}
},
// ends the drag operation and unbinds the mouse move handler
stop = function (event) {
var data = event.data,
target = data.target,
options = data.options,
flags = data.flags,
thumbs = data.thumbs,
// hides the thumbs after the animation is done
done = function () {
if (thumbs && !options.hoverThumbs) {
toggleThumbs(thumbs, options, false);
}
};
// remove drag listeners from doc or target
if(options.dragHold) {
$(document).unbind(events.drag, drag);
} else {
target.unbind(events.drag, drag);
}
// only fire events and drift if we started with a
// valid position
if (data.position) {
triggerEvent('dragend', target);
// only drift if a drag passed our threshold
if (flags.dragging) {
drift(target.get(0), event, done);
} else {
done();
}
}
// only if we moved, and the mouse down is the same as
// the mouse up target do we defer the event
if (flags.dragging && data.start.is(event.target)) {
deferClick(data.start);
}
// clear all internal flags and settings
target.data(datakey).dragging =
data.start =
data.capture =
data.position =
flags.dragged =
flags.dragging = false;
// set the cursor back to normal
target.css('cursor', compat.cursorGrab);
},
// Ensures that a full set of options are provided
// for the plug-in. Also does some validation
getOptions = function(options) {
// fill in missing values with defaults
options = $.extend({}, defaults, options);
// check for inconsistent directional restrictions
if (options.direction !== 'multi' && options.direction !== options.wheelDirection) {
options.wheelDirection = options.direction;
}
// ensure positive values for deltas
options.scrollDelta = math.abs(options.scrollDelta);
options.wheelDelta = math.abs(options.wheelDelta);
// fix values for scroll offset
options.scrollLeft = options.scrollLeft === none ? null : math.abs(options.scrollLeft);
options.scrollTop = options.scrollTop === none ? null : math.abs(options.scrollTop);
return options;
},
// Returns the sizing information (bounding box) for the
// target DOM element
getSizing = function (target) {
var $target = $(target),
width = $target.width(),
height = $target.height(),
scrollWidth = width >= target.scrollWidth ? width : target.scrollWidth,
scrollHeight = height >= target.scrollHeight ? height : target.scrollHeight,
hasScroll = scrollWidth > width || scrollHeight > height;
return {
valid: hasScroll,
container: {
width: width,
height: height,
scrollWidth: scrollWidth,
scrollHeight: scrollHeight
},
thumbs: {
horizontal: {
width: width * width / scrollWidth,
height: settings.thumbThickness,
corner: settings.thumbThickness / 2,
left: 0,
top: height - settings.thumbThickness
},
vertical: {
width: settings.thumbThickness,
height: height * height / scrollHeight,
corner: settings.thumbThickness / 2,
left: width - settings.thumbThickness,
top: 0
}
}
};
},
// Attempts to get (or implicitly creates) the
// remover function for the target passed
// in as an argument
getRemover = function (target, orCreate) {
var $target = $(target), thumbs,
data = $target.data(datakey) || {},
style = $target.attr('style'),
fallback = orCreate ? function () {
data = $target.data(datakey);
thumbs = data.thumbs;
// restore original styles (if any)
if (style) {
$target.attr('style', style);
} else {
$target.removeAttr('style');
}
// remove any created thumbs
if (thumbs) {
if (thumbs.horizontal) { thumbs.horizontal.remove(); }
if (thumbs.vertical) { thumbs.vertical.remove(); }
}
// remove any bound overscroll events and data
$target
.removeData(datakey)
.off(events.wheel, wheel)
.off(events.start, start)
.off(events.end, stop)
.off(events.ignored, false);
} : $.noop;
return $.isFunction(data.remover) ? data.remover : fallback;
},
// Genterates CSS specific to a particular thumb.
// It requires sizing data and options
getThumbCss = function(size, options) {
return {
position: 'absolute',
opacity: options.persistThumbs ? settings.thumbOpacity : 0,
'background-color': 'red',
width: size.width + 'px',
height: size.height + 'px',
'border-radius': size.corner + 'px',
'margin': size.top + 'px 0 0 ' + size.left + 'px',
'z-index': options.zIndex
};
},
// Creates the DOM elements used as "thumbs" within
// the target container.
createThumbs = function(target, sizing, options) {
var div = '<div/>',
thumbs = {},
css = false;
if (sizing.container.scrollWidth > 0 && options.direction !== 'vertical') {
css = getThumbCss(sizing.thumbs.horizontal, options);
thumbs.horizontal = $(div).css(css).prependTo(target);
}
if (sizing.container.scrollHeight > 0 && options.direction !== 'horizontal') {
css = getThumbCss(sizing.thumbs.vertical, options);
thumbs.vertical = $(div).css(css).prependTo(target);
}
thumbs.added = !!css;
return thumbs;
},
// This function takes a jQuery element, some
// (optional) options, and sets up event metadata
// for each instance the plug-in affects
setup = function(target, options) {
// create initial data properties for this instance
options = getOptions(options);
var sizing = getSizing(target),
thumbs, data = {
options: options, sizing: sizing,
flags: { dragging: false },
remover: getRemover(target, true)
};
// only apply handlers if the overscrolled element
// actually has an area to scroll
if (sizing.valid) {
// provide a circular-reference, enable events, and
// apply any required CSS
data.target = target = $(target).css({
position: 'relative',
overflow: 'hidden',
cursor: compat.cursorGrab
}).on(events.wheel, data, wheel)
.on(events.start, data, start)
.on(events.end, data, stop)
.on(events.scroll, data, scroll)
.on(events.ignored, false);
// apply the stop listeners for drag end
if(options.dragHold) {
$(document).on(events.end, data, stop);
} else {
data.target.on(events.end, data, stop);
}
// apply any user-provided scroll offsets
if (options.scrollLeft !== null) {
target.scrollLeft(options.scrollLeft);
} if (options.scrollTop !== null) {
target.scrollTop(options.scrollTop);
}
// add thumbs and listeners (if we're showing them)
if (options.showThumbs) {
data.thumbs = thumbs = createThumbs(target, sizing, options);
if (thumbs.added) {
moveThumbs(thumbs, sizing, target.scrollLeft(), target.scrollTop());
if (options.hoverThumbs) {
target.on(events.hover, data, hover);
}
}
}
target.data(datakey, data);
}
},
// Removes any event listeners and other instance-specific
// data from the target. It attempts to leave the target
// at the state it found it.
teardown = function(target) {
getRemover(target)();
},
// This is the entry-point for enabling the plug-in;
// You can find it's exposure point at the end
// of this closure
overscroll = function(options) {
return this.removeOverscroll().each(function() {
setup(this, options);
});
},
// This function applies touch-specific CSS to enable
// the behavior that Overscroll emulates. This function is
// called instead of overscroll if the device supports it
touchscroll = function(options) {
return this.removeOverscroll().each(function() {
var target = $(this).data(datakey, {
remover: getRemover(this)
}).css(compat.overflowScrolling, 'touch')
.css('overflow', 'auto');
options = getOptions(options);
if (options.scrollLeft !== null) {
target.scrollLeft(options.scrollLeft);
} if (options.scrollTop !== null) {
target.scrollTop(options.scrollTop);
}
});
},
// This is the entry-point for disabling the plug-in;
// You can find it's exposure point at the end
// of this closure
removeOverscroll = function() {
return this.each(function () {
teardown(this);
});
};
// Extend overscroll to expose settings to the user
overscroll.settings = settings;
// Extend jQuery's prototype to expose the plug-in.
// If the supports native overflowScrolling, overscroll will not
// attempt to override the browser's built in support
$.extend(namespace, {
overscroll: compat.overflowScrolling ? touchscroll : overscroll,
removeOverscroll: removeOverscroll
});
})(window, document, navigator, Math, setTimeout, clearTimeout, jQuery.fn, jQuery);
提前谢谢你:)
答案 0 :(得分:0)
他们使用jQuery Overscroll。在源代码中,您可以看到他们拥有<div class="wrap">
并且background image附加到<div id="content">
。对于选择器$(".wrap")
,附加了overscroll插件:
o = $(".wrap").overscroll({
cancelOn: '.fields, #map',
scrollLeft: scrollX,
scrollTop: scrollY
}).on('overscroll:dragstart overscroll:dragend
overscroll:driftstart overscroll:driftend'
,function (event) {}
);
要开始使用,请查看github page for overscroll