Виджеты загрузки изображений позволяют пользователям предварительно просматривать изображения, которые они загружают в приложение или базу данных через формы, Google Drive и т.д. Эти виджеты позволяют пользователю принять решение о просмотре или удалении изображений, выбранных для отправки.
Что мы будем создавать
В этом посте рассматривается загрузка изображений с помощью виджета загрузки изображений Cloudinary и хранение полученного URL изображения в базе данных Appwrite для создания каталога товаров электронной коммерции.
URL GitHub
https://github.com/Iheanacho-ai/optimised-image-upload-vue
Предварительные условия
Чтобы получить максимальную отдачу от этого проекта, необходимо следующее:
- Базовое понимание CSS, JavaScript и Vue.js.
- На компьютере установлен Docker Desktop. Выполните команду
docker -v
, чтобы проверить, установлен ли у нас Docker Desktop; если нет, установите его из документации Get Docker. - Экземпляр Appwrite, запущенный на нашем компьютере. Посмотрите эту статью, чтобы создать локальный экземпляр Appwrite; мы будем использовать надежную базу данных Appwrite и службу Realtime для управления нашим приложением.
Настройка нашего приложения Vue.js
Мы установим Vue CLI, выполнив эти команды терминала для создания нового проекта Vue.
npm install -g @vue/cli
# OR
yarn global add @vue/cli
После установки Vue CLI мы переходим в нужный нам каталог и создаем новый проект.
vue create <name of our project>
Мы меняем директорию на проект и запускаем сервер разработки:
npm run serve
Чтобы посмотреть приложение, заходим на http://localhost:8080/.
Установка зависимостей
Установка Tailwind CSS
Tailwind CSS — это CSS-фреймворк, который позволяет быстро создавать пользовательские интерфейсы для веб-приложений.
Чтобы установить Tailwind CSS в наш проект, выполните следующие команды терминала:
npm install -D tailwindcss@latest postcss@latest autoprefixer@latest
npx tailwindcss init -p
Эти команды создают два файла в корневом каталоге нашего проекта, tailwind.config.js
и postcss.config.js
.
В нашем tailwind.config.js
мы добавляем пути ко всем нашим файлам шаблонов с помощью приведенного ниже кода.
module.exports = {
purge: ['./index.html', './src/**/*.{vue,js,ts,jsx,tsx}'],
content: [],
theme: {
extend: {},
},
plugins: [],
}
Далее мы добавляем директивы tailwind в наш файл src/index.css
.
@tailwind base;
@tailwind components;
@tailwind utilities;
Установка Appwrite
Appwrite Appwrite — это сквозное серверное решение с открытым исходным кодом, которое позволяет разработчикам быстрее создавать приложения.
Чтобы использовать Appwrite в нашем приложении Vue, мы установим клиентский SDK Appwrite для веб-приложений.
npm install appwrite
Создание нового проекта Appwrite
Во время создания экземпляра Appwrite мы указали, какое имя хоста и порт мы используем для нашей консоли. Значение по умолчанию — localhost:80.
Мы переходим на localhost:80 и создаем новую учетную запись, чтобы увидеть нашу консоль.
На нашей консоли есть кнопка Создать проект. Нажмите на нее, чтобы начать новый проект.
После создания проекта появится приборная панель нашего проекта. В верхней части страницы находится панель настроек. Нажмите на нее, чтобы получить доступ к ID проекта и конечной точке API.
Мы копируем ID проекта и конечную точку API, которые нам нужны для инициализации Appwrite Web SDK.
Мы создаем файл init.js
в корневом каталоге нашего проекта для инициализации Appwrite Web SDK со следующим кодом.
import { Appwrite } from 'appwrite';
export const sdk = new Appwrite();
sdk
.setEndpoint('http://localhost/v1') // Replace this with your endpoint
.setProject('projectID'); // Replace this with your ProjectID
Создание анонимной сессии пользователя
Appwrite требует, чтобы пользователь регистрировался перед чтением или записью в базу данных для обеспечения безопасности в нашем приложении. Однако они позволяют нам создать анонимную сессию, чтобы обойти эту политику для простых проектов. Мы сделаем это в нашем файле init.js
.
import { Appwrite } from 'appwrite';
export const sdk = new Appwrite();
sdk
.setEndpoint('http://localhost/v1') // Replace this with your endpoint
.setProject(projectID); // Replace this with your ProjectID
// Create an anonymous user session
sdk.account.createAnonymousSession().then(
(response) => {
console.log(response);
},
(error) => {
console.log(error);
}
);
Создание коллекции и атрибутов
Далее мы настроим нашу базу данных, которая будет хранить статус нашего заказа. В веб-консоли Appwrite мы нажимаем на Database в левой части приборной панели.
Мы создаем коллекцию на вкладке нашей базы данных, нажав на кнопку Добавить коллекцию. Это действие перенаправляет нас на страницу разрешений.
На уровне коллекции мы хотим назначить доступ на чтение и доступ на запись со значением role:all. Мы можем изменить разрешения, чтобы указать, кто имеет доступ на чтение или запись в нашу базу данных.
Справа на странице Разрешения мы копируем идентификатор коллекции, который нам нужен для выполнения операций над документами коллекции.
Далее мы переходим на вкладку Attributes, чтобы создать свойства, которыми должен обладать документ.
Мы создаем три строковых атрибута: productName, productPrice и productImage.
Создание страницы создания продукта
Мы создаем страницу создания продукта в файле App.vue
. Эта страница создания продукта будет содержать два раздела: первый включает форму для сбора информации о продукте, а второй раздел перечисляет продукты в нашей базе данных.
Здесь мы создадим форму для отправки названия, цены и изображения товара в базу данных. Мы добавим следующий фрагмент кода в файл index.js
для создания формы, оформленной с помощью Tailwind CSS.
<template>
<div class= 'product-catalog'>
<div class="product-container mt-5 md:mt-0 md:col-span-2">
<div class="shadow sm:rounded-md sm:overflow-hidden">
<div class="px-4 py-5 bg-white space-y-6 sm:p-6">
<div>
<label for="price" class="block text-sm font-medium text-gray-700">Product Name</label>
<div class="mt-1 relative rounded-md shadow-sm">
<input type="text" name="price" v-model="productName" class="focus:ring-indigo-500 focus:border-indigo-500 block w-full pl-7 pr-12 sm:text-sm border-gray-300 rounded-md" placeholder="product name" />
</div>
</div>
<div>
<label for="price" class="block text-sm font-medium text-gray-700">Price</label>
<div class="mt-1 relative rounded-md shadow-sm">
<div class="absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none">
<span class="text-gray-500 sm:text-sm"> $ </span>
</div>
<input type="text" name="price" v-model="productPrice" class="focus:ring-indigo-500 focus:border-indigo-500 block w-full pl-7 pr-12 sm:text-sm border-gray-300 rounded-md" placeholder="0.00" />
</div>
</div>
<button nclass="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded">
Upload files
</button>
<div className="px-4 py-3 bg-gray-50 text-right sm:px-6">
<button
type="button"
className="cursor inline-flex justify-center py-2 px-4 border border-transparent shadow-sm text-sm font-medium rounded-md text-white bg-indigo-600 hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500"
>
Save
</button>
</div>
</div>
</div>
</div>
</div>
</template>
В секции style
нашего файла App.vue
мы создаем стили Tailwind CSS с помощью этих стилей CSS.
<style>
.product-container{
margin-left: 37%;
width: 30%;
}
</style>
Вот как выглядит наша форма создания продукта.
Встраивание виджета Cloudinary Upload
В этом проекте кнопка Upload File открывает виджет загрузки изображений Cloudinary, позволяющий нам загружать изображения в базу данных Appwrite.
Чтобы понять, как встроить виджет загрузки изображений Cloudinary в наш проект, ознакомьтесь с этой статьей.
Добавьте взаимодействие с нашей базой данных
Когда пользователь нажимает на кнопку сохранения, мы хотим сохранить информацию о товарах в базе данных Appwrite и вывести список сохраненных товаров в нашем приложении.
Хранение информации о товаре в базе данных
Мы храним информацию в базе данных Appwrite в виде документов. В разделе сценария нашего файла App.vue
мы создаем четыре переменные в объекте data
.
<script>
export default {
name: 'App',
data(){
return{
productName: '',
productPrice: '',
productImage: '',
products: []
}
},
}
</script>
В переменных хранится следующая информация.
- Переменная
productName
содержит имя продукта, которое будет храниться в базе данных. - Переменная
productPrice
содержит цену продукта, которая будет храниться в базе данных. - Переменная
productImage
содержит URL изображения продукта для хранения в базе данных - Переменная
products
представляет собой массив всех продуктов, хранящихся в базе данных.
Далее мы импортируем экземпляр sdk
из нашего файла init.js
в файл App.vue
.
import {sdk} from '../init';
Затем мы создаем функцию handleProductSubmit
в нашем файле App.vue
для создания документов в нашей базе данных.
handleProductSubmit: async function(){
try {
await sdk.database.createDocument(collectionID, 'unique()', {
"productName" : this.productName,
"productPrice": this.productPrice,
"productImage": this.productImage
});
alert('your job item has been successfully saved')
this.productName= '',
this.productPrice= '',
this.productImage= ''
} catch (error) {
console.log(error)
}
},
Функция handleProductSubmit
делает следующее:
- Создает новый документ с помощью функции
createDocument()
от Appwrite, передавая в качестве параметров ID коллекции и значения атрибутов. - Предупреждает нас об успешном сохранении документа, затем очищает информацию в локальных переменных состояния
- Записывает в консоль любую ошибку, возникшую при создании документа.
https://gist.github.com/Iheanacho-ai/d20d8322de5e1d51d0ad89febeac996e
Вывод списка продуктов
В файле App.vue
мы создаем функцию listProducts
для получения информации о товарах, хранящейся в нашей базе данных.
listProducts: async function(){
try {
let response = await sdk.database.listDocuments('628a9019078ea3c2b384');
this.products = response.documents
} catch (error) {
console.log(error)
}
},
Функция listProducts
делает следующее:
- Перечисляет все документы в коллекции
- Сохраняет документы в массиве
products
- Записывает в консоль все возникшие ошибки
Затем мы вызываем функцию listProducts
в нашей функции handleProductSubmit
и жизненном цикле mounted
.
mounted: function(){
this.listProducts()
},
mounted: function(){
handleProductSubmit: async function(){
try {
...
this.listProducts()
} catch (error) {
console.log(error)
}
},
}
Удаление продуктов
Далее мы создадим функцию handleDelete
в нашем файле App.vue
, чтобы удалить любой продукт и информацию о нем из нашей базы данных Appwrite.
handleDelete: async function(documentid){
try {
await sdk.database.deleteDocument(collectionID, documentid);
alert("item have been deleted successfully")
this.listProducts()
} catch (error) {
console.log(error)
}
}
Эта функция handleDelete
делает следующее:
- Удаляет документ из нашей коллекции базы данных Appwrite с помощью функции
deleteDocument
. Эта функцияdeleteDocument
находит документ, используя его ID документа и параметр ID коллекции. - Предупреждает пользователя об успешном удалении документа.
- Перечисляет оставшиеся продукты в нашей базе данных с помощью функции
listProducts
. - Записывает в журнал все ошибки, возникшие при удалении документа.
После создания наших функций вот как выглядит наш файл App.vue
.
https://gist.github.com/Iheanacho-ai/7a7eb7a1649bfc492cf9e3282101fcb8
Далее мы передаем переменные productName
и productPrice
в элементы input
нашей формы.
<input type="text" name="price" v-model="productName" class="focus:ring-indigo-500 focus:border-indigo-500 block w-full pl-7 pr-12 sm:text-sm border-gray-300 rounded-md" placeholder="product name" />
<input type="text" name="price" v-model="productPrice" class="focus:ring-indigo-500 focus:border-indigo-500 block w-full pl-7 pr-12 sm:text-sm border-gray-300 rounded-md" placeholder="0.00" />
Наконец, мы передаем функцию handleProductSubmit
нашей кнопке Save.
<button
type="button"
@click="handleProductSubmit"
className="cursor inline-flex justify-center py-2 px-4 border border-transparent shadow-sm text-sm font-medium rounded-md text-white bg-indigo-600 hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500"
>
Save
</button>
ПРИМЕЧАНИЕ: Мы используем кнопку с type= button
, чтобы переопределить стандартное поведение кнопки при отправке.
После выполнения этих шагов вот как выглядит наш файл App.vue
.
https://gist.github.com/Iheanacho-ai/8f5106c552eee8cf1d4cd4efc8a3d5fa
Создание пользовательского интерфейса листинга товаров
Чтобы создать пользовательский интерфейс для отображения товаров, хранящихся в базе данных Appwrite, мы вставим этот код в наш файл App.vue
.
<div className="bg-white">
<div className="max-w-2xl mx-auto py-16 px-4 sm:py-24 sm:px-6 lg:max-w-7xl lg:px-8">
<h2 className="sr-only">Products</h2>
<div className="grid grid-cols-1 gap-y-10 sm:grid-cols-2 gap-x-6 lg:grid-cols-3 xl:grid-cols-4 xl:gap-x-8">
<a href="#" v-for= 'product in products' :key= 'product.productName' className="group">
<div className="w-full aspect-w-1 aspect-h-1 bg-gray-200 rounded-lg overflow-hidden xl:aspect-w-7 xl:aspect-h-8">
<img :src="product.productImage" alt="Tall slender porcelain bottle with natural clay textured body and cork stopper." className="w-full h-full object-center object-cover group-hover:opacity-75" />
</div>
<h3 className="mt-4 text-sm text-gray-700">{{product.productName}}</h3>
<p className="mt-1 text-lg font-medium text-gray-900">${{product.productPrice}}</p>
<button
type="button"
className="cursor inline-flex justify-center py-2 px-4 border border-transparent shadow-sm text-sm font-medium rounded-md text-white bg-indigo-600 hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500"
@click="handleDelete(product.$id)"
>
Delete
</button>
</a>
</div>
</div>
</div>
В приведенном выше блоке кода мы:
- Пройдитесь по массиву
products
для визуализации каждого продукта. - Передайте переменные
productName
,productPrice
иproductImage
в массивproducts
. - Передайте функцию
handleDelete
и параметр ID документа слушателю события@Click
на кнопке Deletebutton
.
Вот как выглядит файл App.vue
.
https://gist.github.com/Iheanacho-ai/03f5eb3f75fa8e799fd217c23229b97e
Заполните форму, чтобы увидеть, как выглядит каталог товаров.
Заключение
В этой статье мы рассмотрели управление оптимизированной загрузкой изображений с помощью Cloudinary и хранение изображений в базе данных Appwrite. Используя эту информацию, мы создали каталог товаров. Вы можете изменить поля, чтобы разместить больше информации о продукте.
Ресурсы
Вот некоторые ресурсы, которые могут оказаться полезными.
- Загрузка файлов Vue и Rich Media в два простых шага
- Создание локального экземпляра Appwrite в 3 шага
- API базы данных