Vue создание простого списка покупок

Vue - список покупок

Данное упражнение, направлено на закрепление того, что мы узнали в предыдущих статьях.

Это приложение должно позволять пользователям создавать и удалять отдельные элементы списка и очищать общий список своих покупок в один клик.

Следующие шаги помогут вам выполнить задание:

Создать интерактивную форму в компоненте, используя ввод, привязанный к v-model.

Добавьте одно поле ввода, в которое вы можете добавить элемент списка покупок. Разрешить пользователям добавлять элементы с помощью нажатия на
клавишу Enter, привязав нажатие к событию @keyup.enter.

Полный код компонента, внизу статьи.

Выглядеть приложение должно вот так:

vue создание простого приложения

Мы начнем с установки 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>

Данный код рекомендую внимательно изучить, попробовать что то изменить, а возможно и добавить новый функционал.

После того как код будет вам понятен, можем двигаться далее.