Angularjs - елементами ng-cloak / ng-show блимають


231

У мене проблема в angular.js з директивою / класом ng-cloakабо ng-show.

Chrome працює чудово, але Firefox викликає миготіння елементів з ng-cloakабо ng-show. IMHO це викликано перетворенням ng-cloak/ ng-showв style="display: none;", ймовірно, компілятор JavaScript Firefox трохи повільніше, тому елементи з'являються на деякий час, а потім ховаються?

Приклад:

<ul ng-show="foo != null" ng-cloak>..</ul>

1
якщо встановити відображення: жоден стиль на цих елементах спочатку не вирішує проблему?
akonsu

3
Я спробую це, я намагався щось подібне із додаванням класу (який приховує елемент), а потім видаленням його через js вручну, але це виглядало ще гірше.
MelkorNemesis

Відповіді:


385

Хоча документація не згадує про це, можливо, буде недостатньо додати display: none;правило до CSS. У випадках, коли ви завантажуєте angular.js в тілі, або шаблони не збираються досить швидко, скористайтеся ng-cloakдирективою та включіть у свій CSS наступне:

/* 
  Allow angular.js to be loaded in body, hiding cloaked elements until 
  templates compile.  The !important is important given that there may be 
  other selectors that are more specific or come later and might alter display.  
 */
[ng\:cloak], [ng-cloak], .ng-cloak {
  display: none !important;
}

Як згадується в коментарі, !importantважливим є. Наприклад, якщо у вас є така розмітка

<ul class="nav">
  <li><a href="/foo" ng-cloak>{{bar}}</a></li>
</ul>

а ви випадково використовуєте bootstrap.css, наступний селектор є більш конкретним для вашого ng-cloak'ed елемента

.nav > li > a {
  display: block;
}

Отже, якщо ви включите правило просто display: none;, правило Bootstrap матиме перевагу і displayбуде встановлено значення block, тож ви побачите мерехтіння перед тим, як шаблон буде зібраний.


3
Також зауважте, що ця сама проблема може трапитися, якщо ви завантажуєте angular.js за допомогою асинхронного завантажувача, такого як requ.js, оскільки правило css в .js не буде проаналізовано в часі. Наведене вище рішення також фіксує цей сценарій.
Йоганн

84
Не вирішує проблему для мене. Не знаю - я думаю, що браузери занадто охоче показують речі спочатку ...
Андрій Дроздюк

7
Браузер НІКОЛИ не повинен відображати DOM, не враховуючи css, навіть при першому проході; це було б дуже неефективно; Перевірте налаштування: p
AlexG

1
як ви перезавантажуєте dom, який був накручений ng, як тільки ви ледаче завантажуєте код модуля doms?
FutuToad

Якщо вище CSS не працює для вас , швидше за все , ваш :в ng:cloakНЕ екрановані. Для чистого CSS переконайтесь, що зворотна косої риби є. Для складеного css, наприклад, Stylus, він буде [ng\\:cloak]. Перевірте свій складений CSS, щоб переконатися, що він правильний.
Джо

47

Як зазначено в документації , ви повинні додати правило до свого CSS, щоб приховати його на основі ng-cloakатрибута:

[ng\:cloak], [ng-cloak], .ng-cloak {
    display: none;
}

Ми використовуємо подібні хитрощі на веб-сайті "Вбудований з кутовим", який ви можете переглянути джерело на Github: https://github.com/angular/builtwith.angularjs.org

Сподіваюся, що це допомагає!


4
angular.js додає це правило стилю до голови документа. Вам дійсно не потрібно додавати це до свого CSS. Але це, здається, працює. Я здогадуюсь тому, що angular.js не додає блоку стилю до голови, поки не завантажить angular.
ntownsend

13
Що дійсно згадується в документації, це таке: "Для найкращого результату сценарій angular.js повинен бути завантажений у головний розділ html-файлу; в якості альтернативи , правило css (вище) повинно бути включене у зовнішній таблицю стилів програми. "
Андрій Дроздюк

4
Іншими словами, якщо ви додаєте посилання на свої сценарії внизу сторінки (як це робить багато людей); потім додайте правило до CSS.
GFoley83

1
Я додавав angular.js з Requ.js, тому це мені допомогло.
оливкова

1
Додана директива ng-cloak до html-елемента, що містить директиву ng-app. Працював як шарм. Приклад: <div ng-cloak ng-app = "my-app">
miniscem

33

Переконайтеся, що AngularJS включений у headHTML-код. Див. Документ ngCloak :

Для найкращого результату сценарій angular.js повинен бути завантажений у головний розділ html-файлу; альтернативно, правило css (вище) повинно бути включене у зовнішній таблицю стилів програми.


3
так! Я не можу зрозуміти, чому, здається, люди скрізь рекомендують завантажувати angular.js в кінці сторінки. Я відчуваю себе краще, якщо Angular візьме на себе контроль з самого початку. Моя ng-cloakзараз працює.
Іван Феррер Вілла

2
Я згоден - річ щодо завантаження скриптів в кінці походить від звичайної веб-розробки, де ви хочете, щоб сторінка відображала щось до того, як js зробить свою справу, але у випадку кутового ви насправді хочете зворотне.
див. Гостріше

1
І перед завантаженням будь-яких таблиць стилів. Включення кутового в headтаблицю стилів, але після цього не вирішує проблему.
AgmLauncher

27

Мені ніколи не пощастило використовувати ngCloak. Я все ще мерехтію, незважаючи на все, що було сказано вище. Єдиний надійний спосіб уникнути мерехтіння - помістити свій вміст у шаблон і включити шаблон. В SPA єдиний HTML, який буде оцінено перед його складанням Angular, - це ваша головна сторінка index.html.

Просто візьміть все, що знаходиться всередині тіла, і вставте його в окремий файл, а потім:

<ng-include src="'views/indexMain.html'"></ng-include>

У вас ніколи не виникає мерехтіння таким чином, коли Angular буде збирати шаблон перед тим, як додати його до DOM.


1
Саме те, що я використовую - чисте і просте, без болісних злому.
Дмитро Зайцев

2
Зауважте, що ng-includeстворюється додатковий запит AJAX для отримання вмісту з сервера. Я навчився важкого шляху, наприклад, ніколи не слід використовувати ng-includeвсередині ng-repeat.
jsuddsjr

1
працював на мене. не забудьте тримати ng-appпоза ng-includeвашої розмітки.
GraehamF

2
Таке рішення працює найкраще, без жодної гикавки. Якщо це можливо, використовуйте цей розчин.
idungotnosn

2
Це рішення виправило справді прикрий стан. Дякую!
Максвелл

22

ngBind та ngBindTemplate - це альтернативи, які не потребують CSS:

<div ng-show="foo != null" ng-cloak>{{name}}</div>  <!-- requires CSS -->
<div ng-show="foo != null" ng-bind="name"></div>
<div ng-show="foo != null" ng-bind-template="name = {{name}}"></div>

1
Гарна, проста відповідь. ng-bindце хороший спосіб уникнути «фігурної спалаху брекетів» або використовувати його ng-cloakна рівні тегів, хоча деякі люди думають, що це робить код менш читабельним. Для них я не бачу причини не змішувати два підходи.
Дейв Еверітт

1
ng-bind набагато кращий підхід до проблеми, оскільки інші відповіді вимагають завантаження першого кутового, без фігурних брекетів взагалі не спалахнути ні за яких обставин
legramira

20

На додаток до прийнятої відповіді, якщо ви використовуєте альтернативний метод спрацьовування ng-cloak ...

Ви також можете додати деякі додаткові особливості до свого CSS / МЕНШИ:

[ng\:cloak], [ng-cloak], [data-ng-cloak], [x-ng-cloak],
.ng-cloak, .x-ng-cloak,
.ng-hide {
    display: none !important;
}

1
Це спрацювало для мого використання, коли жодне з перерахованого вище, здавалося б, не спрацювало.
Порлун

15

У мене була подібна проблема і з'ясувалося, що якщо у вас клас, який містить переходи, елемент буде блимати. Я намагався додати ng-плащ без успіху, але, знявши перехід, кнопка перестала блимати.

Я використовую іонний фреймворк, і контур кнопки має цей перехід

.button-outline {
  -webkit-transition: opacity .1s;
  transition: opacity .1s;
}

Просто перезапишіть клас, щоб видалити перехід, і кнопка перестане блимати.

Оновлення

Знову на ionic з’являється мерехтіння при використанні ng-show / ng-hid. Додавання наступних CSS вирішує це:

.ng-hide-add,
.ng-hide-remove {
  display: none !important;
}

Джерело: http://forum.ionicframework.com/t/beta-14-ng-hide-show/14270/9


1
Але чи не відключить анімацію директиви ng-hid / show?
Кушагра Гур

1
Я не можу згадати. Ви спробували це, і це вимкнуло анімацію?
Seb Fanals

1
Дякую. Це дуже особлива проблема щодо іонної. Я додав .button-clear, .button-icon, .button-outline { @include transition(opacity 0s); }до scss.
hgoebl

9

У мене виникла проблема, коли а <div ng-show="expression">спочатку було б видно частку секунди, хоча "вираз" спочатку був помилковим, перш ніж директива ng-show отримала шанс запуститись.

Я використовував рішення, щоб вручну додати клас "ng-hid", як у <div ng-show="expression" ng-hide>, щоб переконатися, що він почався приховано. Директива ng-show після цього додасть / видалить клас ng-hid.


1
Нічого, з усіх химерних варіантів, які я спробував, це зробило трюк. Дякую!
Микола

Найкраще рішення! Це зводило мене з розуму протягом кількох місяців! Дякую!
абелаббеснабі

Я використовую іонні рамки, і це єдина відповідь, яка насправді працює
Мікель

7

Спробуйте вимкнути Firebug . Я серйозно. Це допомагає в моєму випадку.

Застосуйте прийняту відповідь і переконайтесь, що Firebug у вашому Firefox перетворений вимкнено : натисніть F12, а потім вимкніть Firebug для цієї сторінки - маленьку кнопку у верхньому правому куті.


Так, це зробили для мене Спасибі!
MadeInDreams

Дякую, що зводило мене з розуму. Дивна помилка
Стівен Сімпсон

6

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

Проблема 1: нг-плащ наноситься занадто пізно

Це питання вирішується так, як визначено в багатьох відповідях на цій сторінці, щоб переконатися, що AngularJS завантажений в голову. Див. Документ ngCloak :

Для найкращого результату сценарій angular.js повинен бути завантажений у головний розділ html-файлу; альтернативно, правило css (вище) повинно бути включене у зовнішній таблицю стилів програми.

Проблема 2: нг-плащ знімається занадто рано

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

Рішення jQuery у відповідях, що включають додавання style="display:none"до вашого елемента, вирішують цю проблему до тих пір, поки стиль буде видалено досить пізно (адже ці рішення вирішують обидві проблеми). Однак якщо ви не хочете додавати стилі безпосередньо у свій HTML, ви можете досягти тих же результатів, використовуючиng-show .

Починаючи з прикладу з питання:

<ul ng-show="foo != null" ng-cloak>..</ul>

Додайте до свого елемента додаткове правило ng-show:

<ul ng-show="isPageFullyLoaded && (foo != null)" ng-cloak>..</ul>

(Вам потрібно тримати, ng-cloakщоб уникнути проблеми 1).

Потім у своєму наборі app.run isPageFullyLoaded:

app.run(['$rootScope', function ($rootScope) {
    $rootScope.$safeApply = function (fn) {
        $rootScope.isPageFullyLoaded = true;
    }
}]);

Майте на увазі, що залежно від того, що саме ви робите, app.run може бути чи не найкращим місцем для встановлення isPageFullyLoaded. Найважливіше - переконатися, що isPageFullyLoadedвстановлено значення true після того, як ви не хочете, щоб мерехтіння було готове розкрити користувачеві.

Здається, що Проблема 1 - це проблема, з якою стикається ОП, але інші виявляють, що рішення не працює або лише частково працює, тому що замість них також потрапляє проблема 2 .

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


1
це для мене виправлено "скрипт повинен бути завантажений в головному розділі"
aliopi

4

Ми зіткнулися з цією проблемою в нашій компанії і вирішили її, додавши в CSS-стилі "display: none" для цих мерехтливих елементів ng-show. Нам взагалі не довелося використовувати ng-плащ. На відміну від інших у цій темі, ми відчували цю проблему в Safari, але не в Firefox чи Chrome - можливо, через ліниву помилку перефарбовування Safari в iOS7 .


3

Чому це варто, у мене подібний випуск ng-плаща не працював. Можливо, варто перевірити ваше додаток / сайт із увімкненим кешем для повторного використання вихідних файлів, щоб побачити, чи це допомагає.

З моїм запуском із мерехтінням я тестував DevTools open та кеш-вимкнення. Залишивши панель закритою кеш-пам'яттю, виправлено мою проблему.



3

Я не міг змусити жоден із цих методів працювати, тому в кінцевому підсумку я зробив наступне. Для елемента, який ви хочете спочатку приховати:

<div <!--...--> style="display: none;" ng-style="style">

Потім у свій контролер додайте це вгорі або біля нього:

$scope.style = { display: 'block' };

Таким чином, елемент спочатку прихований і показує лише те, коли дійсно запущений код контролера.

Ви можете налаштувати розташування під свої потреби, можливо, додавши певної логіки. У моєму випадку я перемикаюся на шлях входу, якщо в даний момент не входив у систему, і не хотів, щоб мій інтерфейс заздалегідь мерехтів, тому я встановив $scope.styleпісля реєстрації реєстрацію.


2

Краще використовувати ng-ifзамість ng-show. ng-if повністю видаляє та відтворює елемент у DOM та допомагає уникнути блимання ng-шоу.


але він також знищує будь-які запущені плагіни на тій частині дому ... (наприклад: jquery ui)
Geert Bellemans

2

Я використовую ionic фреймворк, додавання стилю css може не працювати для певних обставин, ви можете спробувати використовувати ng-if замість ng-show / ng-hid

посилання: https://books.google.com.my/books?id=-_5_CwAAQBAJ&pg=PA138&lpg=PA138&dq=ng-show+hide+flickering+in+ios&source=bl&ots=m2Turk8DFh&sig=8hNiWx26euGR2k_WeyaVzdixJ8k&hl=en&sa=X&redir_esc=y#v = одна сторінка & q = ng-show% 20hide% 20flickering% 20in% 20ios & f = false


2

вам краще посилатись на кутовий документ, тому що версія [1.4.9] має оновлення нижче, що дозволяє підтримувати директиву data-ng-cloak.

[ng\:cloak], [ng-cloak], [data-ng-cloak], [x-ng-cloak], .ng-cloak, .x-ng-cloak {
  display: none !important;
}

2

Я спробував рішення ng-cloak вище, але воно все ще має періодичні проблеми з Firefox. Єдине рішення, яке працювало для мене, - це затримати завантаження форми до повного завантаження Angular.

Я просто додав ng-init у додаток і використовую ng-if у формі форми, щоб перевірити, чи змінена я вже встановлена ​​змінна.

<div ng-app="myApp" ng-init="loaded='yes'"> 
   <form ng-if="loaded.length > 0">
      <!--all my elements here-->
   </form>
</div>

1

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

Документи кажуть: "Для найкращого результату сценарій angular.js повинен бути завантажений у головний розділ html-документа; або, як правило, вищевказане правило css має бути включене у зовнішній таблицю стилів програми."

Тепер це не повинно бути зовнішнім таблицею стилів, а лише елементом в голові.

<style type="text/css">
  .ng-cloak {
    display: none !important;
  }
</style>

джерело: https://docs.angularjs.org/api/ng/directive/ngCloak


1

Я перепробував кожне рішення, розміщене тут, і все ще отримав мерехтіння у Firefox.

Якщо це комусь допомагає, я вирішив це, додавши style="display: none;"в основний розділ вмісту, потім використовуючи jQuery (я вже використовував його на сторінці), $('#main-div-id').show();коли все було завантажено після отримання даних з сервера;


Я виявив, що це єдине рішення, яке працювало на мене, але я хотів уникнути використання JQuery, тому знайшов альтернативу. Дивіться мою відповідь тут: stackoverflow.com/a/42527700/4214694
Ендрю Даунес

1

Я дійсно знайшов пропозицію з Веб-журналу Ріка Страля, виправив мою проблему чудово (оскільки у мене все-таки виникала дивна проблема, коли ng-плащ моргав сирим {{код}} часом, особливо під час запуску Firebug):

Ядерний варіант: приховування вмісту вручну

Використання явного CSS є найкращим вибором, тому наступне ніколи не повинно бути необхідним. Але я згадаю тут, оскільки це дає деяке розуміння того, як ви можете приховати / показати вміст вручну під час завантаження для інших фреймворків або у власних шаблонах на основі розмітки.

Перш ніж зрозуміти, що я можу явно вставити стиль CSS на сторінку, я спробував з’ясувати, чому ng-cloak не робить своєї роботи. Затративши годину, потрапляючи нікуди, я нарешті вирішив просто вручну сховатися і показати контейнер. Ідея проста - спочатку схойте контейнер, а потім покажіть його, як тільки Angular зробить початкову обробку та видалення розмітки шаблону зі сторінки.

Ви можете вручну заховати вміст і зробити його видимим після того, як Angular отримав контроль. Для цього я використав:

<div id="mainContainer" class="mainContainer boxshadow"
    ng-app="app" style="display:none">

Зауважте на дисплеї: жоден стиль, який явно не приховує елемент спочатку на сторінці.

Потім, як тільки Angular запустить ініціалізацію та ефективно обробить розмітку шаблону на сторінці, ви зможете показати вміст. Для Angular ця подія "готова" - це функція app.run ():

app.run( function ($rootScope, $location, cellService) {        
    $("#mainContainer").show();
    
});

Це ефективно видаляє дисплей: жоден стиль та вміст не відображається. На момент запуску app.run () DOM буде готовий до відображення із заповненими даними або принаймні порожніми даними - Angular отримав контроль.


Я виявив, що це єдине рішення, яке працювало на мене, але я хотів уникнути використання JQuery, тому знайшов альтернативу. Дивіться мою відповідь тут: stackoverflow.com/a/42527700/4214694
Ендрю Даунес

1

Я спробував усі відповіді вище, і нічого не вийшло. Використовуючи ionic для розробки гібридної програми, намагався зробити повідомлення про помилку не мерехтінням. Я вирішив свою проблему, додавши до мого елемента клас ng-hid. У мого div вже є ng-show, щоб показати елемент, коли є помилка. Додаючи ng-hid, встановіть, щоб div не відображався перед завантаженням кута. Не потрібно плащок або додавання кутових до голови.


1

ЯК з наведеного обговорення

[ng-cloak] {
                display: none;
            }

є ідеальним способом вирішення проблеми.


1

Я використовую ng-show у директиві, щоб показати та приховати спливаючі вікна.

<div class="..." ng-show="showPopup">

Ніщо з перерахованого вище не працювало для мене, і використання ng-if замість ng-show було б надмірним. Це означатиме видалення та додавання всього спливаючого вмісту в DOM при кожному натисканні кнопки. Натомість я додав ng-if в той самий елемент, щоб переконатися, що він не відображається при завантаженні документа:

<div class="..." ng-show="showPopup" ng-if="popupReady">

Згодом я додав ініціалізацію до контролера, відповідального за цю директиву, з таймаутом:

$timeout(function () {
    $scope.popupReady = true;
});

Таким чином я усунув мерехтливу проблему і уникнув дорогої операції вставки DOM при кожному натисканні кнопки. Це відбулося за рахунок використання двох змінних області застосування для однієї і тієї ж мети замість однієї, але поки що це, безумовно, найкращий варіант.


1

Спробував, ng-cloakале все-таки коротко блимає. Нижче код повністю позбавить їх.

<body style="display:none;" ng-style="{'display':'block'}">

1

Жодне з перерахованих вище рішень не працювало для мене. Тоді я вирішив переглянути фактичну функцію і зрозумів, що коли «$ range.watch» був запущений, він вводив значення в поле імені, яке не повинно було бути таким. Тож у коді я встановив і oldValue, і newValue

$scope.$watch('model.value', function(newValue, oldValue) {
if (newValue !== oldValue) {
validateValue(newValue);
}
});

По суті, коли в цьому випадку запускається domain.watch, AngularJS контролює зміни змінної імені (model.value)


0

Я б завернув <ul>з a<div ng-cloak>


2
Йому не потрібно загортати <ul>. ng-cloakбуде закривати той елемент, до якого він застосований, а також нащадків цього елемента.
бтфорд

0

Я особисто вирішив використовувати ng-classатрибут, а не theng-show . Я мав набагато більше успіхів у цьому маршруті, особливо для спливаючих вікон, які завжди не відображаються за замовчуванням.

Що раніше було <div class="options-modal" ng-show="showOptions"></div>

зараз: <div class="options-modal" ng-class="{'show': isPrintModalShown}">

при цьому CSS для класу мод опцій display: noneза замовчуванням. Шоу-клас містить display:blockCSS.


-2

Уникайте розриву лінії

<meta http-equiv="Content-Security-Policy"              content="
default-src 'FOO';   
script-src 'FOO';    
style-src  'FOO'; 
font-src 'FOO';">

Працює з Firefox 45.0.1

<meta http-equiv="Content-Security-Policy"              content="    default-src 'FOO';    script-src 'FOO';     style-src  'FOO';    font-src 'FOO';">
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.