Разбираемся с добавлением изображений к статьям с привязкой к базе данных.
Предыдущая статья: Блог на Svelte. Часть 6: Авторство, теги, пагинация и поддержка markdown
Загрузка изображений к статьям
Мы не будем реализовывать возможность добавлять изображения непосредственно посреди текста. В рамках этого гайда упростим себе задачу и сделаем выбор в пользу заглавных картинок без каких-либо иллюстраций в теле постов.
Настройка Supabase
Начать надо с дополнительной настройки базы данных. Дело в том, что мы будем все файлы изображений хранить в Supabase. Можно выбрать и стороннее хранилище, но конкретно в нашем случае Supabase более чем подходит, предоставляя бесплатно аж целый гигабайт под любые медиафайлы. К тому же мы уже умеем работать с этой БД и нам не составит труда адекватно реализовать все необходимые функции без надобности учить новые варианты взаимодействия с информацией.
Сначала открываем Supabase и переходим в раздел Storage. Внутри находим кнопку Create a new bucket и нажимаем на нее. Так создастся отдельное хранилище под файлы.
Назовем это хранилище pictures, так как здесь будут храниться изображения для всего и сразу. Делаем хранилище файлов публичным, переключив тумблер Make bucket public. Затем сохраняем получившийся bucket.
Затем ищем в разделе Storage пункты выдачи прав на управления данными. Все они сопровождаются кнопкой New policy. Жмем на нее.
В появившемся разделе выбираем Create a policy from a template.
Внутри можно выбрать один из шаблонов. Нам нужен тот, что дает право на внесение любых изменений в хранилище файлов. То есть первый вариант. Редактировать его не нужно.
Даже на следующем экране не надо вносить изменений, единственное, что нужно сделать, поставить галочку напротив пункта ALL.
На этом все. Теперь можно делать запросы к хранилищу файлов и не ловить в ответ ошибки из-за нехватки привилегий.
Кнопка добавления новых изображений
Следующий этап – загрузка изображений к статьям. Мы добавим соответствующий интерфейс в блок создания новой статьи. То есть в тот, где мы указываем название, пишем текст и выбираем теги. Поэтому редактировать будем файл NewPost.svelte.
Сначала открываем NewPost.svelte. Потом добавляем переменную file, чтобы хранить в ней элемент, отвечающий за загрузку изображения в браузер.
let file;
После этого создадим функцию загрузки новых изображений и дополним функцию создания поста, чтобы привязать название новой картинки к конкретному посту.
Осталось связать название загруженной картинки с нашей статьей.
Мы слегка модифицируем функцию добавления новых постов, чтобы установить связь между картинкой и статьей.
Теперь в базе данных Posts будет появляться еще и название картинки. По нему мы сможем находить нужное изображение и показывать его читателям. Это не самый элегантный способ, и на этапе рефакторинга мы его заменим на более простой алгоритм, но и такой вариант тоже возможен.
Не забудьте после этого добавить в html-блок input для загрузки файлов с привязкой к соответствующей переменной – <input bind:this={file} type="file" />
Интерфейсы для отображения существующих картинок
Мы научились загружать картинки. Теперь нужно научить сайт корректно подгружать изображение для статей и показывать их пользователю. В первую очередь мы будем генерировать изображение полностью самостоятельно. То есть создавать новый объект и подсоединять его к уже существующему элементу в верстке. Также мы рассмотрим и другой вариант добавления изображения при помощи одной лишь ссылки.
Начнем с отображения картинки в уже открытой статье.
Сначала просто добавляем переменную imageBlock. Это будет div, в котором мы отрисуем изображение из базы данных.
Потом этот div мы добавим в html-разметку:
<div bind:this={imageBlock}></div>
Теперь пишем функцию для добычи изображений из Supabase.
-
Создаем асинхронную функцию getImage: const getImage = async ( ) => { }
-
В тело добавляем запрос ко всему списку изображений (обращаясь к набору pictures, созданному нами в Supabase): const { data } = await supabase.storage.from('pictures').list()
-
Ищем среди изображений имя того, что соответствует названию нашей статьи. Воспользуемся для этого методом find для поиска по массивам: const imageName = data.find(e => e.name.includes(title))
-
Также добавляем сюда расширение тем же методом, что и в предыдущей функции: const imageExt = imageName.name.split('.').pop()
- Делаем еще один запрос к базе данных, чтобы запросить публичную ссылку на изображение: const { publicURL, error } = supabase.storage.from('pictures').getPublickUrl(`${title}.${imageExt}`)
-
Далее сгенерируем картинку: const image = document.createElement('img')
-
Задаем ссылку на изображение в базе: image.src = publicURL
-
Потом ширину и высоту: image.width = 200 и image.height = 200
-
В конце прикрепляем получившуюся иллюстрацию к блоку imageBlock таким образом: imageBlock.appendChild(image)
Эту функцию мы будем запускать каждый раз при рендеринге элемента со статьей, так что сразу добавим ее в тело onMount.
Второй способ добавления изображений немного проще. Сама функция работает аналогично: берем те же данные, ищем картинку и ссылку на нее, но вместо того, чтобы генерировать картинку с нуля, мы создаем переменную url и добавляем ее в уже подготовленный элемент img в разметке.
<img width=100 height=50 src={url} alt />
Значение url мы будем менять на publicURL внутри onMount. Такой метод я использовал в компоненте Post.svelte, чтобы загружать миниатюрные изображения в списке постов.
Вместо заключения
На стадии рефакторинга мы немного изменим алгоритмы и в целом упростим процедуру привязки картинок к статьям. Уже сейчас мы имеем рабочий код, справляющийся со своей задачей и работающий вполне предсказуемо.
Как всегда, если будут вопросы, обязательно пишите в комментариях.
Продолжение: Создаем блог на Svelte. Часть 8: Лайки
Комментарии