В Slim.js состояние компонента определяется реактивными свойствами и наблюдаемыми изменениями данных. Для реализации логики загрузки используется комбинация реактивного состояния и условного рендеринга.
Для отслеживания состояния загрузки необходимо определить свойство компонента, которое будет хранить булево значение:
import { Slim } from 'slim-js';
class LoadingComponent extends Slim {
isLoading = false;
constructor() {
super();
}
startLoading() {
this.isLoading = true;
}
stopLoading() {
this.isLoading = false;
}
template() {
return `
<div>
${this.isLoading ? `<p>Загрузка данных...</p>` : `<p>Данные загружены</p>`}
<button @click="fetchData">Загрузить</button>
</div>
`;
}
fetchData() {
this.startLoading();
fetch('https://api.example.com/data')
.then(response => response.json())
.then(data => {
console.log(data);
this.stopLoading();
})
.catch(() => {
this.stopLoading();
});
}
}
customElements.define('loading-component', LoadingComponent);
Ключевой момент: isLoading
автоматически отслеживается Slim.js, и любое изменение его значения
вызывает обновление шаблона без дополнительного вмешательства.
Slim.js позволяет использовать тернарные выражения внутри шаблона для отображения различных элементов в зависимости от состояния. Это упрощает реализацию индикатора загрузки:
${this.isLoading
? `<div class="spinner"></div>`
: `<div class="content">Контент загружен</div>`}
Можно комбинировать несколько состояний для более сложной логики:
${this.isLoading
? `<div class="spinner">Загрузка...</div>`
: this.error
? `<div class="error">Ошибка загрузки</div>`
: `<div class="content">Данные готовы</div>`}
Для интеграции с API или длительными процессами рекомендуется использовать методы класса для управления состоянием:
isLoading = true.fetch или
async/await.isLoading = false.Пример с использованием async/await:
async fetchData() {
try {
this.startLoading();
const response = await fetch('https://api.example.com/data');
this.data = await response.json();
} catch (err) {
this.error = true;
} finally {
this.stopLoading();
}
}
Важно: finally гарантирует, что
индикатор загрузки будет скрыт независимо от исхода запроса.
Для улучшения UX используются спиннеры, прогресс-бары и анимации. Slim.js не ограничивает стандартные HTML и CSS, поэтому можно интегрировать любые визуальные компоненты:
<style>
.spinner {
border: 4px solid #f3f3f3;
border-top: 4px solid #3498db;
border-radius: 50%;
width: 30px;
height: 30px;
animation: spin 1s linear infinite;
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
</style>
В шаблоне Slim.js это используется как обычный HTML-элемент:
${this.isLoading ? `<div class="spinner"></div>` : `<div>Контент загружен</div>`}
Если компонент выполняет несколько асинхронных операций одновременно, рекомендуется использовать счетчик загрузок вместо булева флага:
loadingCount = 0;
startLoading() {
this.loadingCount++;
}
stopLoading() {
if (this.loadingCount > 0) this.loadingCount--;
}
get isLoading() {
return this.loadingCount > 0;
}
Такой подход предотвращает преждевременное скрытие индикатора при параллельных запросах.
Часто требуется одновременно обрабатывать загрузку и ошибки:
${this.isLoading
? `<p>Загрузка...</p>`
: this.error
? `<p class="error">Ошибка при загрузке данных</p>`
: `<p>Данные успешно загружены</p>`}
Реактивность Slim.js обеспечивает мгновенное обновление UI при смене
состояния isLoading или error.
Хотите, я могу подготовить ещё один блок с примером сложного компонента с прогресс-баром и несколькими параллельными загрузками для Slim.js? Это будет логическое продолжение темы.