Angularjs - элементы ng-cloak / ng-show мигают

231

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

Chrome работает нормально, но Firefox вызывает мигание элементов с помощью ng-cloakили ng-show. ИМХО, это вызвано преобразованием ng-cloak/ ng-showв style="display: none;", вероятно, компилятор JavaScript Firefox немного медленнее, поэтому элементы появляются на некоторое время, а затем скрываются?

Пример:

<ul ng-show="foo != null" ng-cloak>..</ul>
MelkorNemesis
источник
1
если вы изначально установили display: none style для этих элементов, это решит проблему?
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элемента

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

Поэтому, если вы включите правило просто display: none;, правило Bootstrap будет иметь приоритет, и displayбудет установлено значение block, так что вы увидите мерцание перед компиляцией шаблона.

Тим Шауб
источник
3
Также обратите внимание, что такая же проблема может возникнуть, если вы загружаете angular.js с использованием асинхронного загрузчика, такого как require.js, потому что правило css в .js не будет проанализировано во времени. Решение выше исправляет этот сценарий также.
Иоганн
84
Не решает проблему для меня. Не знаю - я думаю, что браузеры слишком хотят поначалу показывать вещи ...
Андрей Дроздюк
7
Браузер НИКОГДА не должен отображать DOM без учета CSS даже при первом проходе; это было бы крайне неэффективно;
Перепроверьте
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;
}

Мы используем аналогичные приемы на сайте «Built with Angular», источник которого вы можете посмотреть на Github: https://github.com/angular/builtwith.angularjs.org

Надеюсь, это поможет!

btford
источник
4
angular.js добавляет это правило стиля к заголовку документа. Вам действительно не нужно добавлять это в свой CSS. Тем не менее, это похоже на работу. Я предполагаю, что angular.js не добавляет блок стиля к голове, пока не загрузится angular.
ntownsend
13
Что действительно упоминается в документации, так это: «Для достижения наилучшего результата скрипт angular.js должен быть загружен в раздел head файла html; в качестве альтернативы правило css (см. Выше) должно быть включено во внешнюю таблицу стилей приложения. "
Андрей Дроздюк
4
Другими словами, если вы добавляете ссылки на свои скрипты внизу страницы (как это делают многие); затем добавьте правило в свой CSS.
GFoley83
1
Я добавлял angular.js с require.js, так что это помогло мне.
оливковое
1
Добавлена ​​директива ng-cloak в элемент html, содержащий директиву ng-app. Работал как шарм. Пример: <div ng-cloak ng-app = "my-app">
miniscem
33

Убедитесь, что AngularJS включен в headHTML. Видеть документ ngCloak :

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

Андрей Дроздюк
источник
3
да! Я не могу понять, почему люди повсюду рекомендуют загружать angular.js в конце страницы. Я чувствую себя лучше, если Angular берет на себя управление с самого начала. Мой ng-cloakработает сейчас.
Иван Феррер Вилла
2
Я согласен - вещь о скриптах, загружаемых в конце, происходит от обычной веб-разработки, где вы хотите, чтобы страница отображала что-то до того, как js сделает свое дело, но в случае angular вы действительно хотите обратное.
смотрите острее
1
И перед загрузкой любых таблиц стилей. Включение Angular в 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 / LESS:

[ng\:cloak], [ng-cloak], [data-ng-cloak], [x-ng-cloak],
.ng-cloak, .x-ng-cloak,
.ng-hide {
    display: none !important;
}
Кори Баллу
источник
1
Это сработало для моего варианта использования, когда ни один из вышеперечисленных, казалось, не справился с работой.
Porlune
15

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

Я использую ионный каркас и контур кнопки имеет этот переход

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

Просто перезапишите класс, чтобы удалить переход, и кнопка перестанет мигать.

Обновить

Опять же на ионном появляется мерцание при использовании ng-show / ng-hide. Добавление следующего CSS разрешает это:

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

Источник: http://forum.ionicframework.com/t/beta-14-ng-hide-show/14270/9

Себ Фаналс
источник
1
Но не отключит ли это анимацию для директив ng-hide / show?
Кушагра Гур
1
Я не могу вспомнить Вы попробовали это, и это отключило анимацию?
Себ Фаналс
1
Спасибо. Это очень особая проблема для ионных. Я добавил .button-clear, .button-icon, .button-outline { @include transition(opacity 0s); }к своему scss.
hgoebl
9

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

Решение, которое я использовал, состояло в том, чтобы вручную добавить класс ng-hide <div ng-show="expression" ng-hide>, чтобы убедиться, что он изначально был скрыт. После этого директива ng-show добавит / удалит класс ng-hide по мере необходимости.

metamatt
источник
1
вау, из всех мерзких вариантов, которые я пробовал, это помогло. Спасибо!
Никола
Лучшее решение! Это сводило меня с ума в течение нескольких месяцев! Спасибо!
abelabbesnabi
Я использую ионную структуру, и это единственный ответ, который действительно работает
Mikel
7

Попробуйте выключить Firebug . Я серьезно. Это помогает в моем случае.

Примените принятый ответ, а затем убедитесь, что Firebug в вашем Firefox выключен : нажмите F12, затем выключите Firebug для этой страницы - маленькую кнопку в правом верхнем углу.

CoperNick
источник
Да, это сделало это для меня Спасибо!
MadeInDreams
Спасибо, это сводило меня с ума. Странная ошибка
Стивен Симпсон
6

На самом деле есть две отдельные проблемы, которые могут вызвать проблему мерцания, и вы можете столкнуться с одной или обеими из них.

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

Эта проблема решена, как описано во многих ответах на этой странице, чтобы убедиться, что AngularJS загружен в голову. Смотрите документ ngCloak :

Для достижения наилучшего результата скрипт angular.js должен быть загружен в раздел head файла 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 или также.

Важное примечание: Обязательно наносите растворы на оба нг-плаща, которые наносятся слишком поздно и удаляются в ближайшее время. Решение только одной из этих проблем может не облегчить симптомы.

Эндрю Даунс
источник
1
это исправило это для меня "скрипт должен быть загружен в главном разделе"
aliopi
4

Мы столкнулись с этой проблемой в нашей компании и решили ее, добавив «display: none» в стиль CSS для тех мерцающих элементов ng-show. Нам не нужно было использовать нг-плащ вообще. В отличие от других в этой теме, мы сталкивались с этой проблемой в Safari, но не в Firefox или Chrome - возможно, из-за ленивой ошибки перерисовки Safari в iOS7 .

Джейк МакГвайр
источник
3

Для чего это стоит, у меня была похожая проблема нг-плащ не работает. Возможно, стоит проверить ваше приложение / сайт с включенным кэшем, чтобы повторно использовать исходные файлы, чтобы выяснить, помогает ли это.

При запуске с мерцанием я тестировал с открытым DevTools и отключенным кешем. Закрытие панели с включенным кэшированием исправило мою проблему.

mrdazm
источник
3

Хранение приведенных ниже утверждений в заголовке тега исправило эту проблему

<style type="text/css">
    [ng\:cloak], [ng-cloak], [data-ng-cloak], [x-ng-cloak], .ng-cloak, .x-ng-cloak {
    display: none !important;
}
</style>

официальная документация

Сайкиран К
источник
3

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

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

Затем в вашем контроллере добавьте это вверху или около него:

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

Таким образом, элемент изначально скрыт и отображается только тогда, когда код контроллера действительно запущен.

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

shawkinaw
источник
2

Лучше использовать ng-ifвместо ng-show. ng-if полностью удаляет и воссоздает элемент в DOM и помогает избежать мигания ng-шоу.

алексей
источник
но он также уничтожает все работающие плагины в этой части домена ... (например, jquery ui)
Geert Bellemans
2

Я использую ионные рамки, добавление стиля CSS может не работать в определенных обстоятельствах, вы можете попробовать использовать ng-if вместо ng-show / ng-hide

ref: 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=8hNiWx26ek&h_x_x&i_x_d&i_x_d_x_d_x_d_d_x_d_v_d_v_d_v_d_v_d_v_d_v_d_v_d_d_v_k = OnePage & д = нг-шоу% 20hide% 20flickering% 20in% 20ios & F = ложь

d1ck50n
источник
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>
java25
источник
1

В дополнение к другим ответам, если вы обнаружите, что вспышка кода шаблона все еще происходит, вероятно, ваши скрипты находятся внизу страницы, а это означает, что директива ng-cloak прямо вверх не будет работать. Вы можете переместить свои сценарии в голову или создать правило CSS.

В документации сказано: «Для достижения наилучшего результата скрипт angular.js должен быть загружен в раздел head документа 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;"к основному контенту div, а затем используя jQuery (я уже использовал его на странице), $('#main-div-id').show();когда все было загружено после получения данных с сервера;

Hipnosis
источник
Я обнаружил, что это единственное решение, которое работает для меня, но я хотел избежать использования JQuery, поэтому нашел альтернативу. Смотрите мой ответ здесь: stackoverflow.com/a/42527700/4214694
Эндрю Даунс
1

На самом деле я обнаружил, что предложение из веб-журнала Рика Страла отлично исправило мою проблему (поскольку у меня все еще была странная проблема с нг-плащом, мигавшим raw {{code}} время от времени, особенно во время работы Firebug):

Ядерный вариант: скрытие контента вручную

Использование явного CSS - лучший выбор, поэтому в следующем не должно быть необходимости. Но я упомяну это здесь, так как это дает некоторое представление о том, как вы можете скрыть / показать контент вручную при загрузке для других платформ или в ваших собственных шаблонах на основе разметки.

Прежде чем я понял, что могу явно встроить стиль CSS в страницу, я попытался выяснить, почему ng-cloak не выполняет свою работу. Потратив час на то, чтобы никуда не деваться, я наконец решил просто вручную спрятать и показать контейнер. Идея проста - сначала спрячьте контейнер, затем покажите его, как только Angular выполнит первоначальную обработку и удалит разметку шаблона со страницы.

Вы можете вручную скрыть содержимое и сделать его видимым после того, как Angular получит контроль. Для этого я использовал:

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

Обратите внимание на отображение: ни один из стилей, который явно скрывает элемент изначально на странице.

Затем, как только Angular запустит свою инициализацию и эффективно обработает разметку шаблона на странице, вы сможете показать содержимое. Для Angular это событие 'ready' является функцией app.run ():

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

Это эффективно удаляет отображение: стиль отсутствует, а содержимое отображается. К моменту запуска app.run () DOM готов к отображению с заполненными данными или, по крайней мере, с пустыми данными - Angular уже получил контроль.

Campbeln
источник
Я обнаружил, что это единственное решение, которое работает для меня, но я хотел избежать использования JQuery, поэтому нашел альтернативу. Смотрите мой ответ здесь: stackoverflow.com/a/42527700/4214694
Эндрю Даунс
1

Я перепробовал все ответы выше и ничего не получалось. Использовал ionic для разработки гибридного приложения и пытался заставить сообщение об ошибке не мерцать. Я решил проблему, добавив класс ng-hide к своему элементу. У моего div уже есть ng-show, чтобы показать элемент при возникновении ошибки. При добавлении ng-hide установите div, чтобы он не отображался до загрузки angular. Никакой нг-плащ или добавление углов на голову не требуется.

gyleg5
источник
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

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

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

По сути, когда в этом случае запускается scope.watch, AngularJS отслеживает изменения в переменной name (model.value)

D.Adelakun
источник
0

Я бы завернула <ul>с собой<div ng-cloak>

Дэн Дойон
источник
2
Ему не нужно оборачивать <ul>. ng-cloakбудет скрывать любой элемент, к которому он применяется, а также потомков этого элемента.
Btford
0

Я лично решил использовать ng-classатрибут, а неng-show . Я добился гораздо большего успеха, пройдя этот путь, особенно для всплывающих окон, которые всегда не показываются по умолчанию.

Что раньше было <div class="options-modal" ng-show="showOptions"></div>

сейчас: <div class="options-modal" ng-class="{'show': isPrintModalShown}">

с CSS для опционального модального класса display: noneпо умолчанию. Класс show содержит 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';">
Espigah
источник