Таблицы Excel стали неотъемлемой частью современных вычислительных технологий. Они позволяют пользователям организовывать, манипулировать и анализировать данные в табличном формате. Приложения, такие как Google Sheets, установили стандарт для мощных интерактивных таблиц.
В этом блоге мы рассмотрим процесс создания приложения для таблиц с использованием JavaScript. Мы сосредоточимся на основных концепциях программирования, изучим функции JavaScript и предоставим подробные фрагменты кода с объяснениями.
Весь исходный код доступен здесь на моем Codepen.
Что такое Таблицы Google?
Таблицы Google – это веб-приложение, которое позволяет пользователям создавать, редактировать и совместно работать над таблицами онлайн. Оно предоставляет такие функции, как формулы, проверка данных, диаграммы и условное форматирование.
Наш проект эмулирует некоторые основные функции Таблиц Google, сосредотачиваясь на:
- Редактируемых ячейках.
- Анализе и оценке формул.
- Обновлениях в реальном времени через модель Pub/Sub.
- Навигации с клавиатуры и выборе ячеек.
- Динамической оценке зависимостей между ячейками.
Особенности этого проекта
- Редактируемые ячейки: Позволяют пользователям вводить текст или уравнения в ячейки.
- Поддержка формул: Обрабатывает формулы, начинающиеся с
=
и оценивает выражения. - Живые обновления: Изменения в зависимых ячейках вызывают обновления с использованием модели Pub/Sub.
- Навигация с клавиатуры: Позволяет перемещение между ячейками с помощью стрелок.
- Динамическая оценка: Обеспечивает обновление формул в реальном времени, зависящих от других ячеек.
- Обработка ошибок: Предоставляет осмысленные сообщения об ошибках для неверных вводов или круговых зависимостей.
- Масштабируемый дизайн: Позволяет легко расширять для добавления новых строк, столбцов или функций.
Ключевые компоненты приложения
1. Управление режимами
const Mode = {
EDIT: 'edit',
DEFAULT: 'default'
};
Этот перечисляемый тип определяет два режима:
- РЕДАКТИРОВАНИЕ: Позволяет редактировать выбранную ячейку.
- ПО УМОЛЧАНИЮ: Позволяет навигацию и взаимодействие без редактирования.
Зачем использовать режимы?
Режимы упрощают управление состоянием пользовательского интерфейса. Например, в режиме ПО УМОЛЧАНИЮ ввод с клавиатуры перемещает между ячейками, в то время как в режиме РЕДАКТИРОВАНИЕ ввод изменяет содержимое ячейки.
2. Класс Pub/Sub
Модель Pub/Sub обрабатывает подписки и живые обновления. Ячейки могут подписываться на другие ячейки и динамически обновляться при изменении зависимостей.
class PubSub {
constructor() {
this.map = {};
}
get(source) {
let result = [];
let queue = [ (this.map[source] || [])];
while (queue.length) {
let next = queue.shift();
result.push(next.toUpperCase());
if (this.map[next]) queue.unshift(this.map[next]);
}
return result;
}
subscribeAll(sources, destination) {
sources.forEach((source) => {
this.map[source] = this.map[source] || [];
this.map[source].push(destination);
});
}
}
Ключевые функции:
- Динамическое управление зависимостями: Отслеживает зависимости между ячейками.
- Распространение обновлений: Обновляет зависимые ячейки, когда изменяются исходные ячейки.
- Поиск в ширину: Избегает бесконечных циклов, отслеживая все зависимые узлы.
Пример использования:
let ps = new PubSub();
ps.subscribeAll(['A1'], 'B1');
ps.subscribeAll(['B1'], 'C1');
console.log(ps.get('A1')); // Output: ['B1', 'C1']
3. Создание строк и ячеек
class Cell {
constructor(cell, row, col) {
cell.id = `${String.fromCharCode(col + 65)}${row}`;
cell.setAttribute('data-eq', '');
cell.setAttribute('data-value', '');
if (row > 0 && col > -1) cell.classList.add('editable');
cell.textContent = col === -1 ? row : '';
}
}
class Row {
constructor(row, r) {
for (let c = -1; c < 13; c++) {
new Cell(row.insertCell(), r, c);
}
}
}
Основные функции:
- Динамическое создание таблиц: Позволяет программно добавлять строки и столбцы.
- Идентификация ячеек: Генерирует идентификаторы на основе позиции (например, A1, B2).
- Редактируемые ячейки: Ячейки редактируемы только в случае их валидности (не заголовочные строки/столбцы).
Почему использовать динамические строки и ячейки?
Этот подход позволяет масштабировать и изменять размер таблицы, поддерживая функции добавления строк или столбцов без изменения структуры.
4. Обработка событий для взаимодействия
addEventListeners() {
this.table.addEventListener('click', this.onCellClick.bind(this));
this.table.addEventListener('dblclick', this.onCellDoubleClick.bind(this));
window.addEventListener('keydown', this.onKeyDown.bind(this));
}
Основные функции:
- Событие клика: Выбор или редактирование ячеек.
- Событие двойного клика: Позволяет редактировать формулы.
- Событие нажатия клавиши: Поддерживает навигацию стрелками.
5. Анализ и вычисление формул
function calcCell(expression) {
if (!expression) return 0;
return expression.split('+').reduce((sum, term) => {
let value = isNaN(term) ? getCellValue(term) : Number(term);
if (value === null) throw new Error(`Invalid cell: ${term}`);
return sum + Number(value);
}, 0);
}
Основные функции:
- Динамические вычисления: Вычисляет формулы, ссылаясь на другие ячейки.
- Рекурсивная оценка: Разрешает вложенные зависимости.
- Обработка ошибок: Определяет недопустимые ссылки и циклические зависимости.
6. Обработка ошибок для пользовательского ввода
function isValidCell(str) {
let regex = /^[A-Z]{1}[0-9]+$/;
return regex.test(str);
}
Основные функции:
- Проверка: Обеспечивает ввод допустимых идентификаторов ячеек.
- Масштабируемость: Поддерживает динамическое расширение таблицы без нарушения проверки.
Темы JavaScript, рассмотренные
1. Обработка событий
Управляет взаимодействиями, такими как клики и нажатия клавиш.
window.addEventListener('keydown', this.onKeyDown.bind(this));
2. Манипуляция DOM
Создает и изменяет элементы DOM динамически.
let cell = document.createElement('td'); cell.appendChild(document.createTextNode('A1'));
3. Рекурсия
Обрабатывает зависимости динамически.
function calcCell(str) { if (isNaN(str)) { return calcCell(getCellValue(str)); } }
4. Обработка ошибок
Обнаруживает недопустимые ячейки и циклические зависимости.
if (!isValidCell(p)) throw new Error(`invalid cell ${p}`);
Заключение
Этот проект демонстрирует мощную электронную таблицу, используя JavaScript. Он использует обработку событий, рекурсию и шаблоны Pub/Sub, заложив основу для сложных веб-приложений. Расширьте его, добавив функции экспорта данных, графики или правила форматирования.
Ссылки
Source:
https://dzone.com/articles/spreadsheet-application-javascript-guide