angularjs: еквівалент ng-src для фонового зображення: url (…)


150

У angularjs у вас є тег ng-src, який має на меті не отримати помилку щодо недійсного URL-адреси до того, як angularjs отримає оцінку змінних, розміщених між {{і }}.

Проблема полягає в тому, що я використовую досить багато DIV з background-imageнабором URL. Я роблю це завдяки чудовій властивості CSS3, background-sizeяка обробляє зображення до точного розміру DIV.

Єдина проблема полягає в тому, що я отримую багато помилок саме з тієї ж причини, коли вони створили тег ng-src: у мене в URL-адресі є деякі змінні, і браузер вважає, що зображення не існує.

Я усвідомлюю, що існує можливість написання сирого {{"style='background-image:url(myVariableUrl)'"}}, але це здається "брудним".

Я багато шукав і не можу знайти правильний спосіб зробити це. Моя програма стає безладною через усі ці помилки.

Відповіді:


200

ngSrcє рідною директивою, тому, схоже, ви хочете схожу директиву, яка змінює background-imageстиль вашого діва .

Ви можете написати власну директиву, яка робить саме те, що ви хочете. Наприклад

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

До якого ви б так посилалися

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

JSFiddle з милими котами як бонус: http://jsfiddle.net/jaimem/aSjwk/1/


67
Дуже приємна директива; Єдина проблема полягає в тому, що він не підтримує інтерполяцію. Я б, мабуть, модифікував це таким чином: jsfiddle.net/BinaryMuse/aSjwk/2
Мішель Тіллі

1
Дякую, неважливо, що це без інтерполяції, у нього є кошенята!
Віджей Скелору

Будь-які проблеми із цим щодо безпеки, якщо ви завантажуєтесь з ненадійних джерел?
Аакіл Фернандес

це працює, але тільки якщо ваш URL зображення вже визначена, використовуйте @mythz відповідь stackoverflow.com/a/15537359/1479680 мати краще obeservable URL
Magico

229

Цей працює для мене

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

22
Я думаю, це має бути прийнятою відповіддю. Не потрібно додавати спеціальні директиви.
Jakob Løkke Madsen

2
Я додав відповідь, подібну до тієї, просто використовуючи інтерполяцію
wiherek

1
Це брудніше, в тому сенсі, що директива підходить усім, скрізь вам потрібен динамічний фон. У цьому питанні було зазначено, що він менш сприятливий.
Крістіан Бонато

Не працює в Angular 1.5.8, вона все ще намагається завантажити зображення з imgURLне встановленим і повторюється, коли imgURLвстановлюється.
leroydev

Це неправильно. Якщо у вашій URL-адресі є спеціальні змінні, наприклад @%, вона порушиться.
efwjames

69

Наведена вище відповідь не підтримує спостережувану інтерполяцію (і коштувало мені багато часу на спробу налагодження). Посилання jsFiddle в коментарі @BrandonTilley була відповіддю, яка працювала для мене, яку я повторно опублікую тут для збереження:

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

Приклад за допомогою контролера та шаблону

Контролер:

$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];

Шаблон:

Використовуйте в такому шаблоні:

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

або так:

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

40

Можна також зробити щось подібне за допомогою ng-style:

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

який не намагався б отримати неіснуюче зображення.


2
@sqren також бачить це, якщо ви використовуєте більш нову версію Angular (1.1.5 і вище): stackoverflow.com/a/12151492/1218080 . Додано підтримку фактичного потрійного оператора у видах.
голографічний принцип

проста конкатенація рядків на зразок цього працювала для мене на об'єкті замість інтерполяції.
Шардул

25

Подібний до відповіді Хулі, просто з інтерполяцією:

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

1
Він не працює тут: <span ng-style="{'background-image': 'url(/styles/images/profile.png)'}" style="background-image: url("");"></span>. Підхід @hooblei спрацював.
Маркос Ліма

Отримання того ж результату :(
Кушаль Джейсвал

9

лише питання смаку, але якщо ви віддаєте перевагу доступу до змінної чи функції безпосередньо так:

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

замість інтерполяції так:

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

тоді ви можете визначити директиву дещо інакше, з scope.$watchякою буде діяти $parseатрибут

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'
            });
        });
    };
})

У цьому контексті є більше інформації: AngularJS: Різниця між методами $ спостерігати і $ watch


2

@jaime ваша відповідь чудова. Але якщо на вашій сторінці є $ http.get, тоді ви використовуєте ng-if

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

на заводі

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

в області контролера

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
        };
    });
});

і вигляд, якщо ви будете використовувати ng-if, як показано нижче, ви отримаєте зображення шляхом інтерполяції інакше, ви не можете отримати зображення, тому що директива отримує значення перед HTTP-запитом.

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

1

Я знайшов 1,5 компонентів, які абстрагують стилістику від DOM, щоб найкраще працювати в моїй ситуації з асинхронією.

Приклад:

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

А в контролері щось подібне:

this.$onChanges = onChanges;

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

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

0

Оскільки ви згадали, ng-srcі здається, що ви хочете, щоб сторінка закінчила візуалізацію, перш ніж завантажувати ваше зображення, ви можете змінити відповідь jaime для запуску нативної директиви після того, як браузер закінчить надання.

Це повідомлення в блозі пояснює це досить добре; по суті, ви вставляєте $timeoutобгортку для window.setTimeoutперед функцією зворотного виклику , в якому ви робите ці зміни в CSS.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.