1.package.json中引入

"imgcache.js": "^1.0.0"

2.yarn install 保证插件的加入
3.verdor.js 加入引用

"imgcache.js/js/imgcache.js"

4.开始实现功能,一共自定义两个文件
5.新建image-loader.js

/*** 图片加载,已加载图片会缓存在应用本地,非应用环境使用浏览器缓存*/
angular.module('app.services').factory('imageLoader', function($ionicPlatform, $cmApi, $cmLocalStorage) {// 本地存储预加载列表特征值const PRELOAD_HASH = 'preloadHash';// 本地存储预加载列表已加载计数const PRELOAD_COUNT = 'preloadCount';// 加载并行请求限制const LOAD_REQUEST_LIMIT = 5;// 预加载并行请求限制const PRELOAD_REQUEST_LIMIT = 3;// 图片缓存区容量const CACHE_QUOTA = 100 * 1024 * 1024;// 正在进行中的图片请求计数let requestCount = 0;// 请求队列const requestQueue = [];let imageCache = null;// 等待执行的预加载任务let preloadTask = null;let startPreloadWithDelay = null;// 初始化图片缓存$ionicPlatform.ready(function() {if (window.cordova && window.ImgCache) {ImgCache.options.chromeQuota = CACHE_QUOTA;// if (ionic.Platform.isIOS()) {//     ImgCache.options.useDataURI = true;// }window.ImgCache.init(function() {imageCache = window.ImgCache;// 如果有等待执行的预加载任务,则开始预加载if (preloadTask) {preloadTask();preloadTask = null;}}, angular.noop);}});// 处理请求队列中第一个请求function processRequestInQueue() {if (requestQueue.length) {requestQueue.shift()();}}// 生成对象特征值function generateHashCode(obj) {const str = JSON.stringify(obj);let hash = 0,i,chr,len;if (str.length === 0) return hash;for (i = 0, len = str.length; i < len; i++) {chr = str.charCodeAt(i);hash = (hash << 5) - hash + chr;hash |= 0;}return hash;}return {// 加载图片load: function($image, src, successCallback) {const deferred = $cmApi.defer();// 使用 web 环境直接加载图片const useOnlineImage = function() {const img = document.createElement('img');requestCount++;img.onload = function() {$image[0].src = src;if (successCallback) {successCallback();}deferred.resolve();requestCount--;};img.onerror = function() {deferred.reject();requestCount--;};img.src = src;};const loadHandler = function() {if (imageCache) {// 加载图片,图片没有本地缓存时先缓存至本地ImgCache.useCachedFileWithSource($image,src,function() {if (successCallback) {successCallback();}deferred.resolve();},function() {useOnlineImage();// 使用 wifi 时缓存图片const connection = navigator.connection;if (connection && connection.type == Connection.WIFI) {ImgCache.cacheFile(src);}});} else {useOnlineImage();}};if (requestCount <= LOAD_REQUEST_LIMIT) {loadHandler();} else {requestQueue.push(loadHandler);}deferred.promise.finally(processRequestInQueue);return deferred.promise;},// 加载本地图片loadLocalImage: function($image, src, successCallback) {const deferred = $cmApi.defer();if (imageCache) {ImgCache.useCachedFileWithSource($image,src,function() {if (successCallback) {successCallback();}deferred.resolve();},function() {deferred.reject();});} else {deferred.reject();}return deferred.promise;},// 获取当前已缓存图片容量getCurrentSize: function() {if (imageCache) {return (imageCache.getCurrentSize() / 1024 / 1024).toFixed(1) + 'MB';}},// 清除本地缓存clearCache: function() {const deferred = $cmApi.defer();if (window.ImgCache) {ImgCache.clearCache(function() {// 清除本地预加载信息$cmLocalStorage.remove(PRELOAD_HASH);$cmLocalStorage.remove(PRELOAD_COUNT);deferred.resolve({status: 200,data: {},});},function() {deferred.reject();});} else {deferred.reject();}return deferred.promise;},// 预加载图片preload: function(imageList) {const hash = generateHashCode(imageList);let i = 0;let loaded = 0; // 已完成计数let interval = null;// 检查上一次是否有部分预加载已完成if (hash == $cmLocalStorage.get(PRELOAD_HASH, 0)) {// 加载未完成内容loaded = +$cmLocalStorage.get(PRELOAD_COUNT, 0);} else {// 设置新预加载信息$cmLocalStorage.set(PRELOAD_HASH, hash);$cmLocalStorage.set(PRELOAD_COUNT, 0);}// 记录已加载数量const recordLoadedCount = function(index) {if (index > loaded) {loaded = index;// 每加载10张图或加载完成时记录一次加载进度if (index % 10 === 0 || index === imageList.length - 1) {$cmLocalStorage.set(PRELOAD_COUNT, index);}}};// 预加载图片const preloadImage = function(index) {const src = imageList[index];ImgCache.isCached(src, function(src, cached) {if (cached) {recordLoadedCount(index);} else {requestCount++;ImgCache.cacheFile(src,function() {requestCount--;recordLoadedCount(index);processRequestInQueue();},function() {requestCount--;processRequestInQueue();});}});};// 停止预加载const stopPreload = function() {if (interval) {clearInterval(interval);interval = null;}};// 开始预加载const startPreload = function() {const connection = navigator.connection;if (!connection || connection.type != Connection.WIFI || interval) return;i = loaded;if (i < imageList.length) {interval = setInterval(function() {if (connection.type != Connection.WIFI) {stopPreload();return;}// 限制并发请求数量if (requestCount > PRELOAD_REQUEST_LIMIT) return;if (i < imageList.length) {preloadImage(i);i++;}if (i >= imageList.length) {stopPreload();document.removeEventListener('online', startPreloadWithDelay);document.removeEventListener('offline', stopPreload);}}, 1000);}};// 网络恢复后延时1秒开始预加载startPreloadWithDelay = function() {setTimeout(function() {startPreload();}, 1000);};document.addEventListener('online', startPreloadWithDelay, false);document.addEventListener('offline', stopPreload, false);// 检查图片缓存是否已初始化,预加载延迟至图片缓存初始化后开始if (imageCache) {startPreload();} else {preloadTask = startPreload;}},};
});

2.新建lazyload.js

/*** 延迟图片加载,图片进入可视区时才进行加载* preLoadVertical  <Integer>  控制预加载高度,默认 50* preLoadHorizontal  <Integer>  控制预加载宽度,默认 30* loadImmediate  <Boolean>  不检测是否在可视范围内直接开始加载,默认 false* lazyloadWatch  <Boolean>  是否监视图片url变更更新图片,默认 false*/
angular.module('app.directives').directive('cmLazyload', function($document, imageLoader) {// 延迟加载样式类const CLASS_LAZY_LOAD = 'lazyload';const CLASS_LOADED = 'lazyload-loaded';const CLASS_FINISHED = 'lazyload-finished';let ANIMATIONEND_EVENT = '';if (window.onanimationend === undefined && window.onwebkitanimationend !== undefined) {ANIMATIONEND_EVENT = 'webkitAnimationEnd animationend';} else {ANIMATIONEND_EVENT = 'animationend';}// 占位图片const SPACER ='data:image/gif;base64,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';// 加载失败后可重试次数上限const RETRY_LIMIT = 3;// 指令自增索引let count = 0;// 所有需要监听的滚动区const scrollMap = {};let clientHeight = $document[0].documentElement.clientHeight;// var clientWidth = $document[0].documentElement.clientWidth;window.addEventListener('resize', function() {clientHeight = $document[0].documentElement.clientHeight;// clientWidth = $document[0].documentElement.clientWidth;});// 添加滚动监听function addScrollHandler(scrollPanel, image) {const key = scrollPanel[0].$$hashKey;let scrollDelegate = scrollMap[key];if (!scrollDelegate) {const removeImageFromDelegate = function(id) {delete scrollDelegate.images[id];scrollDelegate.length--;// 滚动区内所有图片已加载时,不再监听滚动if (scrollDelegate.length === 0) {scrollPanel.off('scroll', scrollDelegate.handler);delete scrollMap[key];}};const imageLoadSuccessHandler = function(image) {return function() {removeImageFromDelegate(image.id);image.loading = false;};};const imageLoadErrorHandler = function(image) {return function() {image.retryCount++;if (image.retryCount >= RETRY_LIMIT) {removeImageFromDelegate(image.id);}image.loading = false;};};// 滚动处理const scrollHandler = function(e) {let scrollTop = 0;const event = e.originalEvent;if (event.detail && event.detail.scrollTop) {scrollTop = event.detail.scrollTop;} else {scrollTop = event.target.scrollTop;}for (const id in scrollDelegate.images) {const image = scrollDelegate.images[id];if (!image.loading && isInView(image, scrollTop)) {image.loading = true;loadImage(image).success(imageLoadSuccessHandler(image)).error(imageLoadErrorHandler(image));}}};scrollDelegate = {scrollPanel: scrollPanel,images: {},length: 0,handler: ionic.throttle(scrollHandler, 200),};scrollPanel.on('scroll', scrollDelegate.handler);scrollMap[key] = scrollDelegate;}scrollDelegate.images[image.id] = image;scrollDelegate.length++;}// 检查元素是否在可视区垂直高度内function isInView(element, scrollTop) {const preLoadVertical = element.preLoadVertical;if (scrollTop !== undefined) {const top = element.offsetTop - scrollTop,bottom = top + element.height;return top <= clientHeight + preLoadVertical && bottom >= -preLoadVertical;} else {const $element = element.$element;const imageRect = $element[0].getBoundingClientRect();return (imageRect.top <= clientHeight + preLoadVertical &&imageRect.bottom >= -preLoadVertical);}}// 加载图片function loadImage(image) {const $element = image.$element;// 加载并缓存图片return imageLoader.load($element, image.src, function functionName() {$element.removeClass(CLASS_LAZY_LOAD).addClass(CLASS_LOADED);});}// 淡入动画结束后修改 classfunction animationEnd() {$(this).removeClass(CLASS_LOADED).addClass(CLASS_FINISHED);}// 获取元素坐标和尺寸function getElementRect($element) {let element = $element,offsetLeft = 0,offsetTop = 0,rect = $element[0].getBoundingClientRect();if ($element.is(':visible')) {do {const offset = ionic.DomUtil.getPositionInParent(element[0]);offsetLeft += offset.left;offsetTop += offset.top;element = element.offsetParent();if (element.is('html')) {break;}} while (!element.hasClass('scroll-content'));}return {width: rect.width,height: rect.height,offsetLeft: offsetLeft,offsetTop: offsetTop,};}return {restrict: 'A',scope: false,link: function($scope, $element, $attr) {const scrollPanel = $element.parents('.scroll-content').eq(0);const preLoadVertical = parseInt($attr.preLoadVertical) || 50;const preLoadHorizontal = parseInt($attr.preLoadHorizontal) || 30;const loadImmediate = $attr.loadImmediate;let image = null;// 初始化延迟加载function init() {const src = $scope.$eval($attr.cmLazyload);if (!src) {return;}// 处理 watch 导致图片重加载if (image) {$element.off(ANIMATIONEND_EVENT, animationEnd);$element.removeClass(CLASS_LOADED).removeClass(CLASS_FINISHED);}$element[0].src = SPACER;$element.addClass(CLASS_LAZY_LOAD);$element.on(ANIMATIONEND_EVENT, animationEnd);image = {id: count++,$element: $element,loading: false,retryCount: 0,src: src,preLoadVertical: preLoadVertical,preLoadHorizontal: preLoadHorizontal,};// 释放时间片,等元素渲染完毕后获取元素坐标和尺寸setTimeout(function() {angular.extend(image, getElementRect($element));}, 0);// 检查图片是否已缓存imageLoader.loadLocalImage($element, src, function() {$element.removeClass(CLASS_LAZY_LOAD).addClass(CLASS_LOADED);}).error(function() {// 释放时间片,等元素渲染完毕后检查元素状态setTimeout(function() {if (loadImmediate || isInView(image)) {loadImage(image);} else {angular.extend(image, getElementRect($element));addScrollHandler(scrollPanel, image);}}, 0);});}if ($attr.lazyloadWatch) {const listener = $scope.$watch($attr.cmLazyload, init);$scope.$on('$destroy', listener);} else {init();}},};
});

6.在对应的图片加载中可以添加使用,实现懒加载
将之前的

<img ng-src="{{item.picUrl}}" />

改为

<img cm-lazyload="item.picUrl" />

如果对您有帮助,请点个❤️吧

angular实现图片懒加载相关推荐

  1. 前端如何实现图片懒加载(lazyload) 提高用户体验

    定义 图片懒加载又称图片延时加载.惰性加载,即在用户需要使用图片的时候加载,这样可以减少请求,节省带宽,提高页面加载速度,相对的,也能减少服务器压力. 惰性加载是程序人性化的一种体现,提高用户体验,防 ...

  2. “懒”的妙用——浅析图片懒加载技术

    1.定义 图片懒加载是一种网页优化技术.图片作为一种网络资源,在被请求时也与普通静态资源一样,将占用网络资源,而一次性将整个页面的所有图片加载完,将大大增加页面的首屏加载时间.为了解决这种问题,通过前 ...

  3. 按需加载图片(图片懒加载)

    前言 按需要加载图片,这是一个非常实用的功能,不仅可以提高网站的性能,还可以为你节省流量.对于用虚拟主机的朋友来说,如果你的网站是一个图片网站或者图片比较多的网站,那么图片懒加载功能真不能少. 原理 ...

  4. python怎么加载图片-python爬虫--图片懒加载

    图片懒加载 是一种反爬机制,图片懒加载是一种网页优化技术.图片作为一种网络资源,在被请求时也与普通静态资源一样,将占用网络资源,而一次性将整个页面的所有图片加载完,将大大增加页面的首屏加载时间.为了解 ...

  5. template与图片懒加载

    曲线救国的三种案例 第一种:underscore.js的图片懒加载 1 <script id="t2" type="text/template"> ...

  6. 小程序之图片懒加载[完美方案,你不来看看?]

    效果图 既然来了,把妹子都给你. 定义 懒加载,前端人都知道的一种性能优化方式,简单的来说,只有当图片出现在浏览器的可视区域内时,才设置图片正真的路径,让图片显示出来.这就是图片懒加载. 实现原理 监 ...

  7. Python:图片懒加载技术

    一. 案例分析:抓取站长素材http://sc.chinaz.com/中的图片数据 #!/usr/bin/env python # -*- coding:utf-8 -*- import reques ...

  8. document引用图片的src属性能干嘛_如何实现图片懒加载

    背景 图片懒加载是针对图片加载时机的一种优化,在一些图片量比较大的网站(比如电商网站首页,或者团购网站.小游戏首页等),如果我们尝试在用户打开页面的时候,就把所有的图片资源加载完毕,那么很可能会造成白 ...

  9. 不用计算实现 图片懒加载

    不用计算实现 图片懒加载 给图片加上 data-src 属性 const imgs = document.querySelectorAll("img[data-src]");con ...

最新文章

  1. 用PHP开发命令行工具
  2. 一些VC++ 系统类通用类
  3. IO模型(select, poll, epoll的区别和原理)
  4. MySQL数据库备份工具mysqldump的使用(转)
  5. xampp apache无法启动的解决方法
  6. 如何不出国门走进NLP学术前沿
  7. HDU 5900(区间DP)
  8. opencv如何获取图像的平均颜色
  9. webstorm如何支持markdown
  10. arduino定时器控制舵机_Arduino通过串口控制舵机角度
  11. 电视与电脑连接html线,电视机与电脑连接的方法
  12. BC26低功耗的OPENCPU代码注意事项
  13. “丧心病狂” kite
  14. 爪哇国新游记之二十四----二叉树
  15. linux 极路由救砖,极路由HC5761A救砖日志
  16. php 图片保存在手机里、浏览器保存
  17. DiskGenius 复制磁盘 提示 设备未就绪
  18. 体重预测[线性回归]
  19. WebLogic BEA-101020问题
  20. 关于NTU-RGB+D数据集skeleton数据

热门文章

  1. Discussion 3 某大学宿管阿姨的模拟调研
  2. mysql间隙锁可重入_关于mysql 间隙锁
  3. Java面向对象:多态——基于继承的向上转型、方法重写、动态绑定
  4. 0407itness准备活动(动态拉伸)
  5. sqlserver表压缩
  6. Java Dubbo:(一)Dubbo 简介
  7. 文档搜索软件测试,Quest 搜索测试工具
  8. 闲置宽带做边缘CDN回本话费
  9. 李阳疯狂英语突破对话(67)-周末活动
  10. IBM Watson SDK for Unity基础使用教程