#javascript #angular #typescript
#javascript #угловой #typescript
Вопрос:
У меня возникли проблемы с проверкой активного состояния атрибута элемента. Я попробовал ниже, но он вернул false, даже если элемент имеет атрибут в активном состоянии — ( .c-banner.active
присутствует)
ngAfterViewInit() {
const bannerElm = document.getElementById("banner");
const isActive = bannerElm amp;amp; bannerElm.getAttribute("class")
.indexOf("c-banner.active") !== -1; // returned false
}
Комментарии:
1. Итак, каково значение
bannerElm.getAttribute("class")
?2.
.getAttribute("class")
собирается вернуть атрибут class точно таким, какое значение вы видите в DOM, так почему вы ищетеc-banner.active
с точкой и без пробела, как в css-селекторе?3. он вернул «c-banner». и да, @BenSewards, вы правы, он вернул значение точно таким, как есть. Однако прикрепленным атрибутом является .c-banner.active, поэтому мой вопрос заключается в том, как мне проверить, был ли применен CSS-стиль .active state. Спасибо.
4. Я вижу много ответов о том, как правильно получить доступ к классу / classList . Предположительно, значение атрибута class при проверке в перехватчике жизненного цикла ngAfterViewInit равно
c-banner
. Возможно, элемент находится не в ожидаемом состоянии из-за операции, которая является асинхронной по своей природе? Как установить активное состояние баннера? можете ли вы попытаться получить класс элемента по истечении времени ожидания? (только для целей отладки)5. @JanWendland Настройка времени в сочетании с classList.contains сработала для меня!! Спасибо вам, ребята!
Ответ №1:
Почему вы не используете classList и contains?
classList
. contains();
ngAfterViewInit() {
const bannerElm = document.getElementById("banner");
const isActive = bannerElm amp;amp; bannerElm.classList.contains('c-banner') amp;amp; bannerElm.classList.contains('active');
}
Комментарии:
1. @user11151040 Приведенный вами пример кода был неправильным. Это должен быть .classList.contains(). Несмотря на то, что вы были быстрее, но я выбираю другой ответ. К вашему сведению, вы всегда можете нажать «Редактировать» и повторно подтвердить ответ.
2. @displayname да, вы правы. После упоминания объяснения я забыл, как добавить его в содержимое, это очень забавно 🙂 Теперь отредактировал его.
Ответ №2:
Вы можете использовать classList.contains
метод, чтобы проверить, имеет ли элемент класс active.
ngAfterViewInit() {
setTimeout(() => {
const isActive = bannerElm amp;amp;
bannerElm.classList.contains('c-banner') amp;amp;
bannerElm.classList.contains('active');
}, 1000);
}
[ОБНОВЛЕНО] оберните его в setTimeout(), и это сработало! На случай, если у кого-то еще возникла проблема с заказами инициализации компонента, с которой я сталкивался ранее.
Комментарии:
1. @user11151040 довел тебя до этого 🙂
2. @benshabatnoam да, но в целом это содержит трудозатраты 🙂
Ответ №3:
Помимо того, что это наилучший способ фактического доступа к значению атрибута класса, судя по вашим комментариям, проблема, по-видимому, носит асинхронный характер. Чтобы избежать использования хакерского setTimeout
решения, я бы рекомендовал применить mutation observer и соответствующим образом реагировать на изменения атрибута. Вот один из способов, как это сделать.
PS: Отредактировал ответ, чтобы сделать его более подходящим для того, чего вы пытаетесь достичь. В конце концов, это не будет иметь большого значения, кроме того, что в случае изменения состояния баннера до истечения времени отмены, объект будет отправлен сразу, и вы потенциально сэкономите некоторое время ожидания по сравнению с использованием setTimeout
bannerIsActive$ = new BehaviorSubject<boolean>(false);
ngAfterViewInit() {
const banner = document.getElementById('banner');
const observer = new MutationObserver((mutations: MutationRecord[]) => {
const mutation = mutations[0];
const classList: DOMTokenList = mutation.target['classList'];
this.bannerIsActive$.next(mutation.attributeName === 'class' amp;amp; classList.contains('active'));
});
observer.observe(banner, {
attributes: true
});
this.bannerIsActive$.pipe(
debounce(isActive => timer(isActive ? 0 : 1000)),
take(1)
).subscribe(isActive => {
// do something with the banner state
});
}
Комментарии:
1. @janwedland отлично! Вопрос. Что, если я хочу получить состояние только один раз и игнорировать изменение состояния? Я думал о subscribe и onsubscribe, но, возможно, есть лучшее решение!
2. Я бы сказал, это зависит от того, что вы пытаетесь сделать с состоянием. Используете ли вы состояние в своем шаблоне компонента? В этом случае вы могли бы просто инициализировать его с помощью false в вашем компоненте и попросить обратный вызов прослушивателя мутаций обновить его в случае, если баннер установлен активным.
3. Если сценарий немного сложнее, и вы хотите, например, сделать какой-то запрос на основе состояния баннера, вы могли бы создать BehaviourSubject в своем компоненте, инициализировать его с помощью false, подписаться на него со временем отмены, которое вам кажется разумным для выполнения асинхронной операции, и вызвать следующий метод субъекта из наблюдателя мутации. Затем вы можете подписаться на него, и независимо от того, изменилось состояние баннера или нет, вы получите текущее состояние баннера по истечении времени отмены. Но, может быть, вы можете подробнее рассказать о том, чего вы пытаетесь достичь? @displayname
4. @displayname отредактировал этот подход в моем ответе.
5. Я попробовал это, но это не зафиксировало активное состояние.
Ответ №4:
вам следует работать с ViewChild, а не обращаться к вашему DOM напрямую. оба будут работать, но это строгий способ сделать это.
@ViewChild('banner') input;
ngAfterViewInit() {
var classAttributes= this.input.nativeElement.getAttribute('class');
var result=classAttributesamp;amp;classAttributes('c-banner')
}