diff --git a/.gitignore b/.gitignore index 6956fe0..38914f8 100644 --- a/.gitignore +++ b/.gitignore @@ -21,3 +21,4 @@ _site sea-modules node_modules/ .cache +dist diff --git a/.travis.yml b/.travis.yml index e5c2daf..bf8de4c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,19 +1,16 @@ language: node_js node_js: - - 0.10 + - "0.10" install: - - npm install mocha-browser nico + - npm install spm@ninja coveralls before_script: - - git clone git://github.com/aralejs/nico-arale.git _theme - - node_modules/.bin/nico build --theme _theme -C _theme/nico.js + - node_modules/spm/bin/spm-install script: - - node_modules/.bin/mocha-browser _site/tests/runner.html -S + - node_modules/spm/bin/spm-test after_success: - - npm install jscoverage coveralls - - node_modules/.bin/jscoverage --encoding=utf8 src _site/src-cov - - node_modules/.bin/mocha-browser _site/tests/runner.html?cov -S -R lcov | node_modules/.bin/coveralls + - node_modules/spm/bin/spm-test --coveralls | node_modules/.bin/coveralls diff --git a/HISTORY.md b/HISTORY.md index 1fce002..fe43413 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -2,6 +2,10 @@ --- +## 1.4.0 + +`improved` 升级到 spm@3.x 规范。 + ## 1.3.1 `tag:fixed` [#19](https://github.com/aralejs/sticky/issues/19), 绑定 window 的 resize 事件 diff --git a/dist/sticky-debug.js b/dist/sticky-debug.js deleted file mode 100644 index 1c2d5f6..0000000 --- a/dist/sticky-debug.js +++ /dev/null @@ -1,281 +0,0 @@ -define("arale/sticky/1.3.1/sticky-debug", [ "$-debug" ], function(require, exports, module, undefined) { - var $ = require("$-debug"), doc = $(document), stickyPrefix = [ "-webkit-", "-ms-", "-o-", "-moz-", "" ], guid = 0, ua = (window.navigator.userAgent || "").toLowerCase(), isIE = ua.indexOf("msie") !== -1, isIE6 = ua.indexOf("msie 6") !== -1; - var isPositionStickySupported = checkPositionStickySupported(), isPositionFixedSupported = checkPositionFixedSupported(); - // Sticky - // position: sticky simulator - function Sticky(options) { - this.options = options || {}; - this.elem = $(this.options.element); - this.callback = options.callback || function() {}; - this.position = options.position; - this._stickyId = guid++; - } - Sticky.prototype._prepare = function() { - // save element's origin position - var offset = this.elem.offset(); - this._originTop = offset.top; - this._originLeft = offset.left; - // if is fixed, force to call this_supportFixed - if (this.position.top === Number.MAX_VALUE) { - this._callFix = true; - this.position.top = this._originTop; - } - // save element's origin style - this._originStyles = { - position: null, - top: null, - bottom: null, - left: null - }; - for (var style in this._originStyles) { - if (this._originStyles.hasOwnProperty(style)) { - this._originStyles[style] = this.elem.css(style); - } - } - }; - Sticky.prototype.render = function() { - var self = this; - // only bind once - if (!this.elem.length || this.elem.data("bind-sticked")) { - return this; - } - this._prepare(); - // if other element change height in one page, - // or if resize window, - // need adjust sticky element's status - this.adjust = function() { - self._restore(); - var offset = self.elem.offset(); - self._originTop = offset.top; - self._originLeft = offset.left; - scrollFn.call(self); - }; - var scrollFn; - if (sticky.isPositionStickySupported && !this._callFix) { - scrollFn = this._supportSticky; - // set position: sticky directly - var tmp = ""; - for (var i = 0; i < stickyPrefix.length; i++) { - tmp += "position:" + stickyPrefix[i] + "sticky;"; - } - if (this.position.top !== undefined) { - tmp += "top: " + this.position.top + "px;"; - } - if (this.position.bottom !== undefined) { - tmp += "bottom: " + this.position.bottom + "px;"; - } - this.elem[0].style.cssText += tmp; - this.adjust = function() { - scrollFn.call(self); - }; - } else if (sticky.isPositionFixedSupported) { - scrollFn = this._supportFixed; - } else { - scrollFn = this._supportAbsolute; - // ie6 - // avoid floatImage Shake for IE6 - // see: https://github.com/lifesinger/lifesinger. - // github.com/blob/master/lab/2009/ie6sticked_position_v4.html - $("").appendTo("head"); - } - // first run after document ready - scrollFn.call(this); - // stickyX is event namespace - $(window).on("scroll.sticky" + this._stickyId, function() { - if (!self.elem.is(":visible")) return; - scrollFn.call(self); - }); - $(window).on("resize.sticky" + this._stickyId, debounce(function() { - self.adjust(); - }, 120)); - this.elem.data("bind-sticked", true); - return this; - }; - Sticky.prototype._getTopBottom = function(scrollTop, offsetTop) { - var top; - var bottom; - // top is true when the distance from element to top of window <= position.top - if (this.position.top !== undefined) { - top = offsetTop - scrollTop <= this.position.top; - } - // bottom is true when the distance is from bottom of element to bottom of window <= position.bottom - if (this.position.bottom !== undefined) { - bottom = scrollTop + $(window).height() - offsetTop - this.elem.outerHeight() <= this.position.bottom; - } - return { - top: top, - bottom: bottom - }; - }; - Sticky.prototype._supportFixed = function() { - var _sticky = this.elem.data("sticked"); - var distance = this._getTopBottom(doc.scrollTop(), this._originTop); - if (!_sticky && (distance.top !== undefined && distance.top || distance.bottom !== undefined && distance.bottom)) { - this._addPlaceholder(); - this.elem.css($.extend({ - position: "fixed", - left: this._originLeft - }, distance.top ? { - top: this.position.top - } : { - bottom: this.position.bottom - })); - this.elem.data("sticked", true); - this.callback.call(this, true); - } else if (_sticky && !distance.top && !distance.bottom) { - this._restore(); - } - }; - Sticky.prototype._supportAbsolute = function() { - var scrollTop = doc.scrollTop(); - var _sticky = this.elem.data("sticked"); - var distance = this._getTopBottom(scrollTop, this.elem.offset().top); - if (distance.top || distance.bottom || this._callFix) { - // sticky status change only one time - if (!_sticky) { - this._addPlaceholder(); - this.elem.data("sticked", true); - this.callback.call(this, true); - } - // update element's position - this.elem.css({ - position: "absolute", - top: this._callFix ? this._originTop + scrollTop : distance.top ? this.position.top + scrollTop : scrollTop + $(window).height() - this.position.bottom - this.elem.outerHeight() - }); - } else if (_sticky && !distance.top && !distance.bottom) { - this._restore(); - } - }; - Sticky.prototype._supportSticky = function() { - // sticky status change for callback - var _sticky = this.elem.data("sticked"); - var distance = this._getTopBottom(doc.scrollTop(), this.elem.offset().top); - if (!_sticky && (distance.top !== undefined && distance.top || distance.bottom !== undefined && distance.bottom)) { - this.elem.data("sticked", true); - this.callback.call(this, true); - } else if (_sticky && !distance.top && !distance.bottom) { - // don't need restore style and remove placeholder - this.elem.data("sticked", false); - this.callback.call(this, false); - } - }; - Sticky.prototype._restore = function() { - this._removePlaceholder(); - // set origin style - this.elem.css(this._originStyles); - this.elem.data("sticked", false); - this.callback.call(this, false); - }; - // need placeholder when: 1) position: static or relative, but expect for display != block - Sticky.prototype._addPlaceholder = function() { - var need = false; - var position = this.elem.css("position"); - if (position === "static" || position === "relative") { - need = true; - } - if (this.elem.css("display") !== "block") { - need = false; - } - if (need) { - this._placeholder = $('
'); - this._placeholder.width(this.elem.outerWidth(true)).height(this.elem.outerHeight(true)).css("float", this.elem.css("float")).insertAfter(this.elem); - } - }; - Sticky.prototype._removePlaceholder = function() { - // remove placeholder if has - this._placeholder && this._placeholder.remove(); - }; - Sticky.prototype.destroy = function() { - this._restore(); - this.elem.data("bind-sticked", false); - $(window).off("scroll.sticky" + this._stickyId); - $(window).off("resize.sticky" + this._stickyId); - }; - // APIs - // --- - module.exports = sticky; - function sticky(elem, position, callback) { - if (!$.isPlainObject(position)) { - position = { - top: position - }; - } - if (position.top === undefined && position.bottom === undefined) { - position.top = 0; - } - return new Sticky({ - element: elem, - position: position, - callback: callback - }).render(); - } - // sticky.stick(elem, position, callback) - sticky.stick = sticky; - // sticky.fix(elem) - sticky.fix = function(elem) { - return new Sticky({ - element: elem, - // position.top is Number.MAX_VALUE means fixed - position: { - top: Number.MAX_VALUE - } - }).render(); - }; - // for tc - sticky.isPositionStickySupported = isPositionStickySupported; - sticky.isPositionFixedSupported = isPositionFixedSupported; - // Helper - // --- - function checkPositionFixedSupported() { - return !isIE6; - } - function checkPositionStickySupported() { - if (isIE) return false; - var container = doc[0].body; - if (doc[0].createElement && container && container.appendChild && container.removeChild) { - var isSupported, el = doc[0].createElement("div"), getStyle = function(st) { - if (window.getComputedStyle) { - return window.getComputedStyle(el).getPropertyValue(st); - } else { - return el.currentStyle.getAttribute(st); - } - }; - container.appendChild(el); - for (var i = 0; i < stickyPrefix.length; i++) { - el.style.cssText = "position:" + stickyPrefix[i] + "sticky;visibility:hidden;"; - if (isSupported = getStyle("position").indexOf("sticky") !== -1) break; - } - el.parentNode.removeChild(el); - return isSupported; - } - } - // https://github.com/jashkenas/underscore/blob/master/underscore.js#L699 - function getTime() { - return (Date.now || function() { - return new Date().getTime(); - })(); - } - function debounce(func, wait, immediate) { - var timeout, args, context, timestamp, result; - return function() { - context = this; - args = arguments; - timestamp = getTime(); - var later = function() { - var last = getTime() - timestamp; - if (last < wait) { - timeout = setTimeout(later, wait - last); - } else { - timeout = null; - if (!immediate) result = func.apply(context, args); - } - }; - var callNow = immediate && !timeout; - if (!timeout) { - timeout = setTimeout(later, wait); - } - if (callNow) result = func.apply(context, args); - return result; - }; - } -}); diff --git a/dist/sticky.js b/dist/sticky.js deleted file mode 100644 index 19a33a4..0000000 --- a/dist/sticky.js +++ /dev/null @@ -1 +0,0 @@ -define("arale/sticky/1.3.1/sticky",["$"],function(a,b,c,d){function e(a){this.options=a||{},this.elem=k(this.options.element),this.callback=a.callback||function(){},this.position=a.position,this._stickyId=n++}function f(a,b,c){return k.isPlainObject(b)||(b={top:b}),b.top===d&&b.bottom===d&&(b.top=0),new e({element:a,position:b,callback:c}).render()}function g(){return!q}function h(){if(p)return!1;var a=l[0].body;if(l[0].createElement&&a&&a.appendChild&&a.removeChild){var b,c=l[0].createElement("div"),d=function(a){return window.getComputedStyle?window.getComputedStyle(c).getPropertyValue(a):c.currentStyle.getAttribute(a)};a.appendChild(c);for(var e=0;ek?d=setTimeout(j,b-k):(d=null,c||(h=a.apply(f,e)))},k=c&&!d;return d||(d=setTimeout(j,b)),k&&(h=a.apply(f,e)),h}}var k=a("$"),l=k(document),m=["-webkit-","-ms-","-o-","-moz-",""],n=0,o=(window.navigator.userAgent||"").toLowerCase(),p=-1!==o.indexOf("msie"),q=-1!==o.indexOf("msie 6"),r=h(),s=g();e.prototype._prepare=function(){var a=this.elem.offset();this._originTop=a.top,this._originLeft=a.left,this.position.top===Number.MAX_VALUE&&(this._callFix=!0,this.position.top=this._originTop),this._originStyles={position:null,top:null,bottom:null,left:null};for(var b in this._originStyles)this._originStyles.hasOwnProperty(b)&&(this._originStyles[b]=this.elem.css(b))},e.prototype.render=function(){var a=this;if(!this.elem.length||this.elem.data("bind-sticked"))return this;this._prepare(),this.adjust=function(){a._restore();var c=a.elem.offset();a._originTop=c.top,a._originLeft=c.left,b.call(a)};var b;if(f.isPositionStickySupported&&!this._callFix){b=this._supportSticky;for(var c="",e=0;e * html{ background:url(null) no-repeat fixed; } ").appendTo("head"));return b.call(this),k(window).on("scroll.sticky"+this._stickyId,function(){a.elem.is(":visible")&&b.call(a)}),k(window).on("resize.sticky"+this._stickyId,j(function(){a.adjust()},120)),this.elem.data("bind-sticked",!0),this},e.prototype._getTopBottom=function(a,b){var c,e;return this.position.top!==d&&(c=b-a<=this.position.top),this.position.bottom!==d&&(e=a+k(window).height()-b-this.elem.outerHeight()<=this.position.bottom),{top:c,bottom:e}},e.prototype._supportFixed=function(){var a=this.elem.data("sticked"),b=this._getTopBottom(l.scrollTop(),this._originTop);!a&&(b.top!==d&&b.top||b.bottom!==d&&b.bottom)?(this._addPlaceholder(),this.elem.css(k.extend({position:"fixed",left:this._originLeft},b.top?{top:this.position.top}:{bottom:this.position.bottom})),this.elem.data("sticked",!0),this.callback.call(this,!0)):!a||b.top||b.bottom||this._restore()},e.prototype._supportAbsolute=function(){var a=l.scrollTop(),b=this.elem.data("sticked"),c=this._getTopBottom(a,this.elem.offset().top);c.top||c.bottom||this._callFix?(b||(this._addPlaceholder(),this.elem.data("sticked",!0),this.callback.call(this,!0)),this.elem.css({position:"absolute",top:this._callFix?this._originTop+a:c.top?this.position.top+a:a+k(window).height()-this.position.bottom-this.elem.outerHeight()})):!b||c.top||c.bottom||this._restore()},e.prototype._supportSticky=function(){var a=this.elem.data("sticked"),b=this._getTopBottom(l.scrollTop(),this.elem.offset().top);!a&&(b.top!==d&&b.top||b.bottom!==d&&b.bottom)?(this.elem.data("sticked",!0),this.callback.call(this,!0)):!a||b.top||b.bottom||(this.elem.data("sticked",!1),this.callback.call(this,!1))},e.prototype._restore=function(){this._removePlaceholder(),this.elem.css(this._originStyles),this.elem.data("sticked",!1),this.callback.call(this,!1)},e.prototype._addPlaceholder=function(){var a=!1,b=this.elem.css("position");("static"===b||"relative"===b)&&(a=!0),"block"!==this.elem.css("display")&&(a=!1),a&&(this._placeholder=k('
'),this._placeholder.width(this.elem.outerWidth(!0)).height(this.elem.outerHeight(!0)).css("float",this.elem.css("float")).insertAfter(this.elem))},e.prototype._removePlaceholder=function(){this._placeholder&&this._placeholder.remove()},e.prototype.destroy=function(){this._restore(),this.elem.data("bind-sticked",!1),k(window).off("scroll.sticky"+this._stickyId),k(window).off("resize.sticky"+this._stickyId)},c.exports=f,f.stick=f,f.fix=function(a){return new e({element:a,position:{top:Number.MAX_VALUE}}).render()},f.isPositionStickySupported=r,f.isPositionFixedSupported=s}); diff --git a/index.js b/index.js new file mode 100644 index 0000000..de05797 --- /dev/null +++ b/index.js @@ -0,0 +1,345 @@ +var $ = require("jquery"), + doc = $(document), + stickyPrefix = ["-webkit-", "-ms-", "-o-", "-moz-", ""], + guid = 0, + + ua = (window.navigator.userAgent || "").toLowerCase(), + isIE = ua.indexOf("msie") !== -1, + isIE6 = ua.indexOf("msie 6") !== -1; + +var isPositionStickySupported = checkPositionStickySupported(), + isPositionFixedSupported = checkPositionFixedSupported(); + + +// Sticky +// position: sticky simulator +function Sticky(options) { + this.options = options || {}; + this.elem = $(this.options.element); + this.callback = options.callback || function() {}; + this.position = options.position; + this._stickyId = guid++; +} + +Sticky.prototype._prepare = function() { + // save element's origin position + var offset = this.elem.offset(); + this._originTop = offset.top; + this._originLeft = offset.left; + + // if is fixed, force to call this_supportFixed + if (this.position.top === Number.MAX_VALUE) { + this._callFix = true; + this.position.top = this._originTop; + } + + // save element's origin style + this._originStyles = { + position: null, + top: null, + bottom: null, + left: null + }; + for (var style in this._originStyles) { + if (this._originStyles.hasOwnProperty(style)) { + this._originStyles[style] = this.elem.css(style); + } + } +}; + +Sticky.prototype.render = function () { + var self = this; + + // only bind once + if (!this.elem.length || this.elem.data('bind-sticked')) { + return this; + } + + this._prepare(); + + // if other element change height in one page, + // or if resize window, + // need adjust sticky element's status + this.adjust = function() { + self._restore(); + + var offset = self.elem.offset(); + self._originTop = offset.top; + self._originLeft = offset.left; + + scrollFn.call(self); + }; + + var scrollFn; + if (sticky.isPositionStickySupported && !this._callFix) { + scrollFn = this._supportSticky; + + // set position: sticky directly + var tmp = ""; + for (var i = 0; i < stickyPrefix.length; i++) { + tmp += "position:" + stickyPrefix[i] + "sticky;"; + } + if (this.position.top !== undefined) { + tmp += "top: " + this.position.top + "px;"; + } + if (this.position.bottom !== undefined) { + tmp += "bottom: " + this.position.bottom + "px;"; + } + this.elem[0].style.cssText += tmp; + + this.adjust = function() { + scrollFn.call(self); + }; + } else if (sticky.isPositionFixedSupported) { + scrollFn = this._supportFixed; + } else { + scrollFn = this._supportAbsolute; // ie6 + // avoid floatImage Shake for IE6 + // see: https://github.com/lifesinger/lifesinger. + // github.com/blob/master/lab/2009/ie6sticked_position_v4.html + $("").appendTo("head"); + } + + // first run after document ready + scrollFn.call(this); + + // stickyX is event namespace + $(window).on('scroll.sticky' + this._stickyId, function () { + if (!self.elem.is(':visible')) return; + scrollFn.call(self); + }); + + $(window).on('resize.sticky' + this._stickyId, debounce(function() { + self.adjust(); + }, 120)); + + this.elem.data('bind-sticked', true); + + return this; +}; + +Sticky.prototype._getTopBottom = function(scrollTop, offsetTop) { + var top; + var bottom; + + // top is true when the distance from element to top of window <= position.top + if (this.position.top !== undefined) { + top = offsetTop - scrollTop <= this.position.top; + } + // bottom is true when the distance is from bottom of element to bottom of window <= position.bottom + if (this.position.bottom !== undefined) { + bottom = scrollTop + $(window).height() - offsetTop - this.elem.outerHeight() <= this.position.bottom; + } + + return { + top: top, + bottom: bottom + }; +}; + +Sticky.prototype._supportFixed = function () { + var _sticky = this.elem.data('sticked'); + var distance = this._getTopBottom(doc.scrollTop(), this._originTop); + + if (!_sticky && + (distance.top !== undefined && distance.top || + distance.bottom !== undefined && distance.bottom)) { + this._addPlaceholder(); + + this.elem.css($.extend({ + position: 'fixed', + left: this._originLeft + }, distance.top ? { top: this.position.top } : { bottom: this.position.bottom })); + this.elem.data('sticked', true); + this.callback.call(this, true); + } else if (_sticky && !distance.top && !distance.bottom) { + this._restore(); + } +}; + +Sticky.prototype._supportAbsolute = function () { + var scrollTop = doc.scrollTop(); + var _sticky = this.elem.data('sticked'); + var distance = this._getTopBottom(scrollTop, this.elem.offset().top); + + if (distance.top || distance.bottom || this._callFix) { + // sticky status change only one time + if (!_sticky) { + this._addPlaceholder(); + this.elem.data('sticked', true); + this.callback.call(this, true); + } + // update element's position + this.elem.css({ + position: 'absolute', + top: this._callFix ? this._originTop + scrollTop: (distance.top ? this.position.top + scrollTop : + scrollTop + $(window).height() - this.position.bottom - this.elem.outerHeight()) + }); + } else if (_sticky && !distance.top && !distance.bottom) { + this._restore(); + } +}; + +Sticky.prototype._supportSticky = function () { + // sticky status change for callback + var _sticky = this.elem.data('sticked'); + var distance = this._getTopBottom(doc.scrollTop(), this.elem.offset().top); + + if (!_sticky && + (distance.top !== undefined && distance.top || + distance.bottom !== undefined && distance.bottom)) { + this.elem.data('sticked', true); + this.callback.call(this, true); + } else if (_sticky && !distance.top && !distance.bottom){ + // don't need restore style and remove placeholder + this.elem.data('sticked', false); + this.callback.call(this, false); + } +}; + +Sticky.prototype._restore = function () { + this._removePlaceholder(); + + // set origin style + this.elem.css(this._originStyles); + + this.elem.data('sticked', false); + + this.callback.call(this, false); +}; + +// need placeholder when: 1) position: static or relative, but expect for display != block +Sticky.prototype._addPlaceholder = function() { + var need = false; + var position = this.elem.css("position"); + + if (position === 'static' || position === 'relative') { + need = true; + } + if (this.elem.css("display") !== "block") { + need = false; + } + + if (need) { + this._placeholder = $('
'); + this._placeholder.width(this.elem.outerWidth(true)) + .height(this.elem.outerHeight(true)) + .css("float", this.elem.css("float")).insertAfter(this.elem); + } +}; + +Sticky.prototype._removePlaceholder = function() { + // remove placeholder if has + this._placeholder && this._placeholder.remove(); +}; + +Sticky.prototype.destroy = function () { + this._restore(); + this.elem.data("bind-sticked", false); + $(window).off('scroll.sticky' + this._stickyId); + $(window).off('resize.sticky' + this._stickyId); +}; + +// APIs +// --- + +module.exports = sticky; + +function sticky(elem, position, callback) { + if (!$.isPlainObject(position)) { + position = { + top: position + }; + } + if (position.top === undefined && position.bottom === undefined) { + position.top = 0; + } + return (new Sticky({ + element: elem, + position: position, + callback: callback + })).render(); +} + +// sticky.stick(elem, position, callback) +sticky.stick = sticky; + +// sticky.fix(elem) +sticky.fix = function (elem) { + return (new Sticky({ + element: elem, + // position.top is Number.MAX_VALUE means fixed + position: { + top: Number.MAX_VALUE + } + })).render(); +}; + +// for tc +sticky.isPositionStickySupported = isPositionStickySupported; +sticky.isPositionFixedSupported = isPositionFixedSupported; + +// Helper +// --- +function checkPositionFixedSupported() { + return !isIE6; +} + +function checkPositionStickySupported() { + if (isIE) return false; + + var container = doc[0].body; + + if (doc[0].createElement && container && container.appendChild && container.removeChild) { + var isSupported, + el = doc[0].createElement("div"), + getStyle = function (st) { + if (window.getComputedStyle) { + return window.getComputedStyle(el).getPropertyValue(st); + } else { + return el.currentStyle.getAttribute(st); + } + }; + + container.appendChild(el); + + for (var i = 0; i < stickyPrefix.length; i++) { + el.style.cssText = "position:" + stickyPrefix[i] + "sticky;visibility:hidden;"; + if (isSupported = getStyle("position").indexOf("sticky") !== -1) break; + } + + el.parentNode.removeChild(el); + return isSupported; + } +} + +// https://github.com/jashkenas/underscore/blob/master/underscore.js#L699 +function getTime() { + return (Date.now || function() { + return new Date().getTime(); + })() +} +function debounce(func, wait, immediate) { + var timeout, args, context, timestamp, result; + return function() { + context = this; + args = arguments; + timestamp = getTime(); + var later = function() { + var last = getTime() - timestamp; + if (last < wait) { + timeout = setTimeout(later, wait - last); + } else { + timeout = null; + if (!immediate) result = func.apply(context, args); + } + }; + var callNow = immediate && !timeout; + if (!timeout) { + timeout = setTimeout(later, wait); + } + if (callNow) result = func.apply(context, args); + return result; + }; +} diff --git a/package.json b/package.json index e70dd79..8bc56fc 100644 --- a/package.json +++ b/package.json @@ -1,28 +1,36 @@ { - "family": "arale", - "name": "sticky", - "version": "1.3.1", - "keywords": ["utility"], - "description": "实现元素跟随滚动的效果。", - "homepage": "http://aralejs.org/sticky/", - "author": "乔花 ", - "maintainers": [ - "乔花 ", - "偏右 " - ], - "repository": { - "type": "git", - "url": "https://github.com/aralejs/sticky" + "name": "arale-sticky", + "version": "1.4.0", + "keywords": [ + "utility" + ], + "description": "实现元素跟随滚动的效果。", + "homepage": "http://aralejs.org/sticky/", + "author": "乔花 ", + "maintainers": [ + "乔花 ", + "偏右 " + ], + "repository": { + "type": "git", + "url": "https://github.com/aralejs/sticky" + }, + "bugs": { + "url": "https://github.com/aralejs/sticky/issues" + }, + "license": "MIT", + "spm": { + "main": "index.js", + "dependencies": { + "jquery": "1.7.2" }, - "bugs": { - "url": "https://github.com/aralejs/sticky/issues" + "devDependencies": { + "expect.js": "0.3.1", + "sinon": "1.6.0" }, - "license": "MIT", - "spm": { - "alias": { - "$": "$" - }, - "output": ["sticky.js"] - }, - "tests": ["sticky"] + "buildArgs": "--ignore jquery" + }, + "tests": [ + "sticky" + ] } diff --git a/src/sticky.js b/src/sticky.js deleted file mode 100644 index c844fa5..0000000 --- a/src/sticky.js +++ /dev/null @@ -1,348 +0,0 @@ -define(function (require, exports, module, undefined) { - - var $ = require("$"), - doc = $(document), - stickyPrefix = ["-webkit-", "-ms-", "-o-", "-moz-", ""], - guid = 0, - - ua = (window.navigator.userAgent || "").toLowerCase(), - isIE = ua.indexOf("msie") !== -1, - isIE6 = ua.indexOf("msie 6") !== -1; - - var isPositionStickySupported = checkPositionStickySupported(), - isPositionFixedSupported = checkPositionFixedSupported(); - - - // Sticky - // position: sticky simulator - function Sticky(options) { - this.options = options || {}; - this.elem = $(this.options.element); - this.callback = options.callback || function() {}; - this.position = options.position; - this._stickyId = guid++; - } - - Sticky.prototype._prepare = function() { - // save element's origin position - var offset = this.elem.offset(); - this._originTop = offset.top; - this._originLeft = offset.left; - - // if is fixed, force to call this_supportFixed - if (this.position.top === Number.MAX_VALUE) { - this._callFix = true; - this.position.top = this._originTop; - } - - // save element's origin style - this._originStyles = { - position: null, - top: null, - bottom: null, - left: null - }; - for (var style in this._originStyles) { - if (this._originStyles.hasOwnProperty(style)) { - this._originStyles[style] = this.elem.css(style); - } - } - }; - - Sticky.prototype.render = function () { - var self = this; - - // only bind once - if (!this.elem.length || this.elem.data('bind-sticked')) { - return this; - } - - this._prepare(); - - // if other element change height in one page, - // or if resize window, - // need adjust sticky element's status - this.adjust = function() { - self._restore(); - - var offset = self.elem.offset(); - self._originTop = offset.top; - self._originLeft = offset.left; - - scrollFn.call(self); - }; - - var scrollFn; - if (sticky.isPositionStickySupported && !this._callFix) { - scrollFn = this._supportSticky; - - // set position: sticky directly - var tmp = ""; - for (var i = 0; i < stickyPrefix.length; i++) { - tmp += "position:" + stickyPrefix[i] + "sticky;"; - } - if (this.position.top !== undefined) { - tmp += "top: " + this.position.top + "px;"; - } - if (this.position.bottom !== undefined) { - tmp += "bottom: " + this.position.bottom + "px;"; - } - this.elem[0].style.cssText += tmp; - - this.adjust = function() { - scrollFn.call(self); - }; - } else if (sticky.isPositionFixedSupported) { - scrollFn = this._supportFixed; - } else { - scrollFn = this._supportAbsolute; // ie6 - // avoid floatImage Shake for IE6 - // see: https://github.com/lifesinger/lifesinger. - // github.com/blob/master/lab/2009/ie6sticked_position_v4.html - $("").appendTo("head"); - } - - // first run after document ready - scrollFn.call(this); - - // stickyX is event namespace - $(window).on('scroll.sticky' + this._stickyId, function () { - if (!self.elem.is(':visible')) return; - scrollFn.call(self); - }); - - $(window).on('resize.sticky' + this._stickyId, debounce(function() { - self.adjust(); - }, 120)); - - this.elem.data('bind-sticked', true); - - return this; - }; - - Sticky.prototype._getTopBottom = function(scrollTop, offsetTop) { - var top; - var bottom; - - // top is true when the distance from element to top of window <= position.top - if (this.position.top !== undefined) { - top = offsetTop - scrollTop <= this.position.top; - } - // bottom is true when the distance is from bottom of element to bottom of window <= position.bottom - if (this.position.bottom !== undefined) { - bottom = scrollTop + $(window).height() - offsetTop - this.elem.outerHeight() <= this.position.bottom; - } - - return { - top: top, - bottom: bottom - }; - }; - - Sticky.prototype._supportFixed = function () { - var _sticky = this.elem.data('sticked'); - var distance = this._getTopBottom(doc.scrollTop(), this._originTop); - - if (!_sticky && - (distance.top !== undefined && distance.top || - distance.bottom !== undefined && distance.bottom)) { - this._addPlaceholder(); - - this.elem.css($.extend({ - position: 'fixed', - left: this._originLeft - }, distance.top ? { top: this.position.top } : { bottom: this.position.bottom })); - this.elem.data('sticked', true); - this.callback.call(this, true); - } else if (_sticky && !distance.top && !distance.bottom) { - this._restore(); - } - }; - - Sticky.prototype._supportAbsolute = function () { - var scrollTop = doc.scrollTop(); - var _sticky = this.elem.data('sticked'); - var distance = this._getTopBottom(scrollTop, this.elem.offset().top); - - if (distance.top || distance.bottom || this._callFix) { - // sticky status change only one time - if (!_sticky) { - this._addPlaceholder(); - this.elem.data('sticked', true); - this.callback.call(this, true); - } - // update element's position - this.elem.css({ - position: 'absolute', - top: this._callFix ? this._originTop + scrollTop: (distance.top ? this.position.top + scrollTop : - scrollTop + $(window).height() - this.position.bottom - this.elem.outerHeight()) - }); - } else if (_sticky && !distance.top && !distance.bottom) { - this._restore(); - } - }; - - Sticky.prototype._supportSticky = function () { - // sticky status change for callback - var _sticky = this.elem.data('sticked'); - var distance = this._getTopBottom(doc.scrollTop(), this.elem.offset().top); - - if (!_sticky && - (distance.top !== undefined && distance.top || - distance.bottom !== undefined && distance.bottom)) { - this.elem.data('sticked', true); - this.callback.call(this, true); - } else if (_sticky && !distance.top && !distance.bottom){ - // don't need restore style and remove placeholder - this.elem.data('sticked', false); - this.callback.call(this, false); - } - }; - - Sticky.prototype._restore = function () { - this._removePlaceholder(); - - // set origin style - this.elem.css(this._originStyles); - - this.elem.data('sticked', false); - - this.callback.call(this, false); - }; - - // need placeholder when: 1) position: static or relative, but expect for display != block - Sticky.prototype._addPlaceholder = function() { - var need = false; - var position = this.elem.css("position"); - - if (position === 'static' || position === 'relative') { - need = true; - } - if (this.elem.css("display") !== "block") { - need = false; - } - - if (need) { - this._placeholder = $('
'); - this._placeholder.width(this.elem.outerWidth(true)) - .height(this.elem.outerHeight(true)) - .css("float", this.elem.css("float")).insertAfter(this.elem); - } - }; - - Sticky.prototype._removePlaceholder = function() { - // remove placeholder if has - this._placeholder && this._placeholder.remove(); - }; - - Sticky.prototype.destroy = function () { - this._restore(); - this.elem.data("bind-sticked", false); - $(window).off('scroll.sticky' + this._stickyId); - $(window).off('resize.sticky' + this._stickyId); - }; - - // APIs - // --- - - module.exports = sticky; - - function sticky(elem, position, callback) { - if (!$.isPlainObject(position)) { - position = { - top: position - }; - } - if (position.top === undefined && position.bottom === undefined) { - position.top = 0; - } - return (new Sticky({ - element: elem, - position: position, - callback: callback - })).render(); - } - - // sticky.stick(elem, position, callback) - sticky.stick = sticky; - - // sticky.fix(elem) - sticky.fix = function (elem) { - return (new Sticky({ - element: elem, - // position.top is Number.MAX_VALUE means fixed - position: { - top: Number.MAX_VALUE - } - })).render(); - }; - - // for tc - sticky.isPositionStickySupported = isPositionStickySupported; - sticky.isPositionFixedSupported = isPositionFixedSupported; - - // Helper - // --- - function checkPositionFixedSupported() { - return !isIE6; - } - - function checkPositionStickySupported() { - if (isIE) return false; - - var container = doc[0].body; - - if (doc[0].createElement && container && container.appendChild && container.removeChild) { - var isSupported, - el = doc[0].createElement("div"), - getStyle = function (st) { - if (window.getComputedStyle) { - return window.getComputedStyle(el).getPropertyValue(st); - } else { - return el.currentStyle.getAttribute(st); - } - }; - - container.appendChild(el); - - for (var i = 0; i < stickyPrefix.length; i++) { - el.style.cssText = "position:" + stickyPrefix[i] + "sticky;visibility:hidden;"; - if (isSupported = getStyle("position").indexOf("sticky") !== -1) break; - } - - el.parentNode.removeChild(el); - return isSupported; - } - } - - // https://github.com/jashkenas/underscore/blob/master/underscore.js#L699 - function getTime() { - return (Date.now || function() { - return new Date().getTime(); - })() - } - function debounce(func, wait, immediate) { - var timeout, args, context, timestamp, result; - return function() { - context = this; - args = arguments; - timestamp = getTime(); - var later = function() { - var last = getTime() - timestamp; - if (last < wait) { - timeout = setTimeout(later, wait - last); - } else { - timeout = null; - if (!immediate) result = func.apply(context, args); - } - }; - var callNow = immediate && !timeout; - if (!timeout) { - timeout = setTimeout(later, wait); - } - if (callNow) result = func.apply(context, args); - return result; - }; - } -}); diff --git a/tests/sticky-spec.js b/tests/sticky-spec.js index 75f9c1d..ec7afb5 100644 --- a/tests/sticky-spec.js +++ b/tests/sticky-spec.js @@ -1,435 +1,432 @@ -define(function (require) { +//mocha.setup({ignoreLeaks: true}); - //mocha.setup({ignoreLeaks: true}); +var expect = require('expect.js'); +var $ = require('jquery'); +var sinon = require('sinon'); - var expect = require('expect'); - var $ = require('$'); - var sinon = require('sinon'); +var element = null; +var setTop = 50; +var elementTop; +var elementBottom; +var timeout = 30; +var tmp1, tmp2, tmpHeight = 1200; - var element = null; - var setTop = 50; - var elementTop; - var elementBottom; - var timeout = 30; - var tmp1, tmp2, tmpHeight = 1200; +var Sticky = require('../index.js'); - var Sticky = require('sticky'); +var isPositionStickySupported = Sticky.isPositionStickySupported, + isPositionFixedSupported = Sticky.isPositionFixedSupported; - var isPositionStickySupported = Sticky.isPositionStickySupported, - isPositionFixedSupported = Sticky.isPositionFixedSupported; +describe('Sticky.fix', function () { + beforeEach(function () { + $('body').css('height', '2000px'); + element = $('
test
'); + element.appendTo('body'); + }); - describe('Sticky.fix', function () { - beforeEach(function () { - $('body').css('height', '2000px'); - element = $('
test
'); - element.appendTo('body'); - }); + afterEach(function () { + element.remove(); + element = null; + $('body').css('height', ''); + $(document).off('scroll'); + $(document).scrollTop(0); + }); + + it('默认的 top 值', function () { + var originTop = element.offset().top; + var obj = Sticky.fix(element); + expect(obj.position.top).to.be(originTop); + obj.destroy(); + }); - afterEach(function () { - element.remove(); - element = null; - $('body').css('height', ''); - $(document).off('scroll'); - $(document).scrollTop(0); - }); - - it('默认的 top 值', function () { - var originTop = element.offset().top; - var obj = Sticky.fix(element); - expect(obj.position.top).to.be(originTop); - obj.destroy(); - }); + it('fixed 元素, 滚动 500 像素', function (done) { + var oldTop = element.offset().top; - it('fixed 元素, 滚动 500 像素', function (done) { - var oldTop = element.offset().top; + var obj = Sticky.fix(element); - var obj = Sticky.fix(element); + $(document).scrollTop(500); - $(document).scrollTop(500); + setTimeout(function () { + expect(element.css('position')).to.be(isPositionFixedSupported ? 'fixed' : 'absolute'); + expect(obj._placeholder.length).to.be(1); + expect(element.offset().top).to.be(oldTop + 500); + done(); - setTimeout(function () { - expect(element.css('position')).to.be(isPositionFixedSupported ? 'fixed' : 'absolute'); - expect(obj._placeholder.length).to.be(1); - expect(element.offset().top).to.be(oldTop + 500); - done(); + obj.destroy(); + }, timeout); + }); - obj.destroy(); - }, timeout); - }); + it('不需要占位符的 fixed 元素', function (done) { + element.css("position", "absolute"); - it('不需要占位符的 fixed 元素', function (done) { - element.css("position", "absolute"); + var obj = Sticky.fix(element); + $(document).scrollTop(500); - var obj = Sticky.fix(element); - $(document).scrollTop(500); + setTimeout(function () { + expect(obj._placeholder).to.be(undefined); + done(); + obj.destroy(); + }, timeout); + }); + + it('float: left 时', function (done) { + element.css("float", "left"); - setTimeout(function () { - expect(obj._placeholder).to.be(undefined); - done(); - obj.destroy(); - }, timeout); - }); - - it('float: left 时', function (done) { - element.css("float", "left"); + var obj = Sticky.fix(element); + $(document).scrollTop(500); - var obj = Sticky.fix(element); - $(document).scrollTop(500); + setTimeout(function () { + expect(obj._placeholder.length).to.be(1); + done(); + obj.destroy(); + }, timeout); - setTimeout(function () { - expect(obj._placeholder.length).to.be(1); - done(); - obj.destroy(); - }, timeout); + }); - }); + it('重复绑定', function (done) { + var obj1 = Sticky.fix(element); - it('重复绑定', function (done) { - var obj1 = Sticky.fix(element); + var obj2 = Sticky.fix(element); - var obj2 = Sticky.fix(element); + $(document).scrollTop(500); - $(document).scrollTop(500); + setTimeout(function () { + expect(element.data("bind-sticked")).to.be(true); + expect(obj2.adjust).to.be(undefined); + done(); - setTimeout(function () { - expect(element.data("bind-sticked")).to.be(true); - expect(obj2.adjust).to.be(undefined); - done(); + obj1.destroy(); + }, timeout); + }); +}); - obj1.destroy(); - }, timeout); - }); +describe('Sticky.stick', function () { + beforeEach(function () { + tmp1 = $('
').height(1200).prependTo("body"); + element = $('
test
'); + element.appendTo('body'); + elementTop = element.offset().top - setTop; + elementBottom = element.offset().top + element.height() - $(window).height() + setTop; + tmp2 = $('
').height(1200).appendTo("body"); }); - describe('Sticky.stick', function () { - beforeEach(function () { - tmp1 = $('
').height(1200).prependTo("body"); - element = $('
test
'); - element.appendTo('body'); - elementTop = element.offset().top - setTop; - elementBottom = element.offset().top + element.height() - $(window).height() + setTop; - tmp2 = $('
').height(1200).appendTo("body"); - }); + afterEach(function () { + tmp1.remove(); + tmp2.remove(); + element.remove(); + element = null; + $('body').css('height', ''); + $(document).off('scroll'); + $(document).scrollTop(0); + }); + + it('返回实例对象', function () { + var obj = Sticky.stick(element, setTop); + expect(obj.destroy).to.be.a('function'); + }); + + it('同一个接口', function () { + expect(Sticky).to.be.a('function'); + expect(Sticky).to.be(Sticky.stick); + }); + + it('默认的 top 值', function () { + var obj = Sticky.stick(element); + expect(obj.position.top).to.be(0); + }); + + it('destroy 方法', function () { + var obj = Sticky.stick(element); + expect(element.data('bind-sticked')).to.be(true); + obj.destroy(); + expect(element.data('bind-sticked')).to.be(false); + }); - afterEach(function () { - tmp1.remove(); - tmp2.remove(); - element.remove(); - element = null; - $('body').css('height', ''); - $(document).off('scroll'); - $(document).scrollTop(0); - }); - - it('返回实例对象', function () { - var obj = Sticky.stick(element, setTop); - expect(obj.destroy).to.be.a('function'); - }); - - it('同一个接口', function () { - expect(Sticky).to.be.a('function'); - expect(Sticky).to.be(Sticky.stick); - }); - - it('默认的 top 值', function () { - var obj = Sticky.stick(element); - expect(obj.position.top).to.be(0); - }); - - it('destroy 方法', function () { - var obj = Sticky.stick(element); - expect(element.data('bind-sticked')).to.be(true); + it('滚动了一像素', function (done) { + var originPosition = element.css('position'); + var obj = Sticky.stick(element, setTop); + $(document).scrollTop(1); + + setTimeout(function () { + if (isPositionStickySupported) { + expect(element.css('position').indexOf("sticky") !== -1).to.be(true); + } else { + expect(element.css('position')).to.be(originPosition); + } + done(); obj.destroy(); - expect(element.data('bind-sticked')).to.be(false); - }); + }, timeout); + }); - it('滚动了一像素', function (done) { - var originPosition = element.css('position'); - var obj = Sticky.stick(element, setTop); - $(document).scrollTop(1); + it('滚动到差一像素', function (done) { + var originPosition = element.css('position'); + var obj = Sticky.stick(element, setTop); + $(document).scrollTop(elementTop - 1); + + setTimeout(function () { + if (isPositionStickySupported) { + expect(element.css('position').indexOf("sticky") !== -1).to.be(true); + } else { + expect(element.css('position')).to.be(originPosition); + } + done(); + obj.destroy(); + }, timeout); + }); - setTimeout(function () { - if (isPositionStickySupported) { - expect(element.css('position').indexOf("sticky") !== -1).to.be(true); - } else { - expect(element.css('position')).to.be(originPosition); - } - done(); - obj.destroy(); - }, timeout); - }); + it('滚动到元素临界位置', function (done) { + var obj = Sticky.stick(element, setTop); + $(document).scrollTop(elementTop); + + setTimeout(function () { + if (isPositionStickySupported) { + expect(element.css('position').indexOf("sticky") !== -1).to.be(true); + } else if (isPositionFixedSupported) { + expect(element.css('position')).to.be("fixed"); + } else { + expect(element.css('position')).to.be("absolute"); + } + done(); + obj.destroy(); + }, timeout); + }); - it('滚动到差一像素', function (done) { - var originPosition = element.css('position'); - var obj = Sticky.stick(element, setTop); - $(document).scrollTop(elementTop - 1); + it('滚动到元素临界位置多一像素', function (done) { + var obj = Sticky.stick(element, setTop); + $(document).scrollTop(elementTop + 1); + + setTimeout(function () { + if (isPositionStickySupported) { + expect(element.css('position').indexOf("sticky") !== -1).to.be(true); + } else if (isPositionFixedSupported) { + expect(element.css('position')).to.be("fixed"); + } else { + expect(element.css('position')).to.be("absolute"); + } + done(); + obj.destroy(); + }, timeout); - setTimeout(function () { - if (isPositionStickySupported) { - expect(element.css('position').indexOf("sticky") !== -1).to.be(true); - } else { - expect(element.css('position')).to.be(originPosition); - } - done(); - obj.destroy(); - }, timeout); - }); + }); - it('滚动到元素临界位置', function (done) { - var obj = Sticky.stick(element, setTop); - $(document).scrollTop(elementTop); + it('滚动到元素临界位置多300像素', function (done) { + var obj = Sticky.stick(element, setTop); + $(document).scrollTop(elementTop + 300); + + setTimeout(function () { + if (isPositionStickySupported) { + expect(element.css('position').indexOf("sticky") !== -1).to.be(true); + } else if (isPositionFixedSupported) { + expect(element.css('position')).to.be("fixed"); + } else { + expect(element.css('position')).to.be("absolute"); + } + done(); + obj.destroy(); + }, timeout); + }); - setTimeout(function () { - if (isPositionStickySupported) { - expect(element.css('position').indexOf("sticky") !== -1).to.be(true); - } else if (isPositionFixedSupported) { - expect(element.css('position')).to.be("fixed"); - } else { - expect(element.css('position')).to.be("absolute"); - } - done(); - obj.destroy(); - }, timeout); - }); + it('不可见元素', function (done) { + var obj = Sticky.stick(element, setTop); + element.hide(); + $(document).scrollTop(elementTop + 300); - it('滚动到元素临界位置多一像素', function (done) { - var obj = Sticky.stick(element, setTop); - $(document).scrollTop(elementTop + 1); + setTimeout(function () { + expect(element.css('position').indexOf("sticky") !== -1 || element.css('position') === "static").to.be(true); + done(); + element.show(); + obj.destroy(); + }, timeout); + }); - setTimeout(function () { - if (isPositionStickySupported) { - expect(element.css('position').indexOf("sticky") !== -1).to.be(true); - } else if (isPositionFixedSupported) { - expect(element.css('position')).to.be("fixed"); - } else { - expect(element.css('position')).to.be("absolute"); - } - done(); - obj.destroy(); - }, timeout); + it('非块级元素,不加占位元素,以减少复杂性', function (done) { + element.css('display', 'inline') + var obj = Sticky.stick(element, setTop); + $(document).scrollTop(elementTop + 300); - }); + setTimeout(function () { + expect(obj._placeholder).to.be(undefined); + done(); + obj.destroy(); + }, timeout); + }); - it('滚动到元素临界位置多300像素', function (done) { - var obj = Sticky.stick(element, setTop); - $(document).scrollTop(elementTop + 300); + it('stick 回调', function (done) { + var triggered = 0; - setTimeout(function () { - if (isPositionStickySupported) { - expect(element.css('position').indexOf("sticky") !== -1).to.be(true); - } else if (isPositionFixedSupported) { - expect(element.css('position')).to.be("fixed"); - } else { - expect(element.css('position')).to.be("absolute"); - } - done(); - obj.destroy(); - }, timeout); + var obj = Sticky.stick(element, setTop, function(status) { + if (status) { + triggered = 1; + } else { + triggered = 2; + } }); - it('不可见元素', function (done) { - var obj = Sticky.stick(element, setTop); - element.hide(); - $(document).scrollTop(elementTop + 300); + $(document).scrollTop(elementTop); + + setTimeout(function () { + expect(triggered).to.be(1); + $(document).scrollTop(0); setTimeout(function () { - expect(element.css('position').indexOf("sticky") !== -1 || element.css('position') === "static").to.be(true); + expect(triggered).to.be(2); done(); - element.show(); obj.destroy(); }, timeout); - }); + }, timeout); + }); - it('非块级元素,不加占位元素,以减少复杂性', function (done) { - element.css('display', 'inline') - var obj = Sticky.stick(element, setTop); - $(document).scrollTop(elementTop + 300); + it('重复绑定', function (done) { + var triggered = 0; - setTimeout(function () { - expect(obj._placeholder).to.be(undefined); - done(); - obj.destroy(); - }, timeout); + var obj1 = Sticky.stick(element, setTop, function(status) { + if (status) { + triggered = 1; + } else { + triggered = 2; + } + }); + var obj2 = Sticky.stick(element, setTop, function(status) { + if (status) { + triggered = 3; + } else { + triggered = 4; + } }); - it('stick 回调', function (done) { - var triggered = 0; - - var obj = Sticky.stick(element, setTop, function(status) { - if (status) { - triggered = 1; - } else { - triggered = 2; - } - }); + $(document).scrollTop(elementTop); - $(document).scrollTop(elementTop); + setTimeout(function () { + expect(triggered).to.be(1); - setTimeout(function () { - expect(triggered).to.be(1); - $(document).scrollTop(0); + done(); - setTimeout(function () { - expect(triggered).to.be(2); - done(); - obj.destroy(); - }, timeout); - }, timeout); - }); + obj1.destroy(); + }, timeout); + }); - it('重复绑定', function (done) { - var triggered = 0; - - var obj1 = Sticky.stick(element, setTop, function(status) { - if (status) { - triggered = 1; - } else { - triggered = 2; - } - }); - var obj2 = Sticky.stick(element, setTop, function(status) { - if (status) { - triggered = 3; - } else { - triggered = 4; - } - }); - - $(document).scrollTop(elementTop); + it("不支持 position: sticky 的情况", function(done) { + Sticky.isPositionStickySupported = false; - setTimeout(function () { - expect(triggered).to.be(1); + var obj = Sticky.stick(element, setTop); + $(document).scrollTop(elementTop + 300); - done(); + setTimeout(function () { + expect(element.css('position')).to.be(isPositionFixedSupported ? 'fixed' : 'absolute'); + done(); + obj.destroy(); + }, timeout); + }); - obj1.destroy(); - }, timeout); - }); + it("强制支持 position: sticky 的情况", function(done) { + Sticky.isPositionStickySupported = true; - it("不支持 position: sticky 的情况", function(done) { - Sticky.isPositionStickySupported = false; + var obj = Sticky.stick(element, setTop); + $(document).scrollTop(elementTop + 300); - var obj = Sticky.stick(element, setTop); - $(document).scrollTop(elementTop + 300); + setTimeout(function () { + expect(element.css('position').indexOf("sticky") !== -1 || element.css('position') === "static").to.be(true); + $(document).scrollTop(0); - setTimeout(function () { - expect(element.css('position')).to.be(isPositionFixedSupported ? 'fixed' : 'absolute'); + setTimeout(function() { + expect(element.css('position').indexOf("sticky") !== -1 || element.css('position') === "static").to.be(true); done(); obj.destroy(); }, timeout); - }); - - it("强制支持 position: sticky 的情况", function(done) { - Sticky.isPositionStickySupported = true; - - var obj = Sticky.stick(element, setTop); - $(document).scrollTop(elementTop + 300); - - setTimeout(function () { - expect(element.css('position').indexOf("sticky") !== -1 || element.css('position') === "static").to.be(true); - $(document).scrollTop(0); + }, timeout); + }); - setTimeout(function() { - expect(element.css('position').indexOf("sticky") !== -1 || element.css('position') === "static").to.be(true); - done(); - obj.destroy(); - }, timeout); - }, timeout); - }); + it("不支持 position: sticky 且不支持 position: fixed 的情况", function(done) { + Sticky.isPositionStickySupported = false; - it("不支持 position: sticky 且不支持 position: fixed 的情况", function(done) { - Sticky.isPositionStickySupported = false; + Sticky.isPositionFixedSupported = false; - Sticky.isPositionFixedSupported = false; + var obj = Sticky.stick(element, setTop); + $(document).scrollTop(elementTop + 300); - var obj = Sticky.stick(element, setTop); - $(document).scrollTop(elementTop + 300); + setTimeout(function () { + expect(element.css('position')).to.be('absolute'); + $(document).scrollTop(0); setTimeout(function () { - expect(element.css('position')).to.be('absolute'); - $(document).scrollTop(0); - - setTimeout(function () { - expect(element.css('position') === "static").to.be(true); + expect(element.css('position') === "static").to.be(true); - done(); - obj.destroy(); + done(); + obj.destroy(); - }, timeout); }, timeout); + }, timeout); + }); + + it('手工调用 adjust', function (done) { + var triggered = 0; + + var obj = Sticky.stick(element, setTop, function(status) { + if (status) { + triggered = 1; + } else { + triggered = 2; + } }); - it('手工调用 adjust', function (done) { - var triggered = 0; + $(document).scrollTop(elementTop); - var obj = Sticky.stick(element, setTop, function(status) { - if (status) { - triggered = 1; - } else { - triggered = 2; - } - }); + setTimeout(function () { + expect(triggered).to.be(1); - $(document).scrollTop(elementTop); + tmp1.css('height', tmpHeight + 200); + obj.adjust(); + expect(triggered).to.be(2); + $(document).scrollTop(elementTop + 200); setTimeout(function () { expect(triggered).to.be(1); - - tmp1.css('height', tmpHeight + 200); - obj.adjust(); - expect(triggered).to.be(2); - $(document).scrollTop(elementTop + 200); - - setTimeout(function () { - expect(triggered).to.be(1); - done(); - obj.destroy(); - }, timeout); + done(); + obj.destroy(); }, timeout); + }, timeout); + }); + + it('set top and bottom', function(done) { + var triggered = 0; + + var obj = Sticky.stick(element, { + top: setTop, + bottom: setTop + }, function(status) { + if (status) { + triggered = 1; + } else { + triggered = 2; + } }); + $(document).scrollTop(elementTop); - it('set top and bottom', function(done) { - var triggered = 0; - - var obj = Sticky.stick(element, { - top: setTop, - bottom: setTop - }, function(status) { - if (status) { - triggered = 1; - } else { - triggered = 2; - } - }); - $(document).scrollTop(elementTop); + setTimeout(function() { + expect(triggered).to.be(1); + $(document).scrollTop(elementBottom + 1); setTimeout(function() { - expect(triggered).to.be(1); + expect(triggered).to.be(2); - $(document).scrollTop(elementBottom + 1); + $(document).scrollTop(elementBottom); setTimeout(function() { - expect(triggered).to.be(2); - - $(document).scrollTop(elementBottom); - setTimeout(function() { - expect(triggered).to.be(1); - done(); - obj.destroy(); - }, timeout); + expect(triggered).to.be(1); + done(); + obj.destroy(); }, timeout); }, timeout); - }); + }, timeout); + }); - it('window resize', function(done) { - var obj = Sticky.stick(element, setTop); - $(document).scrollTop(elementTop); - $(window).resize(); + it('window resize', function(done) { + var obj = Sticky.stick(element, setTop); + $(document).scrollTop(elementTop); + $(window).resize(); - setTimeout(function() { - done(); - }, 200); - }); + setTimeout(function() { + done(); + }, 200); }); });