使用步骤 1. 下载所需文件 这里提供原生 JavaScript 和 jQuery 两个版本可供下载: 从 GitHub 下载 2. 插入 JavaScript 和添加执行脚本 在页面底部 </body> 之前加入代码, 原生 JavaScript 例子如下: <script src="sidebar-follow.js"></script> <script> /* <![CDATA[ */ (new SidebarFollow()).init({ element: 'sidebar-follow', distanceToTop: 15 }); /* ]]> */ </script> 使用 jQuery 环境的例子如下: <script src="jquery.js"></script> <!-- 如果已在网站的其他地方引入 jQuery, 请不要在次引入 --> <script src="sidebar-follow-jquery.js"></script> <script> /* <![CDATA[ */ (new SidebarFollow()).init({ element: jQuery('#sidebar-follow'), distanceToTop: 15 }); /* ]]> */ </script> 以上两段代码,请根据自己的环境选择,择其一使用即可。 后话 这个区域主要用于了推荐热门文章和增加广告展示, 希望增加用户逗留时间和广告点击率. 侧边栏跟随功能的开发很简单, 我一直不做是担心页面太多浮动区域影响用户阅读, 但现在页面跟随区域已经被广泛使用, 用户也习惯了那我也跟风加上. 现分享出来, 希望对其他站长也有帮助. jquery 版本:
/**
 * @author: mg12 [http://www.neoease.com/]
 * @update: 2012/12/05
 */

SidebarFollow = function() {

	this.config = {
		element: null, // 处理的节点
		distanceToTop: 0 // 节点上边到页面顶部的距离
	};

	this.cache = {
		originalToTop: 0, // 原本到页面顶部的距离
		prevElement: null, // 上一个节点
		parentToTop: 0, // 父节点的上边到顶部距离
		placeholder: jQuery('<div>') // 占位节点
	}
};

SidebarFollow.prototype = {

	init: function(config) {
		this.config = config || this.config;
		var _self = this;
		var element = jQuery(_self.config.element);

		// 如果没有找到节点, 不进行处理
		if(element.length <= 0) {
			return;
		}

		// 获取上一个节点
		var prevElement = element.prev();
		while(prevElement.is(':hidden')) {
			prevElement = prevElement.prev();
			if(prevElement.length <= 0) {
				break;
			}
		}
		_self.cache.prevElement = prevElement;

		// 计算父节点的上边到顶部距离
		var parent = element.parent();
		var parentToTop = parent.offset().top;
		var parentBorderTop = parent.css('border-top');
		var parentPaddingTop = parent.css('padding-top');
		_self.cache.parentToTop = parentToTop + parentBorderTop + parentPaddingTop;

		// 滚动屏幕
		jQuery(window).scroll(function() {
			_self._scrollScreen({element:element, _self:_self});
		});

		// 改变屏幕尺寸
		jQuery(window).resize(function() {
			_self._scrollScreen({element:element, _self:_self});
		});
	},

	/**
	 * 修改节点位置
	 */
	_scrollScreen: function(args) {
		var _self = args._self;
		var element = args.element;
		var prevElement = _self.cache.prevElement;

		// 获得到顶部的距离
		var toTop = _self.config.distanceToTop;

		// 如果 body 有 top 属性, 消除这些位移
		var bodyToTop = parseInt(jQuery('body').css('top'), 10);
		if(!isNaN(bodyToTop)) {
			toTop += bodyToTop;
		}

		// 获得到顶部的绝对距离
		var elementToTop = element.offset().top - toTop;

		// 如果存在上一个节点, 获得到上一个节点的距离; 否则计算到父节点顶部的距离
		var referenceToTop = 0;
		if(prevElement && prevElement.length === 1) {
			referenceToTop = prevElement.offset().top + prevElement.outerHeight();
		} else {
			referenceToTop = _self.cache.parentToTop - toTop;
		}

		// 当节点进入跟随区域, 跟随滚动
		if(jQuery(document).scrollTop() > elementToTop) {
			// 添加占位节点
			var elementHeight = element.outerHeight();
			_self.cache.placeholder.css('height', elementHeight).insertBefore(element);
			// 记录原位置
			_self.cache.originalToTop = elementToTop;
			// 修改样式
			element.css({
				top: toTop + 'px',
				position: 'fixed'
			});

		// 否则回到原位
		} else if(_self.cache.originalToTop > elementToTop || referenceToTop > elementToTop) {
			// 删除占位节点
			_self.cache.placeholder.remove();
			// 修改样式
			element.css({
				position: 'static'
			});
		}
	}
};

js版本:
/**
 * @author: mg12 [http://www.neoease.com/]
 * @update: 2012/12/05
 */

SidebarFollow = function() {

	this.config = {
		element: null, // 处理的节点
		distanceToTop: 0 // 节点上边到页面顶部的距离
	};

	this.cache = {
		originalToTop: 0, // 原本到页面顶部的距离
		prevElement: null, // 上一个节点
		parentToTop: 0, // 父节点的上边到顶部距离
		placeholder: document.createElement('div') // 占位节点
	}
};

SidebarFollow.prototype = {

	init: function(config) {
		this.config = config || this.config;
		var _self = this;
		var element = document.getElementById(_self.config.element);
		var prevElement =  document.getElementById(_self.config.prevElement);

		// 如果没有找到节点, 不进行处理
		if(!element) {
			return;
		}

		// 获取上一个节点
		var prevElement = _self._getPrevElement(element);
		while(prevElement.offsetHeight < 0) {
			prevElement = _self._getPrevElement(prevElement);
			if(!prevElement) {
				break;
			}
		}
		_self.cache.prevElement = prevElement;

		// 计算父节点的上边到顶部距离
		var parent = element.parentNode;
		var parentToTop = _self._getCumulativeOffset(parent).top;
		var parentBorderTop = parseInt(parent.style.borderTop, 10);
		var parentPaddingTop = parseInt(parent.style.paddingTop, 10);
		_self.cache.parentToTop = parentToTop + parentBorderTop + parentPaddingTop;

		// 滚动屏幕
		_self._addListener(window, 'scroll', function() {
			_self._scrollScreen({element:element, prevElement:prevElement, _self:_self});
		});

		// 改变屏幕尺寸
		_self._addListener(window, 'resize', function() {
			_self._scrollScreen({element:element, prevElement:prevElement, _self:_self});
		});
	},

	/**
	 * 修改节点位置
	 */
	_scrollScreen: function(args) {
		var _self = args._self;
		var element = args.element;
		var prevElement = args.prevElement;
		var toTop = _self.config.distanceToTop;

		// 如果 body 有 top 属性, 消除这些位移
		var bodyToTop = parseInt(document.getElementsByTagName('body')[0].style.top, 10);
		if(!isNaN(bodyToTop)) {
			toTop += bodyToTop;
		}

		var elementToTop = 0;
		if(element.style.position === 'fixed') {
			elementToTop = _self._getScrollY();
		} else {
			elementToTop = _self._getCumulativeOffset(element).top - toTop;
		}
		var elementToPrev = _self._getCumulativeOffset(prevElement).top + _self._getVisibleSize(prevElement).height;

		// 当节点进入跟随区域, 跟随滚动
		if(_self._getScrollY() > elementToTop) {
			// 添加占位节点
			var elementHeight = _self._getVisibleSize(element).height;
			_self.cache.placeholder.style.height = elementHeight + 'px';
			element.parentNode.insertBefore(_self.cache.placeholder, element);
			// 记录原位置
			_self.cache.originalToTop = elementToTop;
			// 修改样式
			element.style.top = toTop + 'px';
			element.style.position = 'fixed';

		// 否则回到原位
		} else if(_self.cache.originalToTop > elementToTop || elementToPrev > elementToTop) {
			var parent = _self.cache.placeholder.parentNode;
			if(parent) {
				// 删除占位节点
				parent.removeChild(_self.cache.placeholder);
				// 修改样式
				element.style.position = 'static';
			}
		}
	},

	/**
	 * 获取累计偏移量, 即元素到页面左上角的横行和纵向距离
	 */
	_getCumulativeOffset: function(element) {
		var offset = {
			left:0,
			top:0
		};

		do {
			offset.left += element.offsetLeft || 0;
			offset.top += element.offsetTop  || 0;
			element = element.offsetParent;
		} while (element);

		return offset;
	},

	/**
	 * 获取元素可见尺寸 (包括边线和滚动条)
	 */
	_getVisibleSize: function(element) {
		var dimension = {
			width:0,
			height:0
		};

		dimension.width = element.offsetWidth;
		dimension.height = element.offsetHeight;

		return dimension;
	},

	/**
	 * 获得滚动条纵向距离
	 */
	_getScrollY: function() {
		if(typeof window.pageYOffset != 'undefined') {
			return window.pageYOffset;
		}

		if(typeof document.compatMode != 'undefined' && document.compatMode != 'BackCompat') {
			return document.documentElement.scrollTop;
		}

		return document.body.scrollTop;
	},

	/**
	 * 添加监听事件
	 */
	_addListener: function(node, type, listener) {
		if(node.addEventListener) {
			node.addEventListener(type, listener, false);
			return true;
		} else if(node.attachEvent) {
			node['e' + type + listener] = listener;
			node[type + listener] = function() {
				node['e' + type + listener](window.event);
			};
			node.attachEvent('on' + type, node[type + listener]);
			return true;
		}
		return false;
	},

	/**
	 * 获取上一个节点
	 */
	_getPrevElement: function(element) {
		var prev = element.previousSibling;
		while(prev.nodeType !== 1) {
			prev = prev.previousSibling;
		}
		return prev;
	}
};

分类: web

标签: