深入懒加载

   懒加载(LazyLoad)一直是前端的优化方案之一。它的核心思想是:当用户想看页面某个区域时,再加载该区域的数据。这在一定程度上减轻了服务器端的压力,也加快了页面的呈现速度。

   懒加载多用于图片,因为它属于流量的大头。最典型的懒加载实现方案是先将需要懒加载的图片的src隐藏掉,这样图片就不会下载,然后在图片需要呈现给用户时再加上src属性。

   公司内部库的懒加载正是采用这种方案。它会遍历页面中所有的图片,将其src缓存起来后删除图片的src属性,当图片进入用户的可视区域后再为图片附加src属性。这种方案存在着以下不足:

   ① 在IE和FF下,懒加载的脚本运行时,有部分图片已经于服务器建立链接,这部分abort掉,再在滚动时延迟加载,反而增加了链接数。

   ② 在chrome下,由于webkit内核bug,导致无法abort掉下载,懒加载脚本完全无用。

   ③ 它只能针对图片的懒加载,但无法懒加载页面的某个模块(即延迟渲染页面的DOM节点)。

   

   因此,在原有的技术方案之上,必须实现新的方案来解决这些问题。受到淘宝的懒加载模块启发,思路如下:

   ① 提供一种方式来让我们手动为页面中每个需要懒加载的图片缓存它的src属性,例如:原来的图片为<img src="xxx.jpg" />,现在改为<img data-src="xxx.jpg">。这样,页面在解析的时候,所有懒加载的图片在所有的浏览器下都不会下载,图片进入视野区域时再将data-src赋值给src属性。

   ② 提供延迟加载页面模块的方案。将研究发现,textarea是个不错的容器,浏览器会将该标签内的内容当作普通文本看待。因此,可以将页面中需要懒加载的模块放入textarea容器中,带需要的时候再将其取出。淘宝美食网正是大量运用了模块延迟加载方案。http://chi.taobao.com/market/food/auto.php?spm=885.125570.154248.13.F5s7Bt

基于上述思路,我写了一个懒加载的组件。该组件基于jquery,提供的接口如下:

return {
	init : _init,
	addCallBack : _addCallBack
};
init函数可以初始化该组件,它提供给我们的自定义选项如下:

	var config = {
		mod : 'auto', //分为auto和manul
		IMG_SRC_DATA : 'img-lazyload',
		AREA_DATA_CLS : 'area-datalazyload'
	};
mod 分为自动和手动模式,自动模式正是前面讨论到的目前存在的实现方案,而手动方式是后来讨论的方案①,在手动方式下,我们需要将每个需要懒加载的图片的src属性缓存到一个用户可以自定义的属性中,默认为'img-lazyload',即原始的图片改为<img img-lazyload='xxx.jpg'>。

此外,不管是自动模式和手动模式下,都可以进行模块的懒加载,这时候,需要在每个模块的外层添加textarea容器,并且,将其visibility属性设置为hidden,class设置为一个用户可以自定义的值,默认为'area-datalazyload'。

  实例如下:

//自动模式
datalazyload.init({
    'mod' :auto
});

//手动模式
datalazyload.init({
    'mod' :manual,
   'IMG_SRC_DATA'  : 'data-src'
});

addCallback是特定元素即将出现时的回调函数。调用如下:

datalazyload.addCallback($el,function(event){
     //TO DO
})
其中$el是某个需要延迟加载的jquery对象,function是自定义的回调函数。


组件适用场景:① 有许多图片的页面,例如游戏特权首页:http://vip.qq.com/game.html

              ② 有许多模块,并且每个模块分工明确的页面,例如淘宝美食:http://chi.taobao.com/market/food/auto.php?spm=885.125570.154248.13.F5s7Bt


组件如下:

/**
 * @fileOverview 数据懒加载组件
 * @require jQuery
 */

datalazyload = (function($){

	var config = {
		mod : 'auto', //分为auto和manul
		IMG_SRC_DATA : 'img-lazyload',
		AREA_DATA_CLS : 'area-datalazyload'
	};
	
	
	var IMG_SRC_DATA = '';
	var AREA_DATA_CLS = '';
	
	//用来存放需要懒加载的图片和数据块
	var imgArr = [];
	var areaArr = [];
	
	//支持用户回调的事件类型
	var eventType = 'lazy';
	
    /**
     * 提供给外部的接口
     * @param {Object} [userConfig] 用户自定义配置
     * @private
    */	
	function _init(userConfig) {
		config = $.extend(config,userConfig);
		console.log(config);
		IMG_SRC_DATA = config.IMG_SRC_DATA;
		AREA_DATA_CLS = config.AREA_DATA_CLS;
		_filterItems();
		_initEvent();
	}
	
    /**
     * 处理需要懒加载的图片和数据块的入口
     * @private
    */	
	function _filterItems() {
		_filterImgs();
		_filterAreas();
	}

    /**
     * 事件绑定
     * @private
    */		
	function _initEvent() {
		$(window).scroll(_eventHandler);
		$(window).resize(_eventHandler);
		_eventHandler();
	}

    /**
     * 处理需要懒加载的图片
     * @private
    */	
	function _filterImgs() {
		if (config.mod === 'auto') { 
			//自动模式
			var $imgs = $("img");
			$imgs.each(function() {
				imgArr.push(this);
				var $img = $(this);
				$img.targetY = _getTargetY($img[0]);//先计算出每个图片距离页面顶部的高度,避免在事件事件处理函数中进行大量重复计算
				var dataSrc = $img.attr(IMG_SRC_DATA);
				//对于已存在IMG_SRC_DATA的,可能其它实例处理过,我们直接跳过去
				if (!dataSrc) {
					$img.attr(IMG_SRC_DATA,$img.attr('src'));
					$img.removeAttr('src');
				}
			});
		} else {
			//手动模式下,已经在需要懒加载的IMG中设置了IMG_SRC_DATA属性,所以不作任何处理
			var $imgs = $("img["+IMG_SRC_DATA+"]");
			$imgs.each(function() {
				imgArr.push(this);
				var $img = $(this);
				$img.targetY = _getTargetY($img[0]);//先计算出每个图片距离页面顶部的高度,避免在事件事件处理函数中进行大量重复计算
			});
		}
	}
	
    /**
     * 处理需要懒加载的数据块
     * @private
    */	
	function _filterAreas() {
		var $areas = $("textarea[class='"+AREA_DATA_CLS+"']");
		$areas.each(function() {
			areaArr.push(this);
			var $area = $(this);
			$area.targetY = _getTargetY($area[0]);
		});
	}

    /**
     * window节点的scroll和resize的事件处理函数
     * @private
    */
	function _eventHandler() {
		$.each(imgArr,function(i,el){
			if (el !== undefined) {
				var $img = $(el);
				if (_checkBounding($img)) {
					$img.attr('src',$img.attr(IMG_SRC_DATA));
					$img.trigger(eventType);
					$img.unbind(eventType);
					delete imgArr[i];
				}
			}
		});
		$.each(areaArr,function(i,el){
			if (el !== undefined) {
				var $area = $(el);
				if (_checkBounding($area)) {
					$area.hide();
					$area.removeClass(AREA_DATA_CLS);
					var $div = $("<div></div>");
					$div.insertBefore($area);
					$div.html($area.val());
					delete areaArr[i];
				}
			}
		});		
		
	}
    /**
     * 检查需要懒加载的节点是否进入可视区域
     * @param {jQuery Object} [el]
     * @private
    */	
	function _checkBounding($el) {
		var scrollY = document.body.scrollTop || document.documentElement.scrollTop || window.pageYOffset || 0;//页面滚动条高度
		var seeY = window.innerHeight || document.documentElement.clientHeight;//浏览器可视区域高度
		if ($el.targetY) {
			var targetY = $el.targetY;
		} else {
			var targetY = _getTargetY($el[0]);
		}
		
		//当目标节点进入可使区域
		if (Math.abs(targetY - scrollY) < seeY) {
			return true;
		} else {
			return false;
		}
	} 
	
    /**
     * 获取目标节点距离页面顶部高度
     * @param {HTML Element} [el]
     * @private
    */	
	function _getTargetY(el) {
		var tp = el.offsetTop;
		if (el.offsetParent) {
			while (el = el.offsetParent) {
				tp += el.offsetTop;
			}
		}
		return tp;
	}
	
    /**
     * 特定元素即将出现时的回调函数
     * @param {jQuery Obj} [$el] 
     * @param {Function} [func]
     * @private
    */		
	function _addCallBack($el,func) {
		$el.bind(eventType,function(event) {
			func.call($el,event);
		});
	}
	return {
		init : _init,
		addCallBack : _addCallBack
	};
	
})(jQuery);

  • 1
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
引用和提到了androidx中实现Fragment懒加载的方案。在androidx中,可以使用setMaxLifecycle()方法来设置Fragment的状态,取代了setUserVisibleHint()方法。通过在构造FragmentPagerAdapter时传入BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT参数,并将加载数据的逻辑放到Fragment的onResume()方法中,就可以实现Fragment的懒加载。这种方案可以有效地减少不必要的数据加载和提高性能。同时,androidx还引入了一些新的内容,为开发者提供了很多便利。你可以参考相关的文章和代码来深入了解和实践该方案。 引用提到了网上已经有很多关于androidx的Fragment懒加载的文章,但大多数只是点到了setMaxLifecycle()和修改FragmentPagerAdapter这两个方面,很少有实践的文章。因此,该文章详细记录了作者实践后的结果,可以作为更加详尽的参考。 总结起来,androidx中的Fragment懒加载可以通过setMaxLifecycle()方法和修改FragmentPagerAdapter来实现,并且androidx还引入了一些新的内容,为开发者提供了更多便利。你可以参考相关的文章和代码来了解和实践该方案。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [androidx中的Fragment懒加载方案](https://blog.csdn.net/qq_36486247/article/details/102531304)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 33.333333333333336%"] - *2* [androidx中的Fragment懒加载](https://blog.csdn.net/tongsiw/article/details/107991830)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 33.333333333333336%"] - *3* [androidx下的fragment的lazy懒加载问题详解](https://download.csdn.net/download/weixin_38606656/14916018)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 33.333333333333336%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值