Към съдържанието
wannacode

Условия: празно, грешка, зарежда

Накратко: Условното рендериране показва само частта от разметката, която отговаря на данните (зарежда, грешка, празно или списък); във Vue с v-if, v-else и v-show.

Проблем

Зарежда, грешка и списък едновременно

Каталогът е зареден. Под заглавието обаче пише „Зареждане…“, после „Продуктите не се заредиха.“, после „Няма продукти в тази категория.“ и чак тогава са продуктите.

Vue

Компонентът Catalog получава status и продуктите като props. Той обаче не ги гледа: рисува всичките четири части винаги. Купувачът не знае на кое да вярва, а екранният четец прочита и грешката, и продуктите.

Идеята

Частта, която отговаря на данните

Каталогът има четири състояния: зарежда, грешка, празно и готов. На екрана трябва да е само частта за текущото. Това е условно показване: компонентът решава какво да върне според данните.

Във Vue условията са атрибути в шаблона:

<p v-if="status === 'loading'" role="status">Зареждане…</p>
<p v-else-if="status === 'error'" role="alert">Продуктите не се заредиха.</p>
<p v-else-if="status === 'empty'">Няма продукти в тази категория.</p>
<ul v-else>…</ul>

v-if рисува елемента само ако изразът е верен. v-else-if и v-else продължават веригата и трябва да са веднага след предишния елемент от нея. От веригата се рисува точно един елемент.

Двете библиотеки решават едно и също по свой начин: React с JavaScript около разметката, Vue с атрибути в нея. Резултатът е един и същ: елементът на невярното условие го няма в DOM-а. Не е скрит, а не съществува.

Тук status е даден като prop. Как каталогът го сменя сам, докато зарежда от API, е в модула „Ефекти, данни и формуляри“.

Виж го

Виж кой клон влиза

Една стойност влиза в компонента, а в DOM-а влиза само един клон. Гледай колона „DOM“ при всяка смяна на status.

<template>
<p v-if="status === 'loading'">Зареждане…</p>
<p v-else-if="status === 'error'">Грешка</p>
<p v-else-if="status === 'empty'">Няма продукти</p>
<ul v-else>…</ul>
</template>
<!-- в DOM, но скрито -->
<p v-show="status === 'loading'">Зареждане…</p>
Стъпка по стъпка, с думи
  1. status идва в компонента като prop. Тя е 'loading': v-if съвпада и се рисува само <p>Зареждане…</p>. Другите клонове ги няма в DOM-а.
  2. status става 'error'. Библиотеката рисува наново: сега съвпада вторият клон. <p>Зареждане…</p> излиза от DOM-а, а съобщението за грешка влиза.
  3. 'empty': само съобщението, че категорията е празна.
  4. 'ready': нито v-if, нито v-else-if съвпада, затова се рисува v-else: списъкът. В DOM-а е винаги един клон.
  5. Другият начин: v-show рисува елемента винаги и сменя само display. При loading той се вижда.
  6. status става 'ready'. Елементът остава в DOM-а, с всичко в него, и само получава display: none. Не се вижда, а екранният четец го прескача.
  7. v-if маха елемента от DOM-а, v-show само го скрива. v-if е по подразбиране, а v-show е за нещо, което се сменя често или трябва да пази написаното.

Първата част е условно показване: при нова стойност старият елемент излиза от DOM-а, а новият влиза. Втората част е скриване: елементът е в DOM-а през цялото време и само се показва или скрива. За нея е краят на урока.

Пробвай

Четирите състояния

Catalog рисува всичко наведнъж. Направи го така, че във всеки раздел да е само частта на неговото състояние: „Зареждане…“ при loading, грешката при error, „Няма продукти в тази категория.“ при empty и списъкът при ready. Другите части да ги няма в страницата.

Vue

Пробвай

Попълни

„Зареждане…“ трябва да се вижда само докато status е loading.

<p ="status === 'loading'" role="status">Зареждане…</p>

Идеята

Изчерпан: значка и изключен бутон

Условието не е само за цели части. В картата на продукта то сменя текст и атрибут:

<p v-if="product.stock === 0" class="badge">Изчерпан</p>
<p v-else>Остават {{ product.stock }} бр.</p>
<button type="button" :disabled="product.stock === 0">Добави</button>

:disabled="true" слага атрибута disabled, а :disabled="false" го маха.

Изключеният бутон не се натиска, не взима фокус с Tab, а екранният четец казва, че е недостъпен. Значката казва защо. Бутон, който се натиска, а после казва „няма наличност“, е по-лош: купувачът разбира едва след клика.

Пробвай

Изчерпан

Направи ProductCard така, че при stock 0 да показва „Изчерпан“ и бутонът „Добави“ да е изключен. Иначе да показва „Остават 5 бр.“ и бутонът да работи. Сиренето е изчерпано.

Vue

Идеята

Нулата на екрана

v-if гледа дали стойността е вярна, затова v-if="items.length" при празна кошница не рисува нищо. Нулата излиза, ако условието е в {{ }}:

<p>{{ items.length && `В кошницата: ${items.length}` }}</p> <!-- празна кошница: 0 -->
<p v-if="items.length > 0">В кошницата: {{ items.length }}</p> <!-- празна кошница: нищо -->

&& не връща true или false. Той връща лявата страна, ако тя е невярна: тук 0, а {{ }} я показва. {{ false }} показва дори думата „false“. Условията пиши с v-if, а {{ }} остави за стойности.

Пробвай

Намери грешката

При празна кошница в горния ъгъл пише „0“.

Избери реда с грешката.

Идеята

Махнато или скрито

Понякога елементът трябва да остане в DOM-а и само да не се вижда. Тук и двата панела имат поле за бележка. Отвори двата, напиши нещо, затвори ги и ги отвори пак.

Vue
В първия раздел панелът е с v-if: при затваряне го няма, а при отваряне е нов, с празно поле. Във втория е с v-show: той остава в DOM-а със display: none и пази написаното.

Махането е по подразбиране: по-малко елементи в страницата, нищо скрито за екранния четец. Скриването е за части, които се отварят и затварят често или трябва да пазят какво е въведено в тях.

По-точно, за любопитните

v-if на <template>. За да покажеш няколко елемента при едно условие без обвивка, сложи v-if на <template>: той не влиза в DOM-а. v-show не работи на <template>, защото няма елемент, на който да сложи display: none.

Цената. v-if прави и маха елементите при всяка смяна, а v-show ги прави веднъж, още при първото рисуване, и после сменя само display. Затова v-show е за части, които се сменят често, а v-if е за части, които рядко се показват.

v-if и v-for. Във Vue 3 v-if на същия елемент като v-for се изпълнява първи и не вижда променливата от цикъла. Сложи v-if на обвивка или филтрирай данните.

Options API в стария код ползва същите v-if, v-else и v-show.

aria-hidden не е скриване. aria-hidden="true" скрива елемента само от екранния четец, а на екрана той остава. За скриване от всички е display: none: hidden, v-show или махане.

Упражнение

Кошницата

App показва три кошници: празна, с продукти и с изчерпан продукт. Направи Cart така, че празната да казва „Кошницата е празна.“, без списък и сума, и бутонът „Поръчай“ да е изключен. Пълната показва редовете, „Общо: 4,00 €“ и работещ бутон. Изчерпаният продукт има значка „Изчерпан“, над бутона пише „Махни изчерпаните продукти, за да поръчаш.“ (role alert), а бутонът е изключен.

Vue

Тест

Провери се

1. Условието за „Зареждане…“ е невярно. Какво има на негово място в DOM-а?
2. Кошницата е празна. Какво показва <p>{{ items.length && 'Има продукти' }}</p>?
3. Кое е вярно за v-else?
4. Панел с поле за бележка се отваря и затваря често, а написаното трябва да остане. Кое е по-подходящо?

Създаден от Иво Гергов като част от кампанията на Evo Tech за достъпно обучение по програмиране ·