10 минут
5 минут
39 минут
Ниже приведен вольный пересказ этого скринкаста с переписыванием под Vue3 + script setup. Т.е. сначала просмотрите видео, чтобы понять о чём идет речь, а потом по пересказу попробуйте реализовать пример.
Расшифровка скринкаста (вольный пересказ своими словами)
Внимание! Cегодня мы с вами напишем очень и очень плохой код почему так и зачем мы это сделаем?
Мы это сделаем потому что когда вас учат писать сразу хороший код, вас учат решать задачу одним способом. Рано или поздно вы сталкиваетесь c задачами, решения которые вы не знаете и оказываетесь ситуации когда не понимаете хорошее ваше решение или плохое.
Мы с вами вначале напишем плохой, но к сожалению распространенный код и шаг за шагом, в рамках этой серии видео, будем его улучшать. У нас, как и в реальной жизни, будут появляться новые требования заказчика, мы будем находить какие-то баги сами уже у себя и сами героический фиксить и так далее.
Таким образом, на выходе вы не только получите хороший код для решения этой задачи, но и понимание как глядя на код понять что он действительно плохой.
В рамках расшифровки скринкаста я сразу буду переписывать его на Vue3, используя
vite+script setup
Чем же мы с вами займемся? Мы с вами напишем небольшое приложение, которое позволяет добавлять в список отслеживания криптовалюты, используя api cryptocompare.com.
Соответственно мы будем иметь возможность добавить криптовалютные пары "имя валюты - USD" в наблюдение и, когда мы выбираем конкретную валюту, у нас внизу появляется график отслеживания.
В домашнем задании первой лекции вы должны были научится создавать приложене Vue. Откроем его и удаляем "рыбу":
src/assets и src/componentsв App.vue удаляем всё из скрипта и шаблона (стили вообще удаляем)
<template>
<!-- тут будет html -->
</template>
<script setup>
// тут будет бизнес-логика (js)
</script>
в main.js комментируем строчку с импортом ./main.css
Можем запустить проект командой npm run dev и посмотреть на пустое окно, убедившись заодно, что нет ошибок
В материалах есть ссылка на файлы с вёрсткой.
Скопируйте содержимое <body> из файла index.htm в ваш шаблон (внутрь тега <template> вместо комментария)
Все сработало. Как видите все подключилось но выглядит как-то криво
Очевидно нам нужны стили. Как можно подключить css? В рамках скринкаста стили добавлены прямо в файл App.vue, но мы сделаем более правильно: скопируйте файл app.css в каталог src/assets и в файле main.js раскомментируйте и поправьте строчку с импортом файла стилей
import './assets/app.css'
Почему-то в проекте на vite показывает крутилку на весь экран, удалите из вёрстки первый <div> с этим спиннером (у меня он закомментирован)
Теперь всё выглядит "красиво"
Сегодня все наше внимание будет приковано к файлу App.vue.
Итак, что нам надо? Будем двигаться сверху вниз, оживляя эту страницу. Первое что нам надо это научиться заполнять поле "Тикер" и, когда нажимается кнопка "добавить", реагировать на нажатие.
Как мы помним, сильной стороной Vue является так называемое двухстороннее связывание, когда мы можем определить что-то в данных java-скрипта и вывести это что-то на экран. И когда что-то на экране поменяется оно автоматически изменится в приложении.
Ну что же давайте учиться это делать. Как вы помните vue декларативен. Что это означает? Это означает, что нам надо будет выучить язык описания компонентов, благо он не сложный. То есть у нас есть несколько заранее зарезервированных слов, с помощью которых мы будем объявлять те или иные особенности компонент.
Дальше в скринкасте расписывается функция
data(), которая возвращает реактивные данные, доступные в шаблоне. Но это устаревший синтаксис Option API из Vue2, во Vue3 стандартом являетсяSetup API, причем имеющий два варианта написания: функцияsetup()иscript setup. Мы будем использовать<script setup>.
Просто определим реактивную переменную:
<script setup>
import { ref } from "vue"
const ticker = ref('default')
</script>
Задав ей значение по умолчанию ('default') просто чтобы мы увидели как же осуществляется "двухстороннее связывание".
Как вы помните, vue это html-first фреймворк, это означает что мы пишем html, а дальше с помощью специальных атрибутов и интерполяций подсказываем как связать наш html с данными и первый атрибут (все атрибуты которые используют vue начинаются c v-) это v-model.
v-model как раз говорит "свяжи мне в две стороны вот этот вот input с данными (переменной ticker)"
И вот у нас в поле ввода появилось значение default, но перед тем как что то делать я бы хотел убедиться что связь работает в обе стороны, т.е. когда правим поле ввода меняется и значение переменной.
Мы используем так называемый синтаксис интерполяции... это две фигурные скобки. Обратите внимание их можно использовать только в тех местах где вы вводите текст просто на странице. То есть я не могу его использовать где-то внутри атрибута, только там где просто обычный текст.
Например:
<label
for="wallet"
class="block
text-sm
font-medium
text-gray-700"
>
Тикер {{ ticker }}
</label>
Теперь, если начать менять содержимое поля ввода input, то будет меняться и содержимое метки (label)
Мы научились с вами связывать переменные в две стороны. Это работает c инпутами, чекбоксами, с радио батонами. Потом мы научимся писать наши собственные компоненты которые умеют работать с v-model
Давайте что-нибудь с этим сделаем а что мы можем с этим сделать? Например при нажатии кнопки "добавить" я хочу чтобы что-то произошло.
Как бы мы это делали в обычном java-скрипте? Мы нашли бы элемент на страничке через query-селектор, добавили слушатель на события клик и после этого сказали бы какую функцию вызывать.
Во VUE все работает похожим образом. Мы пишем v-on:click="..." (мы говорили что все атрибуты VUE начинаются с v-), дальше имя события клик. Мы здесь можем написать обычный java-скрипт код (например, "ticker = 123"). И при нажатии кнопку "добавить" в переменную ticker запишется значение 123 и верстка автоматически изменилась (поменялось содержимое поля ввода и метки).
Но согласитесь писать код прямо в верстке как то странно, поэтому мы хотим чтобы код можно было писать рядом с вёрсткой (вспоминаем про SFC)
В оригинальном видео рассказывается про ключевое слово
method, но это тоже устаревший синтаксис.
Мы просто в <script setup> пишем функцию (напомню, что в секции <template> видны все имена, описанные в скрипте, а название функции это тоже имя)
<script setup>
import { ref } from "vue"
const ticker = ref('default')
function add () {
alert('Я работаю!')
}
</script>
Обратите внимание здесь можно будет потом передавать аргументы, то есть в 99% случаях надпись add и add() абсолютно одинаковы.
Итак пробуем: выводится алерт
Хорошо, но нам же хочется в скрипте дотянуться до значения, введенного в input. Как же нам это делать?
...
thisиспользуется только во Vue2, во Vue3 используется ЗНАЧЕНИЕ (полеvalue) реактивной переменной
function add () {
alert(ticker.value)
}
Проверяем, действительно вывелось ровно то значение которое введено в input.
Подождите, я хочу ещё, чтобы это событие срабатывало, когда я нажимаю кнопку Enter (дальше я пропустил полет мысли и привожу финальный результат: v-on:keydown.enter - при возникновении события нажатия клавиши Enter выполнить функцию add)
<input
v-model="ticker"
v-on:keydown.enter="add"
...
Дальше реализуем список тикеров. Очевидно что нам надо как-то научиться повторять какие-то вещи. Очевидно что повторять нам надо что то, то это скорее всего будет массивом.
Создадим в скрипте массив тикеров: просто объявляем переменную
const tickers = ref([1, 2, 3, 4])
Как сказать vue "повтори какую-то вещь несколько раз"?
Во-первых, что за вещь мне надо повторять? Нужно в верстке найти место, которое повторяется, удалить лишние повторы и использовать так называемую структурную директиву (директивами называются атрибуты которые обрабатываются vue опять же существенное упрощение но пока сойдет и так) v-for. У нас есть две ключевые структурные директивы мы потом поговорим почему они являются структурными но пока запомнить v-for и v-if они настолько суровы что даже друг с другом не дружат.
<div
v-for="t in tickers"
v-bind:key="t"
...
Я много раз повторял, что название переменных должно быть самоочевидным и, по идее, переменная цикла должна называться
ticker, но в этом случае она будет "перекрывать" одноименную переменную из скрипта. Нужно либо переименовать в скрипте переменнуюtikerвtickerName(мы не будем этого делать, чтобы не рассинхронизироваться со скринкастом), либо использовать переменную циклаt(для циклов и лямбда функций допускается использование однобуквенных переменных цикла)
Этот код говорит "для всех tickers повтори пожалуйста вот этот блок". Дальше нам выдаст ошибку про key.
Для циклов нужно использовать констукцию v-bind:key="уникальное значение". В нашем случае мы можем использовать просто значение t, но есть синтаксис v-for c индексом:
<div
v-for="(t, index) in tickers"
v-bind:key="index"
...
>
<div
class="px-4 py-5 sm:p-6 text-center">
<dt
class="text-sm font-medium text-gray-500 truncate"
>
{{ t }}
</dt>
Давайте чуть-чуть доведем до ума, но перед этим сделаем маленький шаг назад дело в том что в мире vue огромное количество раз вы будете писать в v-bind и v-on.
Писать так очень многословно поэтому придумали так называемую короткую запись, когда вместо v-on мы пишем собаку @, а вместо v-bind просто ничего не пишут, оставляют только :.
Нам надо выводить будет явное имя валюты и значение соответственно наш массив нужно переопределить как то так:
const tickers = ref([
{ name: 'DEMO', price: '-' },
{ name: 'DEMO', price: '-' },
{ name: 'DEMO', price: '-' }
])
Видите, теперь он начал выводить переменную t которая содержит весь объект и радостно нарисовал строковое представление объекта. Нам надо вывести поля name и price:
<dt class="text-sm font-medium text-gray-500 truncate">
{{ t.name }}
</dt>
<dd class="mt-1 text-3xl font-semibold text-gray-900">
{{ t.price }}
</dd>
Давайте научимся для начала добавлять такие элементы плюс давайте приведем это всё в тот дизайн который был, а именно добавим USD в пару:
<dt class="text-sm font-medium text-gray-500 truncate">
{{ t.name }} - USD
</dt>
Берём "рыбу" объекта и реализуем добавление её в массив tickers в функции add
function add () {
const newTicker = {
name: 'DEMO',
price: '-'
}
tickers.value.push(newTicker)
}
Не забываем, что обращение к значению реактивной переменной происходит через свойство
.value
Хорошо теперь только нам осталось вместо имени подставить название нового тикера:
function add () {
const newTicker = {
name: ticker.value,
^^^^^^^^^^^^^
price: '-'
}
tickers.value.push(newTicker)
}
Теперь хочется очищать тикер когда он добавился в массив. Вспомним что у нас связь двухсторонняя и просто запишем в тикер пустую строку в методе add
function add () {
const newTicker = {
name: ticker.value,
price: '-'
}
tickers.value.push(newTicker)
// очищаем текущее значение
ticker.value = ''
}
Обратите внимание это фундаментальный акцент на том как вообще работает vue. Мы хотим и умеем работать с данными html декларативно (мы же теперь с вами знаем это слово). Описываем как к этим данным привязать переменные и никогда не меняем html напрямую
Хорошо давайте двигаться дальше - теперь мы хотим удалять валюты. Прекрасно давайте найдем эту кнопку удалить, повесим на нее событие click и назовем handleDelete:
<button
@click="handleDelete(t)"
^^^^^^^^^^^^^^^^^^^^^^^^
Давайте напишем метод handleDelete (просто фильтруем исходный массив, возвращая все элементы, кроме того, который хотим удалить)
function handleDelete (tickerToRemove) {
tickers.value = tickers.value.filter(
t => t != tickerToRemove
)
}
Удаление работает, только вот видите некрасивый вот эти две полосочки
Мы бы хотели, чтобы их не было, чтобы этот кусок вообще не отображался, когда у меня нет данных.
v-ifЕсли хотим скрыть несколько не вложенных тегов, то можем завернуть их в тег template
<template
v-if="tickers.length > 0">
Сегодня мы с вами:
v-modelv-on или краткую запись @v-for и v-ifПовторите практическое задание (Криптономикон)