Лучший способ предварительной загрузки изображений с помощью Angular.js
Angular ng-src сохраняет предыдущую модель, пока она не предварительно загрузит изображение внутри. Я использую другое изображение для баннера на каждой странице, когда я переключаю маршруты, меняю основной вид, оставляя заголовок как есть, просто меняя модель bannerUrl, когда у меня есть.
В результате появляется предыдущее изображение баннера во время загрузки нового.
Я был удивлен, что еще нет директивы, но я хотел сделать дискуссию, прежде чем пытаться ее построить.
Что я хочу сделать, я думаю, есть модель баннера для пользовательского атрибута. как:
<img preload-src="{{bannerUrl}}" ng-src="{{preloadedUrl}}">
Затем $scope.watch для bannerUrl изменится, и как только он изменится, сначала замените ng-src загрузчиком-загрузчиком, а затем создайте tempary img dom, предварительно загрузите изображение из preload-src, а затем передайте его preloadUrl.
Нужно думать, как обрабатывать несколько изображений тоже для галерей, например.
Есть ли у кого-нибудь какие-либо данные? или, может быть, кто-то может указать мне на существующий код?
Я видел существующий код на github, который использует background-image, но это не работает для меня, поскольку мне нужна динамическая высота/ширина, поскольку мое приложение является отзывчивым, и я не могу сделать это с фоновым изображением.
Спасибо
Ответы
Ответ 1
Наличие двух URL-адресов в директиве кажется сложным прикосновением. Я думаю, лучше написать директиву, которая работает как:
<img ng-src="{{bannerUrl}}" spinner-on-load />
И директива может смотреть ng-src
и (например) установить видимость: false с помощью счетчика до загрузки изображения. Так что-то вроде:
scope: {
ngSrc: '='
},
link: function(scope, element) {
element.on('load', function() {
// Set visibility: true + remove spinner overlay
});
scope.$watch('ngSrc', function() {
// Set visibility: false + inject temporary spinner overlay
});
}
Таким образом, элемент ведет себя очень похоже на стандартный img с атрибутом ng-src
, только с небольшим дополнительным поведением, прикрепленным болтами.
http://jsfiddle.net/2CsfZ/47/
Ответ 2
Если кто-то заинтересован, это мое окончательное решение: я использую twitter bootstrap. Таким образом, добавлен класс "затухания" ко всем изображениям и просто переключение класса "в" с директивой по постепенному выходу и выходу изображения при загрузке изображения
angular.module('myApp').directive('imgPreload', ['$rootScope', function($rootScope) {
return {
restrict: 'A',
scope: {
ngSrc: '@'
},
link: function(scope, element, attrs) {
element.on('load', function() {
element.addClass('in');
}).on('error', function() {
//
});
scope.$watch('ngSrc', function(newVal) {
element.removeClass('in');
});
}
};
}]);
<img img-preload class="fade" ng-src="{{imgSrc}}">
Рабочий пример: http://ishq.org
Ответ 3
Если вы хотите, вы можете передать сбой изображения и загрузчик изображений в качестве атрибутов для директивы....
myApp.directive("mySrc", function() {
return {
link: function(scope, element, attrs) {
var img, loadImage;
var IMAGE_LOAD="123.jpg";
var IMAGE_FAIL="123.jpg";
img = null;
loadImage = function() {
element[0].src = IMAGE_LOAD;
img = new Image();
img.src = attrs.mySrc;
img.onload = function() {
element[0].src = attrs.mySrc;
};
img.onerror=function ()
{
element[0].src = IMAGE_FAIL;
}
};
loadImage();
}
};
});
Ответ 4
Просто чтобы поделиться ^^
//css
.media-box{
position: relative;
width:220px;
height: 220px;
overflow: hidden;
}
.media-box div{
position: absolute;
left: 0;
top: 0;
}
.spinner{
position: absolute;
left: 0;
top: 0;
background: #CCC url(./spinner.gif) no-repeat center center;
display: block;
width:220px;
height: 220px;
}
.feed img.spinner-show{
visibility: visible;
}
.feed img.spinner-hide{
visibility: hidden;
}
//html
<div class="media-box">
<div>
<img data-ng-src="{{item.media}}" alt="" title="" data-spinner-on-load>
</div>
</div>
//js
.directive('spinnerOnLoad', function() {
return {
restrict: 'A',
link: function(scope,element){
element.on('load', function() {
element.removeClass('spinner-hide');
element.addClass('spinner-show');
element.parent().find('span').remove();
});
scope.$watch('ngSrc', function() {
element.addClass('spinner-hide');
element.parent().append('<span class="spinner"></span>');
});
}
}
});
Ответ 5
Вместо использования
element.on('load', function() {});
используйте imagesLoaded плагин. Это значительно ускорит ваши изображения.
Таким образом, окончательный код:
link: function(scope, element) {
imagesLoaded(element, function() {
});
scope.$watch('ngSrc', function() {
});
}
Ответ 6
Я думаю, что это, пожалуй, самое элегантное решение, потому что директива фактически создает счетчик и автоматически удаляет его:
app.directive('spinnerLoad', [function spinnerLoad() {
return {
restrict: 'A',
link: function spinnerLoadLink(scope, elem, attrs) {
scope.$watch('ngSrc', function watchNgSrc() {
elem.hide();
elem.after('<i class="fa fa-spinner fa-lg fa-spin"></i>'); // add spinner
});
elem.on('load', function onLoad() {
elem.show();
elem.next('i.fa-spinner').remove(); // remove spinner
});
}
};
}]);
Вот html:
<img ng-src='{{imgUrl}}' spinner-load />
Примечание. Для этого вам нужно будет использовать шрифт, отличный от этого, чтобы работать, как описано здесь.
Ответ 7
У меня есть эта директива, которая показывает spinner при изменении img-src:
<img-with-loading
img-src="{{src}}"
spinner-class="{{spinnerClass}}"
/>
Код здесь: http://jsfiddle.net/ffabreti/yw74upyr/
Ответ 8
изображения могут быть предварительно загружены при изменении маршрута с помощью image-preloader factory и решить:
// call REST
return getContent.get().$promise.then(function(response) {
//return response;
// preload images from response
var imageLocations = [
// put image(s) from response to array
response.PostImage.big[0],
];
// check do we have (all) image(s) in array
console.log(imageLocations);
// return when all images are preloaded
return preloader.preloadImages( imageLocations )
.then(function() {
//if it was success
return response;
},
function() {
//if it failed
return response;
});
});
полный учебник здесь:
https://www.coditty.com/code/angular-preload-images-on-route-change-by-using-resolve
Ответ 9
Простое решение, которое я нашел, это изменить URL-адрес на "//: 0" перед назначением нового значения
$scope.bannerUrl = 'initial value';
// When we want to change it
$scope.bannerUrl = '//:0'; // remove the previous img so it not visible while the new one loads
$scope.bannerUrl = scope.preloadedUrl