Home » Как изменять атрибуты, классы и стили в DOM
Как изменять атрибуты, классы и стили в DOM

Как изменять атрибуты, классы и стили в DOM

Если ты фулстек-разработчик или системный администратор, который в свободное время пилит веб-интерфейсы для мониторинга серверов, то работа с DOM — это твой хлеб насущный. Манипуляции с атрибутами, классами и стилями в JavaScript позволяют создавать динамичные дашборды, настраивать кастомные админки и делать интерфейсы, которые реагируют на состояние твоей инфраструктуры в реальном времени. Эта статья — твой практический гайд по всем основным способам изменения DOM-элементов, с примерами кода, которые можно сразу запустить на своём VPS или выделенном сервере.

Как это работает: основы манипуляций с DOM

DOM (Document Object Model) — это программный интерфейс для HTML-документов. Каждый элемент на странице — это объект со свойствами и методами. Когда ты меняешь атрибуты, классы или стили, браузер мгновенно перерисовывает страницу.

Основные способы доступа к элементам:

// Поиск элементов
const element = document.getElementById('server-status');
const elements = document.getElementsByClassName('warning');
const queryElement = document.querySelector('.cpu-usage');
const queryElements = document.querySelectorAll('div[data-server]');

Работа с атрибутами, классами и стилями осуществляется через различные API:

  • Атрибуты: setAttribute(), getAttribute(), removeAttribute()
  • Классы: className, classList (add, remove, toggle, contains)
  • Стили: style.property, cssText, getComputedStyle()

Работа с атрибутами: пошаговое руководство

Атрибуты — это свойства HTML-элементов. Для админских интерфейсов часто используются data-атрибуты для хранения информации о серверах:

// Установка атрибутов
element.setAttribute('data-server-id', '12345');
element.setAttribute('title', 'CPU: 85%, RAM: 12GB');

// Получение атрибутов
const serverId = element.getAttribute('data-server-id');
const hasAttribute = element.hasAttribute('data-online');

// Удаление атрибутов
element.removeAttribute('data-temp');

// Работа с boolean атрибутами
element.disabled = true;
element.checked = false;

Практический пример для мониторинга серверов:

function updateServerStatus(serverId, isOnline) {
    const serverElement = document.querySelector(`[data-server-id="${serverId}"]`);
    
    if (isOnline) {
        serverElement.setAttribute('data-status', 'online');
        serverElement.setAttribute('title', 'Server is online');
    } else {
        serverElement.setAttribute('data-status', 'offline');
        serverElement.setAttribute('title', 'Server is offline');
    }
}

Манипуляции с классами: элегантно и эффективно

Классы — это основной способ стилизации элементов и индикации состояний. Современный подход — использовать classList API:

// Добавление классов
element.classList.add('active');
element.classList.add('server-online', 'high-load');

// Удаление классов
element.classList.remove('server-offline');

// Переключение классов
element.classList.toggle('collapsed');

// Проверка наличия класса
if (element.classList.contains('critical')) {
    // Критическое состояние сервера
}

// Замена класса
element.classList.replace('warning', 'critical');

Сравнение старого и нового подходов:

Старый способ (className) Новый способ (classList) Преимущества
element.className += ‘ active’ element.classList.add(‘active’) Нет проблем с пробелами
element.className = element.className.replace(‘active’, ”) element.classList.remove(‘active’) Простота и читаемость
element.className.indexOf(‘active’) !== -1 element.classList.contains(‘active’) Булевый результат

Пример системы индикации состояния серверов:

class ServerMonitor {
    constructor() {
        this.statusClasses = {
            online: 'status-online',
            offline: 'status-offline',
            warning: 'status-warning',
            critical: 'status-critical'
        };
    }
    
    updateServerStatus(serverId, status) {
        const element = document.querySelector(`#server-${serverId}`);
        
        // Очищаем все статусы
        Object.values(this.statusClasses).forEach(cls => {
            element.classList.remove(cls);
        });
        
        // Добавляем новый статус
        element.classList.add(this.statusClasses[status]);
        
        // Добавляем анимацию при изменении
        element.classList.add('status-changed');
        setTimeout(() => element.classList.remove('status-changed'), 300);
    }
}

Управление стилями: от простого к сложному

Стили можно изменять напрямую через JavaScript. Это мощный инструмент для создания динамичных интерфейсов:

// Изменение отдельных стилей
element.style.backgroundColor = '#ff0000';
element.style.fontSize = '16px';
element.style.display = 'none';

// Изменение нескольких стилей через cssText
element.style.cssText = 'color: red; font-size: 14px; margin: 10px;';

// Получение вычисленных стилей
const computedStyle = window.getComputedStyle(element);
const actualColor = computedStyle.color;
const actualMargin = computedStyle.marginTop;

Продвинутый пример с анимацией загрузки CPU:

function animateCPUUsage(element, targetPercent) {
    const startPercent = parseInt(element.style.width) || 0;
    const duration = 1000; // 1 секунда
    const startTime = performance.now();
    
    function animate(currentTime) {
        const elapsed = currentTime - startTime;
        const progress = Math.min(elapsed / duration, 1);
        
        const currentPercent = startPercent + (targetPercent - startPercent) * progress;
        
        element.style.width = `${currentPercent}%`;
        
        // Цвет зависит от загрузки
        if (currentPercent < 50) {
            element.style.backgroundColor = '#4CAF50'; // зеленый
        } else if (currentPercent < 80) {
            element.style.backgroundColor = '#FF9800'; // оранжевый
        } else {
            element.style.backgroundColor = '#F44336'; // красный
        }
        
        if (progress < 1) {
            requestAnimationFrame(animate);
        }
    }
    
    requestAnimationFrame(animate);
}

Положительные и отрицательные практики

✅ Хорошие практики:

  • Используй classList вместо className для работы с классами
  • Кеширuj DOM-элементы в переменных, если обращаешься к ним многократно
  • Используй CSS-классы для сложных стилей вместо inline-стилей
  • Группируй изменения DOM для минимизации reflow/repaint

❌ Антиpaттерны:

  • Не делай многократные поиски одного элемента
  • Избегай прямого изменения style для сложных стилей
  • Не забывай про производительность при массовых операциях
Проблема Плохо Хорошо
Многократный поиск document.querySelector('#el').style.color = 'red';
document.querySelector('#el').style.fontSize = '14px';
const el = document.querySelector('#el');
el.style.color = 'red';
el.style.fontSize = '14px';
Сложные стили element.style.cssText = 'много стилей...'; element.classList.add('prepared-class');

Автоматизация и скрипты для серверного мониторинга

Вот реальный пример скрипта для мониторинга серверов, который обновляет интерфейс в реальном времени:

class ServerDashboard {
    constructor() {
        this.wsConnection = null;
        this.servers = new Map();
        this.init();
    }
    
    init() {
        this.connectWebSocket();
        this.setupEventListeners();
    }
    
    connectWebSocket() {
        this.wsConnection = new WebSocket('ws://localhost:8080/monitoring');
        
        this.wsConnection.onmessage = (event) => {
            const data = JSON.parse(event.data);
            this.updateServerDisplay(data);
        };
    }
    
    updateServerDisplay(serverData) {
        const { serverId, cpu, memory, disk, status } = serverData;
        const serverElement = document.querySelector(`#server-${serverId}`);
        
        if (!serverElement) return;
        
        // Обновляем прогресс-бары
        this.updateProgressBar(serverElement.querySelector('.cpu-bar'), cpu);
        this.updateProgressBar(serverElement.querySelector('.memory-bar'), memory);
        this.updateProgressBar(serverElement.querySelector('.disk-bar'), disk);
        
        // Обновляем статус
        this.updateServerStatus(serverElement, status);
        
        // Обновляем атрибуты для последующей обработки
        serverElement.setAttribute('data-last-update', Date.now());
        serverElement.setAttribute('data-cpu', cpu);
        serverElement.setAttribute('data-memory', memory);
    }
    
    updateProgressBar(barElement, percentage) {
        const progressFill = barElement.querySelector('.progress-fill');
        
        // Анимированное изменение ширины
        progressFill.style.transition = 'width 0.3s ease';
        progressFill.style.width = `${percentage}%`;
        
        // Изменение цвета в зависимости от значения
        progressFill.classList.remove('low', 'medium', 'high', 'critical');
        
        if (percentage < 50) {
            progressFill.classList.add('low');
        } else if (percentage < 75) {
            progressFill.classList.add('medium');
        } else if (percentage < 90) {
            progressFill.classList.add('high');
        } else {
            progressFill.classList.add('critical');
        }
        
        // Обновляем текст
        barElement.querySelector('.percentage-text').textContent = `${percentage}%`;
    }
    
    updateServerStatus(serverElement, status) {
        const statusIndicator = serverElement.querySelector('.status-indicator');
        
        // Очищаем предыдущие классы статуса
        statusIndicator.classList.remove('online', 'offline', 'warning', 'maintenance');
        
        // Добавляем новый статус
        statusIndicator.classList.add(status);
        
        // Обновляем атрибуты
        statusIndicator.setAttribute('data-status', status);
        statusIndicator.setAttribute('title', `Server is ${status}`);
        
        // Добавляем пульсацию для критических состояний
        if (status === 'offline' || status === 'critical') {
            statusIndicator.classList.add('pulse');
        } else {
            statusIndicator.classList.remove('pulse');
        }
    }
}

// Инициализация при загрузке страницы
document.addEventListener('DOMContentLoaded', () => {
    new ServerDashboard();
});

Альтернативные решения и библиотеки

Хотя нативный JavaScript мощен, существуют библиотеки, которые упрощают работу с DOM:

  • jQuery — классика, но уже устарела для современных проектов
  • Alpine.js — легковесная альтернатива для простых интерактивных элементов
  • Stimulus — минималистичный фреймворк от создателей Ruby on Rails
  • Lit — современная библиотека для создания веб-компонентов

Пример с Alpine.js для простого переключения состояний:

<div x-data="{ serverStatus: 'online' }">
    <div :class="'server-' + serverStatus" 
         :data-status="serverStatus"
         @click="serverStatus = serverStatus === 'online' ? 'offline' : 'online'">
        Server Status: <span x-text="serverStatus"></span>
    </div>
</div>

Производительность и оптимизация

При работе с большим количеством элементов важно учитывать производительность:

// Плохо: множественные reflow/repaint
for (let i = 0; i < 1000; i++) {
    const element = document.getElementById(`server-${i}`);
    element.style.display = 'block';
    element.style.backgroundColor = 'red';
}

// Хорошо: пакетное обновление
const fragment = document.createDocumentFragment();
for (let i = 0; i < 1000; i++) {
    const element = document.getElementById(`server-${i}`);
    element.style.cssText = 'display: block; background-color: red;';
}

// Еще лучше: используй requestAnimationFrame для больших операций
function batchUpdate(elements, callback) {
    let index = 0;
    const batchSize = 10;
    
    function processBatch() {
        const endIndex = Math.min(index + batchSize, elements.length);
        
        for (let i = index; i < endIndex; i++) {
            callback(elements[i], i);
        }
        
        index = endIndex;
        
        if (index < elements.length) {
            requestAnimationFrame(processBatch);
        }
    }
    
    requestAnimationFrame(processBatch);
}

Интеграция с современными инструментами

Для продвинутых сценариев можно интегрировать DOM-манипуляции с другими инструментами:

  • Web Components — создание переиспользуемых компонентов
  • Intersection Observer — отслеживание видимости элементов
  • Mutation Observer — отслеживание изменений DOM
  • CSS Custom Properties — динамическое изменение CSS-переменных

Пример с CSS Custom Properties:

// Динамическое изменение цветовой темы
function setTheme(isDark) {
    const root = document.documentElement;
    
    if (isDark) {
        root.style.setProperty('--primary-color', '#333');
        root.style.setProperty('--background-color', '#1a1a1a');
        root.style.setProperty('--text-color', '#fff');
    } else {
        root.style.setProperty('--primary-color', '#007bff');
        root.style.setProperty('--background-color', '#fff');
        root.style.setProperty('--text-color', '#333');
    }
    
    // Сохраняем настройку
    localStorage.setItem('theme', isDark ? 'dark' : 'light');
}

Заключение и рекомендации

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

Ключевые выводы:

  • Используй современные API: classList, setAttribute, querySelector
  • Кеширuj DOM-элементы для повышения производительности
  • Предпочитай CSS-классы inline-стилям для сложной стилизации
  • Группируй изменения DOM для минимизации reflow/repaint
  • Используй requestAnimationFrame для тяжелых операций

Когда использовать:

  • Создание дашбордов мониторинга серверов
  • Разработка админских интерфейсов
  • Построение интерактивных форм конфигурации
  • Реализация real-time обновлений статуса системы

Помни: хороший код — это не только работающий код, но и код, который легко поддерживать. Используй семантичные имена классов, комментируй сложную логику и всегда тестируй на разных устройствах и браузерах. Если планируешь деплоить свои решения, обязательно протестируй их на своём VPS или выделенном сервере в продакшен-окружении.


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

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

Leave a reply

Your email address will not be published. Required fields are marked