Lit — это лёгкий и производительный фреймворк для создания веб-компонентов на основе стандартов Web Components. Он предоставляет удобные инструменты для реактивного обновления интерфейса, шаблонов и управления состоянием компонентов. Одной из интересных возможностей современного веба является работа с файловой системой через File System Access API, которое позволяет веб-приложениям читать и записывать файлы на локальном устройстве пользователя с его явного разрешения.
Для начала работы с Lit необходимо установить пакет:
import { LitElement, html, css } from 'lit';
Создание простого компонента:
class FileEditor extends LitElement {
static properties = {
fileContent: { type: String }
};
constructor() {
super();
this.fileContent = '';
}
render() {
return html`
<textarea .value=${this.fileContent} @input=${this.updateContent}></textarea>
<button @click=${this.openFile}>Открыть файл</button>
<button @click=${this.saveFile}>Сохранить файл</button>
`;
}
updateContent(event) {
this.fileContent = event.target.value;
}
}
customElements.define('file-editor', FileEditor);
File System Access API предоставляет два основных
интерфейса: FileSystemFileHandle для работы с отдельными
файлами и FileSystemDirectoryHandle для работы с папками.
Доступ к ним осуществляется через вызовы
window.showOpenFilePicker() или
window.showSaveFilePicker().
async openFile() {
try {
const [fileHandle] = await window.showOpenFilePicker({
types: [
{
description: 'Текстовые файлы',
accept: { 'text/plain': ['.txt'] }
}
]
});
const file = await fileHandle.getFile();
this.fileContent = await file.text();
} catch (err) {
console.error('Ошибка при открытии файла:', err);
}
}
Ключевые моменты:
showOpenFilePicker возвращает массив, даже если выбран
только один файл.fileHandle.getFile() возвращает объект
File, из которого можно прочитать содержимое через
text() или arrayBuffer().async saveFile() {
try {
const fileHandle = await window.showSaveFilePicker({
suggestedName: 'document.txt',
types: [
{
description: 'Текстовые файлы',
accept: { 'text/plain': ['.txt'] }
}
]
});
const writable = await fileHandle.createWritable();
await writable.write(this.fileContent);
await writable.close();
} catch (err) {
console.error('Ошибка при сохранении файла:', err);
}
}
Особенности:
createWritable() возвращает объект для записи
данных.close() для фиксации
изменений.showSaveFilePicker позволяет указать рекомендуемое имя
файла и типы файлов.Lit автоматически обновляет DOM при изменении реактивных свойств,
таких как fileContent. Это позволяет создавать полноценные
редакторы, где изменение текста в textarea синхронно
отображается в состоянии компонента и может быть сохранено на диск.
Пример расширения функциональности:
class FileEditor extends LitElement {
static properties = {
fileContent: { type: String },
fileName: { type: String }
};
constructor() {
super();
this.fileContent = '';
this.fileName = '';
}
render() {
return html`
<h3>${this.fileName || 'Новый файл'}</h3>
<textarea .value=${this.fileContent} @input=${this.updateContent}></textarea>
<div>
<button @click=${this.openFile}>Открыть</button>
<button @click=${this.saveFile}>Сохранить</button>
</div>
`;
}
updateContent(event) {
this.fileContent = event.target.value;
}
async openFile() {
try {
const [fileHandle] = await window.showOpenFilePicker();
const file = await fileHandle.getFile();
this.fileContent = await file.text();
this.fileName = file.name;
} catch (err) {
console.error(err);
}
}
async saveFile() {
try {
const fileHandle = await window.showSaveFilePicker({
suggestedName: this.fileName || 'document.txt'
});
const writable = await fileHandle.createWritable();
await writable.write(this.fileContent);
await writable.close();
this.fileName = fileHandle.name;
} catch (err) {
console.error(err);
}
}
}
customElements.define('file-editor', FileEditor);
showOpenFilePicker({ multiple: true }) возвращает массив
файловых дескрипторов.window.showDirectoryPicker() позволяет получить доступ к
папкам и их содержимому, читать и создавать файлы внутри
директории.queryPermission() и
requestPermission().Для больших файлов рекомендуется использовать потоковую запись через
writable.write() с Blob частями, чтобы
избежать блокировки интерфейса.
const chunk = new Blob([this.fileContent.slice(0, 1024)]);
await writable.write(chunk);
Lit обеспечивает плавное обновление интерфейса, что позволяет безопасно использовать File System Access API даже при работе с большими текстами или бинарными данными.