v-if
Ряд директив позволяет по условию изменять структуру DOM, и одной из таких является директива v-if. Она позволяет отобразить или скрыть элемент HTML по условию. Например:
<!DOCTYPE html> <html> <head> <title>Vue.js</title> <meta charset="utf-8" /> </head> <body> <div id="app"> <p v-if="visible">Первый параграф</p> <p>Второй параграф</p> <button v-on:click="visible = !visible">{{ visible ? 'Скрыть' : 'Показать' }}</button> </div> <script src="https://unpkg.com/vue"></script> <script> const app = new Vue({ el: '#app', data: { visible: true } }) </script> </body> </html>
Директива v-if в качестве параметра принимает условие, которое возвращает значение true или false. Если true, то элемент, к которому применяется директива v-if, отображается. Если false, то, наоборот, скрывается. В данном примере это значение определено в свойстве visible. С помощью кнопки в примере выше мы можем изменить значение свойства visible и соответственно отобразить или скрыть элемент.
В паре с директивой v-if может использоваться директива v-else, которая позволяет отобразить другой элемент, если условие в директиве v-if равно false:
<!DOCTYPE html> <html> <head> <title>Vue.js</title> <meta charset="utf-8" /> </head> <body> <div id="app"> <p v-if="visible">Первый параграф</p> <p v-else>Второй параграф</p> <button v-on:click="visible = !visible">{{ visible ? 'К параграфу 2' : 'К параграфу 1' }}</button> </div> <script src="https://unpkg.com/vue"></script> <script> const app = new Vue({ el: '#app', data: { visible: true } }) </script> </body> </html>
В данном случае, если условие, которое представляет свойство visible, равно true, то отображается первый параграф. Если условие возвращает false, то отображается второй параграф.
template
Так как выражение v-if является директивой, то оно может применяться только к одному элементу. Но что если мы хотим применить ее к группе элементов? В этом случае мы можем применить v-if для элемента <template>, который выступает в качестве обертки для группы элементов:
<!DOCTYPE html> <html> <head> <title>Vue.js</title> <meta charset="utf-8" /> </head> <body> <div id="app"> <template v-if="visible"> <h1>Заголовок 1</h1> <p>Параграф 1</p> </template> <template v-else> <h1>Заголовок 2</h1> <p>Параграф 2</p> </template> <button v-on:click="visible = !visible">{{ visible ? 'К параграфу 2' : 'К параграфу 1' }}</button> </div> <script src="https://unpkg.com/vue"></script> <script> const app = new Vue({ el: '#app', data: { visible: true } }) </script> </body> </html>
v-else-if
С помощью директивы v-else-if к v-if можно добавить обработку дополнительных условий. Например, в зависимости от введенного числа необходимо отображать тот или иной элемент:
<!DOCTYPE html> <html> <head> <title>Vue.js</title> <meta charset="utf-8" /> </head> <body> <div id="app"> <input type="number" v-model="number" /> <p v-if="number == 1">Один</p> <p v-else-if="number == 2">Два</p> <p v-else-if="number > 2 && number < 7">Несколько</p> <p v-else>Много</p> </div> <script src="https://unpkg.com/vue"></script> <script> const app = new Vue({ el: '#app', data: { number: 1 } }) </script> </body> </html>
Аналогично можно использовать v-else-if вместе с template:
<!DOCTYPE html> <html> <head> <title>Vue.js</title> <meta charset="utf-8" /> </head> <body> <div id="app"> <input type="number" v-model="number" /> <template v-if="number == 1"> <p>Один</p> </template> <template v-else-if="number == 2"> <p>Два</p> </template> <template v-else-if="number > 2 && number < 7"> <p>Несколько</p> </template> <template v-else> <p>Много</p> </template> </div> <script src="https://unpkg.com/vue"></script> <script> const app = new Vue({ el: '#app', data: { number: 1 } }) </script> </body> </html>
v-show
Директива v-show аналогично v-if позволяет скрывать или отображать элементы по определенному условию:
<!DOCTYPE html> <html> <head> <title>Vue.js</title> <meta charset="utf-8" /> </head> <body> <div id="app"> <div v-show="visible"> <h2>Заголовок</h2> <p>Текст</p> </div> <button v-on:click="visible = !visible">{{ visible ? 'Скрыть' : 'Отобразить' }}</button> </div> <script src="https://unpkg.com/vue"></script> <script> const app = new Vue({ el: '#app', data: { visible: true } }) </script> </body> </html>
Здесь в зависимости от значения условия, которое представляет свойство visible, будет скрываться или отображаться блок div. А с помощью кнопки мы можем переключить значение этого свойства с true на false и наоборот.
Но в отличие от v-if директива v-show не изменяет структуру DOM, а манипулирует значением стилевого свойства display. То есть если условие в v-show возвращает false, то для элемента устанавливается стиль display:none; и тем самым данный элемент скрывается на веб-странице.
В то же время манипуляции с DOM через v-if увеличивают накладные расходы и снижают производительность. Поэтому в тех ситуациях, когда возможно частое переключение видимости элемента, следует предпочитать v-show.
v-for
Для рендеринга коллекций предназначена директива v-for. Она имеет следующий синтаксис:
v-for="item in items"
Где items представляет массив, а item псевдоним для текущего перебираемого элемента из массива items.
Например, выведем массив элементов на страницу:
<!DOCTYPE html> <html> <head> <title>Vue.js</title> <meta charset="utf-8" /> </head> <body> <div id="app"> <ul> <li v-for="phone in phones">{{ phone }}</li> </ul> </div> <script src="https://unpkg.com/vue"></script> <script> const app = new Vue({ el: '#app', data: { phones: ['iPhone', 'Samsung', 'Nokia', 'Xiaomi'] } }) </script> </body> </html>
Таким образом, для каждого элемента в массиве phones будет создаваться html-элемент <li>.
Подобным образом можно выводить и более сложные объекты из массива:
<!DOCTYPE html> <html> <head> <title>Vue.js</title> <meta charset="utf-8" /> </head> <body> <div id="app"> <ul> <li v-for="user in users"> <p>Имя: {{ user.name }}</p> <p>Возраст: {{ user.age }}</p> </li> </ul> </div> <script src="https://unpkg.com/vue"></script> <script> const app = new Vue({ el: '#app', data: { users: [ { name: 'Tom', age: 22 }, { name: 'Bob', age: 31 }, { name: 'Sam', age: 28 } ] } }) </script> </body> </html>
Индексы
При переборе элементов с помощью дополнительного параметра в v-for мы можем получить индекс элемента в массиве, используя следующий синтаксис:
v-for="(element, index) in array"
Где element - это текущий перебираемый элемент в массиве array, а index - индекс этого элемента в массиве. Например:
<!DOCTYPE html> <html> <head> <title>Vue.js</title> <meta charset="utf-8" /> </head> <body> <div id="app"> <ul> <li v-for="(phone, index) in phones"> {{ index + 1 }}. {{ phone }} </li> </ul> </div> <script src="https://unpkg.com/vue"></script> <script> const app = new Vue({ el: '#app', data: { phones: ['iPhone', 'Samsung', 'Nokia', 'Xiaomi'] } }) </script> </body> </html>
Перебор объектов
Подобно тому, как мы перебираем массив, мы можем перебирать и все свойства одного объекта с помощью синтаксиса:
v-for="(value, property) in obj"
Где property - название свойства объекта, а value - его значение.
<!DOCTYPE html> <html> <head> <title>Vue.js</title> <meta charset="utf-8" /> </head> <body> <div id="app"> <ul> <li v-for="user in users"> <p v-for="(value, key) in user"> {{ key }} : {{ value }} </p> </li> </ul> </div> <script src="https://unpkg.com/vue"></script> <script> const app = new Vue({ el: '#app', data: { users: [ { name: 'Tom', age: 22 }, { name: 'Bob', age: 31 }, { name: 'Sam', age: 28 } ] } }) </script> </body> </html>
template
Директиву v-for можно применить только к одному html-элементу. Если необходимо, чтобы для каждого объекта из массива создавалось несколько html-элементов, то блок этих элементов следует обертывать элементом template:
<!DOCTYPE html> <html> <head> <title>Vue.js</title> <meta charset="utf-8" /> </head> <body> <div id="app"> <ul> <template v-for="user in users"> <li>Name: {{ user.name }}</li> <li>Age: {{ user.age }}</li> </template> </ul> </div> <script src="https://unpkg.com/vue"></script> <script> const app = new Vue({ el: '#app', data: { users: [ { name: 'Tom', age: 22 }, { name: 'Bob', age: 31 }, { name: 'Sam', age: 28 } ] } }) </script> </body> </html>
Перебор чисел
С помощью v-for можно перебрать все числа от 1 до определенного значения. Например, перебор всех чисел от 1 до 10:
<!DOCTYPE html> <html> <head> <title>Vue.js</title> <meta charset="utf-8" /> </head> <body> <div id="app"> <div> <span v-for="n in 10">{{ n }}</span> </div> </div> <script src="https://unpkg.com/vue"></script> <script> const app = new Vue({ el: '#app' }) </script> </body> </html>
Управление массивами
Во Vue.js для каждого массива определено ряд методов, с помощью которых можно управлять элементами массива:
Эти методы являются обертками над одноименными стандартными методами JavaScript для управления массивами и работают точно также. Единственное отличие их от стандартных методов состоит в том, что эти методы-обертки информируют систему Vue.js о том, что с массивом были произведены некоторые действия, и соответственно для этого массива может быть произведен повторный рендеринг на веб-странице.
Но кроме выше описанных методов, которые изменяют отдельные элементы массива, есть ряд методов в JavaScript, которые возвращают новый массив, типа filter(), concat(), slice(). Результат таких функций лучше привязывать к вычисляемому свойству, которое позволит произвести повторный рендеринг элементов веб-страницы.
Добавление и удаление
Определим код для добавления нового элемента в массив и удаления из массива:
<!DOCTYPE html> <html> <head> <title>Vue.js</title> <meta charset="utf-8" /> </head> <body> <div id="app"> <p> <input type="text" v-model="newPhone" /> <button v-on:click="phones.push(newPhone)">Добавить</button> </p> <ul> <li v-for="(phone, index) in phones"> <p>{{ phone }} <button v-on:click="phones.splice(index, 1)">Удалить</button></p> </li> </ul> </div> <script src="https://unpkg.com/vue"></script> <script> const app = new Vue({ el: '#app', data: { newPhone: '', phones: ['iPhone', 'Samsung', 'Nokia', 'Xiaomi'] } }) </script> </body> </html>
При нажатии на кнопку в массив будет добавлять введенное в текстовое поле значение, которое доступно через свойство newPhone. И в итоге произойдет обновление списка на веб-странице, и мы увидим добавленный элемент.
И кроме того, для каждого элемента предусмотрена кнопка, через которую по индексу можно удалить элемент из массива.
Установка элемента в массиве
При работе с массивами мы можем столкнуться с некоторыми ограничениями. В частности, мы не можем просто по индексу переустановить элемент массива, присвоив ему новое значение:
this.phones[1] = 'Samsung Galaxy S8'
Для установки значения нам надо использовать метод Vue.set():
Vue.set(массив, индекс_элемента, новое_значение)
Например, обновим второй элемент массива:
<!DOCTYPE html> <html> <head> <title>Vue.js</title> <meta charset="utf-8" /> </head> <body> <div id="app"> <ul> <li v-for="phone in phones"> <p>{{ phone }}</p> </li> </ul> <button v-on:click="updateList">Обновить</button> </div> <script src="https://unpkg.com/vue"></script> <script> const app = new Vue({ el: '#app', data: { phones: ['iPhone', 'Samsung', 'Nokia', 'Xiaomi'] }, methods: { updateList: function() { Vue.set(this.phones, 1, 'Samsung Galaxy S8') } } }) </script> </body> </html>
Возвращение нового массива
Ряд методов, такие как slice, concat, filter не изменяют текущий массив, а возвращают новый. Одно из решений может заключаться в переустановке массива. Например, используем метод slice, который возвращает часть массива:
<!DOCTYPE html> <html> <head> <title>Vue.js</title> <meta charset="utf-8" /> </head> <body> <div id="app"> <ul> <li v-for="phone in phones"> <p>{{ phone }}</p> </li> </ul> <button v-on:click="updateList">Обновить</button> </div> <script src="https://unpkg.com/vue"></script> <script> const app = new Vue({ el: '#app', data: { phones: ['iPhone', 'Samsung', 'Nokia', 'Xiaomi'] }, methods: { updateList: function() { this.phones = this.phones.slice(1, 3) } } }) </script> </body> </html>
Для фиксации нового массива присваиваем полученный массив свойству phones.
Однако данный способ не всегда является оптимальным. Особенно если мы хотим сохранить старый массив и изменять лишь его визуальное представление. И более идеальным вариантом, как правило, является разделение данных и представления этих данных. Для представления данных обычно определяется вычисляемое свойство-список, элементы которого выводятся на веб-страницу:
<!DOCTYPE html> <html> <head> <title>Vue.js</title> <meta charset="utf-8" /> </head> <body> <div id="app"> <input v-model="start" type="number" /> <input v-model="end" type="number" /> <ul> <li v-for="phone in visibleList"> <p>{{ phone }}</p> </li> </ul> </div> <script src="https://unpkg.com/vue"></script> <script> const app = new Vue({ el: '#app', data: { start: 0, end: 3, phones: ['iPhone', 'Samsung', 'Nokia', 'Xiaomi'] }, computed: { visibleList: function() { return this.phones.slice(this.start, this.end); } } }) </script> </body> </html>
Фильтрация и сортировка массива
Фильтрация массива
Стандартной ситуацией при работе с коллекциями объектов является фильтрация. Как правило, при фильтрации есть некоторый начальный список, а пользователю же возвращается некоторый временный результат. Начальный же список при этом не изменяется. И для этого во Vue.js лучше определить привязку к вычисляемому свойству:
<!DOCTYPE html> <html> <head> <title>Vue.js</title> <meta charset="utf-8" /> </head> <body> <div id="app"> <p> <input type="text" v-model="company" /> </p> <ul> <li v-for="phone in filteredList"> <p>{{ phone.title }} - {{ phone.company }}</p> </li> </ul> </div> <script src="https://unpkg.com/vue"></script> <script> const app = new Vue({ el: '#app', data: { company: '', phones: [ { title: 'iPhone 7', company: 'Apple' }, { title: 'iPhone 6S', company: 'Apple' }, { title: 'Galaxy S8', company: 'Samsung' }, { title: 'Galaxy S7 Edge', company: 'Samsung' }, { title: 'Nokia N8', company: 'HMD Global' } ] }, computed: { filteredList: function() { const company = this.company return this.phones.filter(function (element) { if (company === '') { return true } return element.company.indexOf(company) > -1 }) } } }) </script> </body> </html>
В данном случае фильтрация работает по принципу живого поиска. При вводе значения в текстовое поле происходит повторное вычисление свойства filteredList. Это свойство представляет результат функции, которая возвращает те объекты, у которых поле company соответствует введенному значению. То есть идет фильтрация телефонов по компании производителя. Если же значение не введено, то возвращаем все элементы из массива phones. В итоге можем динамически фильтровать элементы списка.
Сортировка списка
Для сортировки списка применяется похожая техника, что и для фильтрации:
<!DOCTYPE html> <html> <head> <title>Vue.js</title> <meta charset="utf-8" /> <style> a:hover { cursor: pointer; } </style> </head> <body> <div id="app"> <table> <tr> <td><a @click="sortParam = 'title'">Модель</a></td> <td><a @click="sortParam = 'company'">Компания</a></td> <td><a @click="sortParam = 'price'">Цена</a></td> </tr> <tr v-for="phone in sortedList"> <td>{{ phone.title }}</td> <td>{{ phone.company }}</td> <td>{{ phone.price }}</td> </tr> </table> </div> <script src="https://unpkg.com/vue"></script> <script> const app = new Vue({ el: '#app', data: { sortParam: '', phones: [ { title: 'Galaxy S8', company: 'Samsung', price: 45000 }, { title: 'iPhone 7', company: 'Apple', price: 49000 }, { title: 'Nokia N8', company: 'HMD Global', price: 25000 }, { title: 'Galaxy Note 8', company: 'Samsung', price: 50000 }, { title: 'iPhone 8', company: 'Apple', price: 60000 } ] }, computed: { sortedList () { switch (this.sortParam) { case 'title': return this.phones.sort(sortByTitle) case 'company': return this.phones.sort(sortByCompany) case 'price': return this.phones.sort(sortByPrice) default: return this.phones } } } }) const sortByTitle = function (d1, d2) { return (d1.title.toLowerCase() > d2.title.toLowerCase()) ? 1 : -1 } const sortByCompany = function (d1, d2) { return (d1.company.toLowerCase() > d2.company.toLowerCase()) ? 1 : -1 } const sortByPrice = function (d1, d2) { return (d1.price > d2.price) ? 1 : -1 } </script> </body> </html>
Как и в случае с фильтрацией, привязка устанавливается к вычисляемому свойству. При нажатии на заголовок столбца в таблице происходит переустановка значения свойства sortParam, которое представляет критерий фильтрации. При его изменении повторно вычисляется свойство sortedList, которое сортирует массив phones в соответствии со значением в sortParam. Для фильтрации по трем критериям определены три вспомогательные функции sortByTitle, sortByCompany и sortByPrice.