DevGang
Авторизоваться

Как управлять DOM на чистом JavaScript?

Управление DOM с помощью JavaScript в современных браузерах и IE 11+

Добавить или удалить класс из элемента Разрешить ввод только определенных символов Добавить к элементу Подписаться на событие Вычислить положение мыши относительно элемента Рассчитать размер полосы прокрутки Изменить favicon Проверить элемент по селектору Проверка наличия класса у элемента Проверьте, является ли элемент потомком другого Проверьте, находится ли элемент в области просмотра Проверка, является ли элемент прокручиваемым Проверка, поддерживается ли ввод даты Клонировать элемент Связь между iframe и его родительским окном Скопировать текст в буфер обмена Подсчитайте количество символов текстовой области Создать элемент Создать слайдер сравнения изображений Создать одноразовый обработчик событий Создание изменяемых размеров разделенных видов Обнаружение кликов за пределами элемента Определить, находится ли элемент в фокусе Определите, включен ли caps-lock Как определить Mac OS браузер Определить высоту и ширину элемента Определение левый и правый клик мыши Скачать файл Перетаскивание элементов в списоке Перетаскивание столбецов таблицы Перетаскивание строки таблицы Выполнить код, когда документ готов Экспорт таблицы в CSV Получить CSS-стили элемента Получить или установить заголовок документа Получить или установить HTML-элемент Получить, установить и удалить атрибуты Получить установить и удалить атрибуты data Получить братьев и сестер элемента Получить размер выбранного файла Получить ближайший элемент по данному селектору Получить значение по умолчанию для свойства css Получиту высоту и ширину документа Получить первый прокручиваемый родительский элемент Получить родительский элемент Получить положение элемента относительно другого Получить позицию элемента относительно документа Получить размер изображения Получить текстовое содержимое элемента Вернуться на предыдущую страницу Выделите элемент при перетаскивании файла поверх него Вставить элемент после или перед другим элементом Вставить данный HTML после или перед элементом Загрузить файл CSS динамически Загрузить файл JavaScript динамически Цикл по нодлисту Сделать изменяемый размер элемента Вставить изображение из буфера обмена Placeholder для contenteditable Нажмите Shift и введите новую строку Предварительный просмотр изображения перед его загрузкой Поместить курсор в конец ввода Перенаправить на другую страницу Перезагрузить текущую страницу Удалить все дочерние узлы Удалить элемент Заменить элемент Заменить элемент Заменить сломанные изображения Измените размер фрейма, чтобы он соответствовал его содержанию Изменить размер изображения Изменить размер столбцов таблицы Измените ширину текстового поля, чтобы оно автоматически соответствовало его содержимому Масштабировать текст, чтобы он поместился внутри элемента Прокрутить до верхней части страницы Выберите элемент или список элементов Выберите дочерние элементы Сериализация данных формы в строку запроса Показывать фальшивый элемент при перетаскивании элемента Сортировка таблицы, нажав на ее заголовки Поменять местами два узла Скрыть / показать элемент Переключить видимость пароля Запустить событие Развернуть элемент Загрузить файлы с помощью AJAX Обернуть элемент вокруг данного элемента

Предположим, что мы хотим отсортировать любой столбец следующей таблицы:

<table id="sortMe" class="table">
    ...
</table>

Сортировать строки

Прежде всего, мы получим все заголовки, обойдем их в циклу и добавим обработчик события для события click к каждому из них:

// Query the table
const table = document.getElementById('sortMe');

// Query the headers
const headers = table.querySelectorAll('th');

// Loop over the headers
[].forEach.call(headers, function(header, index) {
    header.addEventListener('click', function() {
        // This function will sort the column
        sortColumn(index);
    });
});

Функция sortColumn(index) упомянутая выше будет сортировать все строки от данного столбца index.

Для этого:

  • Мы можем использовать метод Array.sort() для сортировки текущих строк
  • Затем удалите все текущие строки
  • И добавить отсортированные строки
// Query all rows
const tableBody = table.querySelector('tbody');
const rows = tableBody.querySelectorAll('tr');

const sortColumn = function(index) {
    // Clone the rows
    const newRows = Array.from(rows);

    // Sort rows by the content of cells
    newRows.sort(function(rowA, rowB) {
        // Get the content of cells
        const cellA = rowA.querySelectorAll('td')[index].innerHTML;
        const cellB = rowB.querySelectorAll('td')[index].innerHTML;

        switch (true) {
            case cellA > cellB: return 1;
            case cellA < cellB: return -1;
            case cellA === cellB: return 0;
        }
    });

    // Remove old rows
    [].forEach.call(rows, function(row) {
        tableBody.removeChild(row);
    });

    // Append new row
    newRows.forEach(function(newRow) {
        tableBody.appendChild(newRow);
    });
};

Как видите, массив предоставляет встроенный метод sort, который принимает функцию для сравнения двух элементов. В нашем случае две ячейки столбца сравниваются на основе его HTML-содержимого:

newRows.sort(function(rowA, rowB) {
    // Get the content of cells
    const cellA = rowA.querySelectorAll('td')[index].innerHTML;
    const cellB = rowB.querySelectorAll('td')[index].innerHTML;

    ...
});

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

Поддержка других типов

Мы добавляем пользовательский атрибут к каждому заголовку, чтобы указать тип его ячеек:

<thead>
    <tr>
        <th data-type="number">No.</th>
        <th>First name</th>
        <th>Last name</th>
    </tr>
</thead>

Например, столбец № будет иметь атрибут data-type="number". Если атрибут отсутствует, типы содержимого ячеек являются строковыми. Нам нужна функция для преобразования содержимого ячеек из строки в другой тип:

// Transform the content of given cell in given column
const transform = function(index, content) {
    // Get the data type of column
    const type = headers[index].getAttribute('data-type');
    switch (type) {
        case 'number':
            return parseFloat(content);
        case 'string':
        default:
            return content;
    }
};

Пример кода демонстрирует number и string столбцы, но вы можете поддерживать больше типов, такие как дата.

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

newRows.sort(function(rowA, rowB) {
    const cellA = rowA.querySelectorAll('td')[index].innerHTML;
    const cellB = rowB.querySelectorAll('td')[index].innerHTML;

    // Transform the content of cells
    const a = transform(index, cellA);
    const b = transform(index, cellB);    

    // And compare them
    switch (true) {
        case a > b: return 1;
        case a < b: return -1;
        case a === b: return 0;
    }
});

Поддержите оба направления

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

// Track sort directions
const directions = Array.from(headers).map(function(header) {
    return '';
});

directions является массивом, в котором каждый элемент может быть asc или desc указывать направление сортировки в ассоциированном столбце.

Функция sortColumn() в настоящее время включает больше логики для сравнения двух строк на основе текущего направления:

const sortColumn = function(index) {
    // Get the current direction
    const direction = directions[index] || 'asc';

    // A factor based on the direction
    const multiplier = (direction === 'asc') ? 1 : -1;

    ...

    newRows.sort(function(rowA, rowB) {
        const cellA = rowA.querySelectorAll('td')[index].innerHTML;
        const cellB = rowB.querySelectorAll('td')[index].innerHTML;

        const a = transform(index, cellA);
        const b = transform(index, cellB);    

        switch (true) {
            case a > b: return 1 * multiplier;
            case a < b: return -1 * multiplier;
            case a === b: return 0;
        }
    });

    ...

    // Reverse the direction
    directions[index] = direction === 'asc' ? 'desc' : 'asc';

    ...
};
Комментарии
Чтобы оставить комментарий, необходимо авторизоваться