Урок 7 :: Class & Style Binding :: Привязка к классу и стилю

Вот, что мы с Вами сделаем на этом уроке.
Vue Mastery
Пройдем по этой ссылке:
Class & Style Binding ➳

... Все внимательно послушаем, посмотрим, прочитаем.

Затем сделаем конспект (мой см ниже).

Конспект

Привязка к классу и стилю
В этом уроке мы рассмотрим концепцию привязки к классу и стилю.

Чтобы начать этот урок, вы можете либо получить программой git коммандой checkout исходный код в ветке
L7-start репозитория, либо перейти в CodePen, чтобы взять файлы там.

Примечание переводчика

Чтобы перейти на ветку с файлами начала урока 7 выполните команду:

git checkout L7-start

Наша Цель
Привязка классов и стилей к нашим элементам на основе данных нашего приложения (объект data).

Привязка Стиля
На последнем уроке мы добавили функционал. При наведении курсора на “зеленый” или “синий” происходит обновление отображаемого изображения: появляются зеленые или синие носки соответственно. Но разве пользовательский интерфейс не был бы лучше, если бы вместо того, чтобы зависать над словом “зеленый” (“green”) или “синий” (“blue”), мы зависали над фактическими цветами зеленого и синего? Давайте создадим маленькие зеленые и синие кружки, на которые мы сможем навести курсор. Мы можем достичь этого с помощью привязки стилей.

Во-первых, чтобы оформить наши дивы в виде кругов, нам нужно будет добавить новый класс .color-circle к div, а котором у нас варианты товаров (т.е. носки зеленые и синие).

📄 index.html
<div 
  v-for="variant in variants" 
  :key="variant.id" 
  @mouseover="updateImage(variant.image)" 
  class="color-circle" 
</div>

Этот класс уже живет в нашем css-файле. Как вы можете видеть, он просто преобразует наши дивы в маленький круг диаметром 50 пикселей:

📄 styles.css
.color-circle {
  width: 50px;
  height: 50px;
  margin-top: 8px;
  border: 2px solid #d8d8d8;
  border-radius: 50%;
} 

Теперь, когда мы закончили с этим, мы можем перейти к фактической привязке стиля. Так же, как это звучит, мы хотим привязать стили к дивам. Мы делаем это, используя v-bind (или ее сокращение: :) для атрибута стиля style и привязывая к нему объект стиля.

📄 index.html
<div 
  v-for="variant in variants" 
  :key="variant.id" 
  @mouseover="updateImage(variant.image)" 
  class="color-circle" 
  :style="{ backgroundColor: variant.color }">
</div>

Здесь мы устанавливаем цвет дивов backgroundColor равным variant.color. Поэтому вместо того, чтобы печатать строки “зеленый” и “синий”, мы используем для выбора цвета фона наших кругов.

Проверив это в браузере, мы теперь должны увидеть два цветных круга, заполненных зеленым и синим фоном.
les07_pic01.jpg
Круто! Теперь давайте на более глубоком уровне поймем, как все это работает.

Понимание Привязки Стиля
В нашем варианте div мы добавили атрибут style и привязали к нему объект style.

📄 index.html
<div 
  ...
  :style="{ backgroundColor: variant.color }">
</div>

Этот объект стиля имеет свойство CSS backgroundColor, и мы устанавливаем его равным соответствующему вариантному цвету во время текущей итерации v-for.

В первой итерации variant.color имеет значение "green" ("зеленый").

Vue берет эту информацию и преобразует ее в код:style="{ backgroundColor: green }"

Затем отображает кружок с зеленым фоном зеленом фоне.
les07_pic02.jpg
Vue повторяет этот процесс для второго варианта цвета, чтобы создать синий круг.

Верблюд против Шашлыка (Camel vs Kebab)
Есть некоторые важные вещи, которые следует учитывать при использовании привязки стилей, подобной этой.

📄 index.html
<div :style="{ backgroundColor: variant.color }></div>

Внутри этого выражения помните, что этот объект стиля полностью является JavaScript. Вот почему я использовал camelCase в названии свойства. Если бы я сказал background-color, это было бы истолковано как знак минус. Но мы здесь не занимаемся никакой математикой. Мы задаем имя свойства CSS.

Поэтому, поскольку мы находимся в этом объекте JavaScript, мы должны использовать camelCased, если только мы не хотим использовать стиль Kebab в кавычках, чтобы избежать математического неправильного толкования, например так:

📄 index.html
<div :style="{ 'background-color': variant.color }></div>

Оба варианта будут работать. Помните про кавычки для стиля Kebab.

Привязка стиля: Объекты
Иногда вам может потребоваться добавить несколько стилей к элементу, но добавление их всех в строку может привести к беспорядку. В этих ситуациях мы можем привязаться ко всему объекту стиля, который находится в наших данных.
les07_pic03.jpg
Теперь, когда мы рассмотрели тему привязки стилей, давайте рассмотрим аналогичную тему: привязка классов.

Привязка к классу Вернувшись в наше приложение, вы заметите, что, когда значение data.InStock равно false, мы все равно можем нажать кнопку "Добавить в корзину" ("Add to Cart") и увеличить значение количества товара в корзине. Но если товара нет на складе, возможно, мы не хотим, чтобы пользователь мог добавить товар в корзину. Поэтому давайте изменим это поведение, отключая кнопку всякий раз, когда InStock имеет значение false. Делая кнопку отключенной, используем привязку к классу.

Чтобы сделать это, мы будем использовать сокращение для v-bind атрибута disabled, чтобы добавлять этот атрибут всякий раз, когда нашего продукта нет на складе.

📄 index.html
<button 
  class="button" 
  :disabled="!inStock" 
  @click="addToCart">
  Add to Cart
</button>

Теперь всякий раз, когда InStock имеет значение false и мы нажимаем кнопку "Добавить в корзину" ("Add to Cart"), ничего не произходит, так как он кнопка отключена. Но кнопка все еще кажется активной, что вводит в заблуждение наших пользователей. Поэтому давайте использовать привязку класса для добавления класса disabledButton, а также всякий раз, когда InStock имеет значение false.

Вы увидите в нашем CSS-файле, что у нас уже есть этот класс disabledButton, который устанавливает цвет фона (background-color) серым и делает курсор (cursor) недопустимым.

📄 styles.css
.disabledButton {
  background-color: #d8d8d8;
  cursor: not-allowed;
}

Чтобы применить этот класс по условию, на основе значения InStock, мы будем использовать сокращение для v-bind атрибута класса и использовать выражение, которое добавляет класс disabledButton (или нет) всякий раз, когда !InStock.

📄 index.html
<button 
  class="button" 
  :class="{ disabledButton: !inStock }" 
  :disabled="!inStock" 
  @click="addToCart">
  Add to Cart
</button>

Теперь всякий раз, когда InStock имеет значение false, кнопка не только будет отключена, но и будет отображаться отключенной.
les07_pic04.jpg
Несколько Имен Классов
Приступая к работе с привязкой классов, следует отметить некоторые моменты. Например, что происходит, когда у нас уже есть существующий класс, и мы хотим условно добавить другой класс на основе значения данных?

Например, если у нас уже есть класс color-circle в этом div, и мы условно добавим класс active, как это будет выглядеть?
les07_pic05.jpg
Эти классы будут объединены следующим образом:

📄 index.html
<div class="color circle active"></div>

Троичные (тернарные) операторы
Полезным инструментом, который дает нам привязка классов, является возможность использовать встроенные тернарные операторы для добавления различных классов на основе условия.
les07_pic06.jpg
В этом случае, поскольку isActive является истинным, мы действительно добавляем класс activeClass. Если бы это было ложно, мы бы не добавили класс (''); в качестве альтернативы мы могли бы добавить совершенно другой класс.

Различия в синтаксисе и варианты использования, которые я только что показал вам с привязкой к классу и стилю, - это только начало. Поэтому я рекомендую ознакомиться с документами Vue для получения дополнительных вариантов использования и примеров.

Задача кодирования
Мы подошли к концу этого урока, теперь будем решать новые задачи кодирования.

Вот, что надо сделать.

Свяжите класс out-of-stock-img с картинкой, когда свойство inStock равно false.

Вы можете найти код решения, загрузив L7-end ветвь репозитория или просмотрев решение в Codepen.

Чтобы перейти на ветку с файлами окончания урока 7 выполните команду:

git checkout L7-end

Код файла index.html данного урока

    <div id="app">
      <div class="nav-bar"></div>

      <div class="cart">Cart({{ cart }})</div>
      
      <div class="product-display">
        <div class="product-container">
          <div class="product-image">
            <!-- solution -->
            <img :class="{ 'out-of-stock-img': !inStock }" v-bind:src="image">
            <!-- solution -->
          </div>
          <div class="product-info">
            <h1>{{ product }}</h1>
            <p v-if="inStock">In Stock</p>
            <p v-else>Out of Stock</p>
            <ul>
              <li v-for="detail in details">{{ detail }}</li>
            </ul>

            <div 
              v-for="variant in variants" 
              :key="variant.id" 
              @mouseover="updateImage(variant.image)" 
              class="color-circle" 
              :style="{ backgroundColor: variant.color }">
            </div>
            
            <button 
              class="button" 
              :class="{ disabledButton: !inStock }" 
              :disabled="!inStock" 
              @click="addToCart">
              Add to Cart
            </button>
          </div>
        </div>
      </div>
    </div>

    <!-- Import App -->
    <script src="./main.js"></script>

    <!-- Mount App -->
    <script>
      const mountedApp = app.mount('#app')
    </script>


Код файла main.js данного урока

const app = Vue.createApp({
    data() {
        return {
            cart:0,
            product: 'Socks',
            brand: 'Vue Mastery',
            image: '../assets/images/socks_blue.jpg',
            inStock: false,
            details: ['50% cotton', '30% wool', '20% polyester'],
            variants: [
              { id: 2234, color: 'green', image: '../assets/images/socks_green.jpg' },
              { id: 2235, color: 'blue', image: '../assets/images/socks_blue.jpg' },
            ]
        }
    },
    methods: {
        addToCart() {
            this.cart += 1
        },
        updateImage(variantImage) {
            this.image = variantImage
        }
    }
})




Результат выполнения данного урока

Cart({{ cart }})

{{ product }}

In Stock

Out of Stock

  • {{ detail }}


Примечание переводчика

1. Я слегка меняю контент оригинальных файлов курса для тренировки, проверки русификации и т.д.

2. Код для HTML я размещаю в этом файле между тегами body.

3. Обратите внимание, чтобы в консоле браузера не было ошибок.

Теперь Нажмите здесь для перехода к следующему уроку ➳

... или ...


Ссылки по теме.