angularjs: odpowiednik ng-src dla background-image: url (…)


150

W angularjs masz tag ng-src, którego celem jest to, że nie otrzymasz błędu dla nieprawidłowego adresu URL, zanim angularjs będzie mógł ocenić zmienne umieszczone między {{a }}.

Problem polega na tym, że używam całkiem sporo DIV z background-imageustawionym adresem URL. Robię to ze względu na doskonałą właściwość CSS3, background-sizektóra przycina obraz do dokładnego rozmiaru DIV.

Jedynym problemem jest to, że otrzymuję wiele błędów z tego samego powodu, dla którego utworzyli tag ng-src: mam kilka zmiennych w adresie URL, a przeglądarka uważa, że ​​obraz nie istnieje.

Zdaję sobie sprawę, że jest możliwość napisania prymitywnego {{"style='background-image:url(myVariableUrl)'"}}, ale to wydaje się „brudne”.

Szukałem dużo i nie mogę znaleźć właściwego sposobu, aby to zrobić. Z powodu tych wszystkich błędów moja aplikacja staje się bałaganem.

Odpowiedzi:


200

ngSrcjest dyrektywą natywną, więc wygląda na to, że potrzebujesz podobnej dyrektywy, która modyfikuje background-imagestyl Twojego elementu div .

Możesz napisać własną dyrektywę, która robi dokładnie to, co chcesz. Na przykład

app.directive('backImg', function(){
    return function(scope, element, attrs){
        var url = attrs.backImg;
        element.css({
            'background-image': 'url(' + url +')',
            'background-size' : 'cover'
        });
    };
});​

Które byś wywołał w ten sposób

<div back-img="<some-image-url>" ></div>

JSFiddle z uroczymi kotami jako bonus: http://jsfiddle.net/jaimem/aSjwk/1/


67
Bardzo ładna dyrektywa; jedynym problemem jest to, że nie obsługuje interpolacji. Prawdopodobnie zmodyfikowałbym to w ten sposób: jsfiddle.net/BinaryMuse/aSjwk/2
Michelle Tilley

1
Dziękuję, nie ma znaczenia, że ​​jest bez interpolacji, ma kocięta!
Visgean Skeloru

Czy są jakieś problemy z bezpieczeństwem, jeśli ładujesz z niezaufanych źródeł?
Aakil Fernandes

to działa, ale tylko wtedy, gdy adres URL obrazu jest już zdefiniowany, użyj @mythz answer stackoverflow.com/a/15537359/1479680, aby uzyskać lepszy dostępny adres URL
Magico

229

Ten działa dla mnie

<li ng-style="{'background-image':'url(/static/'+imgURL+')'}">...</li>

22
Myślę, że to powinna być akceptowana odpowiedź. Nie ma potrzeby dodawania niestandardowej dyrektywy.
Jakob Løkke Madsen

2
Dodałem odpowiedź podobną do tej, używając tylko interpolacji
wiherek

1
Jest brudniejszy w tym sensie, że dyrektywa pasuje do wszystkich, wszędzie tam, gdzie potrzebne jest dynamiczne tło. Pytanie wspomniało, że wydaje się, że nie nadaje się do ponownego użycia.
Christian Bonato,

Nie działa w Angular 1.5.8, nadal próbuje załadować obraz imgURLbez ustawionego i ponawia próbę, gdy imgURLzostanie ustawiony.
leroydev

To jest niepoprawne, jeśli masz jakieś specjalne zmienne, takie jak @% w swoim adresie URL, zepsuje się.
efwjames

69

Powyższa odpowiedź nie obsługuje obserwowalnej interpolacji (i kosztowała mnie dużo czasu podczas debugowania). Link jsFiddle w @BrandonTilley komentarzu była odpowiedź, że pracował dla mnie, co będę ponownie post tutaj dla zachowania:

app.directive('backImg', function(){
    return function(scope, element, attrs){
        attrs.$observe('backImg', function(value) {
            element.css({
                'background-image': 'url(' + value +')',
                'background-size' : 'cover'
            });
        });
    };
});

Przykład użycia kontrolera i szablonu

Kontroler :

$scope.someID = ...;
/* 
The advantage of using directive will also work inside an ng-repeat :
someID can be inside an array of ID's 
*/

$scope.arrayOfIDs = [0,1,2,3];

Szablon:

Użyj w szablonie w następujący sposób:

<div back-img="img/service-sliders/{{someID}}/1.jpg"></div>

lub tak:

<div ng-repeat="someID in arrayOfIDs" back-img="img/service-sliders/{{someID}}/1.jpg"></div>

40

Można również zrobić coś takiego za pomocą ng-style:

ng-style="image_path != '' && {'background-image':'url('+image_path+')'}"

który nie próbowałby pobrać nieistniejącego obrazu.


2
@sqren zobacz również, jeśli używasz nowszej wersji Angular (1.1.5 i nowszych): stackoverflow.com/a/12151492/1218080 . Dodano obsługę rzeczywistego operatora trójskładnikowego w widokach.
zasada holograficzna

prosta konkatenacja ciągów znaków, taka jak ta, działała dla mnie na obiekcie zasięgu, zamiast interpolacji.
Shardul

25

Podobnie jak odpowiedź Hooblei, tylko z interpolacją:

<li ng-style="{'background-image': 'url({{ image.source }})'}">...</li>

1
To nie działa tutaj: <span ng-style="{'background-image': 'url(/styles/images/profile.png)'}" style="background-image: url("");"></span>. Podejście @hooblei zadziałało.
Marcos Lima

Uzyskanie tego samego wyniku :(
Kushal Jayswal,

9

tylko kwestia gustu, ale jeśli wolisz mieć bezpośredni dostęp do zmiennej lub funkcji:

<div id="playlist-icon" back-img="playlist.icon">

zamiast interpolować w ten sposób:

<div id="playlist-icon" back-img="{{playlist.icon}}">

wtedy możesz zdefiniować dyrektywę nieco inaczej, z scope.$watchktórą zrobi to $parsena atrybucie

angular.module('myApp', [])
.directive('bgImage', function(){

    return function(scope, element, attrs) {
        scope.$watch(attrs.bgImage, function(value) {
            element.css({
                'background-image': 'url(' + value +')',
                'background-size' : 'cover'
            });
        });
    };
})

więcej informacji na ten temat można znaleźć tutaj: AngularJS: Różnica między metodami $ observ i $ watch


2

@jaime, twoja odpowiedź jest w porządku. Ale jeśli twoja strona ma $ http.get, użyj ng-if

app.directive('backImg', function(){
    return function($scope, $element, $attrs){
        var url = $attrs.backImg;
        $element.css({
            'background-image': 'url(' + url + ')',
            'background-size': 'cover'
        });
    }
});

w fabryce

app.factory('dataFactory', function($http){
    var factory = {};
    factory.getAboutData = function(){
        return $http.get("api/about-data.json");
    };
    return factory;
});

w obszarze kontrolera

app.controller('aboutCtrl', function($scope, $http, dataFactory){
    $scope.aboutData = [];
    dataFactory.getAboutData().then(function(response){
        // get full home data
        $scope.aboutData = response.data;
        // banner data
        $scope.banner = {
            "image": $scope.aboutData.bannerImage,
            "text": $scope.aboutData.bannerText
        };
    });
});

a widok, jeśli użyjesz ng-if jak poniżej, otrzymasz obraz przez interpolację, w przeciwnym razie nie możesz uzyskać obrazu, ponieważ dyrektywa pobiera wartość przed żądaniem HTTP.

<div class="stat-banner"  ng-if="banner.image" background-image-directive="{{banner.image}}">

1

Zauważyłem, że z 1.5 komponentami wyodrębnianie stylu z DOM działa najlepiej w mojej sytuacji asynchronicznej.

Przykład:

<div ng-style="{ 'background': $ctrl.backgroundUrl }"></div>

A w kontrolerze coś takiego:

this.$onChanges = onChanges;

function onChanges(changes) {
    if (changes.value.currentValue){
        $ctrl.backgroundUrl = setBackgroundUrl(changes.value.currentValue);
    }
}

function setBackgroundUrl(value){
    return 'url(' + value.imgUrl + ')';
}

0

Ponieważ wspomniałeś ng-srci wygląda na to, że chcesz, aby strona zakończyła renderowanie przed załadowaniem obrazu, możesz zmodyfikować odpowiedź jaime, aby uruchomić natywną dyrektywę po zakończeniu renderowania przez przeglądarkę.

Ten post na blogu dość dobrze to wyjaśnia; Zasadniczo, można włożyć $timeoutopakowanie do window.setTimeoutwcześniej funkcji połączenia zwrotnego, w którym można wprowadzać te modyfikacje CSS.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.