Данное упражнение, направлено на закрепление того, что мы узнали в предыдущих статьях.
Это приложение должно позволять пользователям создавать и удалять отдельные элементы списка и очищать общий список своих покупок в один клик.
Следующие шаги помогут вам выполнить задание:
Создать интерактивную форму в компоненте, используя ввод, привязанный к v-model.
Добавьте одно поле ввода, в которое вы можете добавить элемент списка покупок. Разрешить пользователям добавлять элементы с помощью нажатия на
клавишу Enter, привязав нажатие к событию @keyup.enter.
Полный код компонента, внизу статьи.
Выглядеть приложение должно вот так:
Мы начнем с установки vue и vite, и попытаемся описывать все наши шаги.
Установим vue и vite, открыв терминал и написав команды:
npm create vite@latest vue-mini-shop --template vue
После этого, будет предложено выбрать фреймворк - мы выбираем vue.
Язык - java script.
После этого, нам показаны команды:
cd vue-mini-shop npm install npm run dev
Выполнив их, мы запустим базовый шаблон vue.
Создадим компонент shop.vue внутри папки components, и импортируем его в App.vue, удалив все не нужное.
/* App.vue */
<script setup>
import Shop from './components/Shop.vue'
</script>
<template>
<Shop />
</template>
После того как мы убедимся, что наш компонент импортировался, и отображается на главной странице приложения, нам необходима сверстать его дизайн:
<template>
<div class="shop">
<h2>Shopping list</h2>
<form class="shop-form">
<div class="shop-form__serach">
<input class="shop-form__input" type="text" placeholder="Please enter to add new item">
<button class="shop-btn">Add item</button>
</div>
</form>
<div class="shop-items">
<div class="shop-item">
<span class="shop-item__title">Первый элемент</span>
<button class="shop-item__remove">Remove</button>
</div>
</div>
<div class="shop-nav">
<button class="remove-btn">Remove all</button>
</div>
</div>
</template>
Затем в секцию style, добавим атрибут scoped, и напишем код стилей:
<style scoped>
.shop-nav{
text-align: center;
}
.shop{
max-width: 700px;
margin-left: auto;
margin-right: auto;
}
.shop-item{
display: flex;
align-items: flex-start;
gap:30px;
}
.shop-item__remove{
flex-shrink: 0;
border-radius: 4px;
display: inline-flex;
border:1px solid rgb(236, 121, 121);
background-color: rgb(236, 121, 121);
color:#fff;
padding: 4px 10px;
}
.remove-btn{
flex-shrink: 0;
border-radius: 4px;
display: inline-flex;
border:1px solid rgb(236, 121, 121);
background-color: rgb(236, 121, 121);
color:#fff;
padding: 8px 20px;
}
.shop-item__title{
flex:1;
}
.shop-items{
margin-bottom: 30px;
border: 1px solid #ddd;
padding: 20px;
}
.shop-form__serach{
display: flex;
align-items: center;
gap:20px;
margin-bottom: 30px;
}
.shop-form__input{
flex:1;
height: 30px;
border: 1px solid #ccc;
border-radius: 4px;
padding-left: 15px;
padding-right: 15px;
}
.shop-btn{
border-radius: 4px;
display: inline-flex;
border:1px solid rgb(236, 121, 121);
background-color: rgb(236, 121, 121);
color:#fff;
padding: 8px 20px;
}
</style>
И после того как наш интерфейс будет построен, мы можем сосредоточиться на логике нашего приложения.
Для нашего простого приложения, нам понадобиться, всего лишь 2 переменные - addString - переменная для привязки значения введенного в поле ввода, и items - переменная, в которой мы будем хранить все добавленные элементы.
В секции script мы создадим переменные:
export default({
data(){
return {
addString:'',
items:[]
}
}
})
Обратите внимание, при использовании options API - стандартное API, которое использовалось во Vue2, и поддерживается в Vue3, мы должны начинать свой код с export default, а data, должна быть функцией, и возвращать переменные, как указано выше. В дальнейших статьях, мы более глубоко разберем новый Composition API, а пока мы пишем на option API.
Затем мы должны связать addString с полем ввода, через v-model, а также, добавим обработку нажатия клавиши enter:
<input class="shop-form__input" type="text" v-model="addString" placeholder="Please enter to add new item" @keyup.enter="addItem">
Метода addItem еще нет, но мы уже знаем, что при нажатии на кнопку enter он нам понадобится.
Созданную переменную items, мы должны проитерировать, ведь, в ней будут храниться наши элементы.
<div class="shop-items" v-if="items">
<div class="shop-item" v-for="(item,index) in items" :key="index">
<span class="shop-item__title">{{item}}</span>
<button class="shop-item__remove" @click="removeItem(index)">Remove</button>
</div>
</div>
Мы проверяем есть ли элементы в массиве, и выводим их с помощью v-for, так же нам нужен индекс каждого элемента, чтобы при нажатии на кнопку удаления, мы передали индекс (порядковый номер) элемента в массиве, и его удалили.
Удалять элемент, из списка, мы будем с помощью js функции - filter. Мы возьмем наш массив, найдем элемент, порядковый номер которого был передан в метод, и отфильтруем массив:
removeItem(i){
this.items = this.items.filter((item,index)=>index !== i);
},
Удалить все элементы, мы можем просто заменив наш массив на пустой:
removeAll(){
this.items = [];
}
Также, мы вынесли в отдельный метод очистку формы (которая нам нужна при добавлении элемента), чтобы пользователь мог сразу добавить новый:
clearForm(){
this.addString = '';
},
А затем, можем его вызвать внутри метода добавления элемента:
addItem(){
if(this.addString){
this.items.push(this.addString);
this.clearForm(); // <----
}
},
Полный код компонента:
<template>
<div class="shop">
<h2>Shopping list</h2>
<form class="shop-form">
<div class="shop-form__serach">
<input class="shop-form__input" type="text" v-model="addString" placeholder="Please enter to add new item" @keyup.enter="addItem">
<button class="shop-btn" @click.prevent="addItem">Add item</button>
</div>
</form>
<div class="shop-items" v-if="items">
<div class="shop-item" v-for="(item,index) in items" :key="index">
<span class="shop-item__title">{{item}}</span>
<button class="shop-item__remove" @click="removeItem(index)">Remove</button>
</div>
</div>
<div class="shop-nav">
<button class="remove-btn" @click="removeAll()">Remove all</button>
</div>
</div>
</template>
<script>
export default{
data(){
return{
addString:'',
items:[]
}
},
methods:{
addItem(){
if(this.addString){
this.items.push(this.addString);
this.clearForm();
}
},
clearForm(){
this.addString = '';
},
removeItem(i){
this.items = this.items.filter((item,index)=>index !== i);
},
removeAll(){
this.items = [];
}
}
}
</script>
<style scoped>
.shop-nav{
text-align: center;
}
.shop{
max-width: 700px;
margin-left: auto;
margin-right: auto;
}
.shop-item{
display: flex;
align-items: flex-start;
gap:30px;
margin-bottom: 20px;
}
.shop-item__remove{
flex-shrink: 0;
border-radius: 4px;
display: inline-flex;
border:1px solid rgb(236, 121, 121);
background-color: rgb(236, 121, 121);
color:#fff;
padding: 4px 10px;
}
.remove-btn{
flex-shrink: 0;
border-radius: 4px;
display: inline-flex;
border:1px solid rgb(236, 121, 121);
background-color: rgb(236, 121, 121);
color:#fff;
padding: 8px 20px;
}
.shop-item__title{
flex:1;
}
.shop-items{
margin-bottom: 30px;
border: 1px solid #ddd;
padding: 20px;
}
.shop-form__serach{
display: flex;
align-items: center;
gap:20px;
margin-bottom: 30px;
}
.shop-form__input{
flex:1;
height: 30px;
border: 1px solid #ccc;
border-radius: 4px;
padding-left: 15px;
padding-right: 15px;
}
.shop-btn{
border-radius: 4px;
display: inline-flex;
border:1px solid rgb(236, 121, 121);
background-color: rgb(236, 121, 121);
color:#fff;
padding: 8px 20px;
}
</style>
Данный код рекомендую внимательно изучить, попробовать что то изменить, а возможно и добавить новый функционал.
После того как код будет вам понятен, можем двигаться далее.