September 29, 2019

Несколько полезных трюков во Vue.js

Перевод статьи A few handy Vue.js tricks

1. Проброс всех props'ов из родительского компонента в дочерний компонент

Если вы разрабатываете приложения на Vue.js, то в какой-то момент вы наверняка напишите компонент, который будет «обернут» вокруг другого компонента. Так называемый компонент-обертка будет часто принимает все props'ы, которые также принимает компонент, который он оборачивает. Затем вы захотите «пробросить» все эти props'ы в завернутый компонент. Вместо этого:

<template>
  <child-component :someprop1="someprop1"
                   :someprop2="someprop2"
                   :someprop3="someprop3"
                   :someprop4="someprop4"
                   ...
  />
</template>

вы можете просто пробросить все props'ы компонента-обертки в оборачиваемый компонент, выполнив это:

<template>
  <child-component v-bind="$props"/>
</template>

2. Гарантия того, что два компонента принимают одинаковые props'ы

Этот трюк может быть скомбинирован с трюком №1. Теперь, когда известно, как перенаправить все props'ы в обернутый компонент, можно задаться вопросом: как убедиться в том, что компонент-обертка принимает все те же props'ы, что и обернутый компонент? В компоненте-обертке, можно написать что-то вроде этого:

<template>
  <child-component v-bind="$props"/>
</template>

<script>
  import ChildComponent from '@/components/ChildComponent'
  
  export default {
    props: {
      someProp1: String,
      someProp2: String,
      someProp3: String,
      // и т.д.
    }
  }
</script>

Этот подход имеет некоторые недостатки. Одним из этих недостатков является то, что если вы переписываете ChildComponent и, возможно, добавляете или удаляете props'ы, вам также придется вносить изменения в компонент-обертку. Другим недостатком является дублирование кода и, как правило, плохая эстетика кода. К счастью, есть очень простое решение этой проблемы:

<template>
  <child-component v-bind="$props"/>
</template>

<script>
  import ChildComponent from '@/components/ChildComponent'
  
  export default {
    props: {
      ...ChildComponent.options.props
    }
  }
</script>

3. Отправка всех event listener'ов родительского компонента в дочерний компонент

Вам не нужно этого делать, если дочерний компонент, которому вы хотите передать event listener'ы, находится в корне родительского компонента, так как он по умолчанию получает все event listener'ы. Однако, если это не так, как в следующем примере, вы можете сделать это:

<template>
  <div>
    ...
    <child-component v-on="$listeners"/>
    ...
  </div>
</template>

4. Красивый синтаксис слотов

Начиная с Vue 2.6, для именованных слотов появилось сокращение, как, например, для событий: @click вместо v-on:click. Если у вас, к примеру, есть компонент <my-table>, в котором есть именованный слот row, в котором есть slot-prop с именем item, то мы можем передать ему кусок шаблона и получить доступ к prop'су item следующим образом:

<template>
  ...
  <my-table>
    <template #row="{ item }">
      /* some content here. You can freely use 'item' here */
    </template>
  </my-table>
  ...
</template>

5. Динамические аргументы директивы

Возможно, это самая впечатляющая и мощная функция, предлагаемая Vue 2.6: динамическая передача аргументов директивы компоненту. Предположим, у вас есть компонент <my-button>. По некоторым причинам, иногда вы хотите прослушать событие click, а в других случаях вы хотите прослушать dblclick. Вы можете решить это с помощью динамических директив, таких как:

<template>
  ...
  <my-button @[someEvent]="handleSomeEvent()"/>
  ...
</template>

<script>
  ...
  data() {
    return {
      ...
      someEvent: someCondition ? 'click' : 'dblclick'
    }
  },
  
  methods: {
    handleSomeEvent() {
      // do something
    }
  }
  ...
</script>

Динамические event listener'ы - это только одна из многих вещей, которые вы можете сделать. Так же вы можете применить тот же шаблон к динамическим атрибутам HTML, props'ам и многому другому!

6. Динамический атрибут src в изображении

Это частый случай, когда вам нужно отобразить локально сохраненное изображение, путь которого хранится в переменной или в свойстве какого-либо объекта. Хотя для этого есть несколько решений, я предпочитаю использовать функцию require, который поставляется webpack'ом. Предположим, что в data вашего компонента Vue есть объект, который выглядит следующим образом:

data() {
  return {
    company: {
      name: 'CashMoney Inc.',
      logo: 'cashmoneylogo.png'
    }
  }
}

Путь к изображению, которое вы хотите отобразить, хранится в свойстве logo объекта company. В этом примере мы будем иметь ввиду то, что все наши изображения находятся по пути src/assets. Так же у нас существует подпапка с названием logos, которая содержит в себе несколько изображений логотипов. Таким образом, полный путь к нашему изображению будет: src/assets/logos/cashmoneylogo.png.

Из всего этого следует, что в <template> вашего компонента вы должны создать тег <img> и динамически пробросить данные в значение атрибута src:

<template>
  ...
  <img :src="require(`@/assets/logos/${company.logo}`)"/>
  ...
</template>

Несколько вещей, которые мы рассмотрим:

  • Путь, который передается в функцию require, является шаблонной строкой `…`. Таким образом, вы можете аккуратно вставить переменную, используя ${...} вместо конкатенации строки с помощью оператора +
  • Функция require не будет работать с полностью динамическим путем, поскольку webpack'у, во время сборки проекта, нужно знать о том, какие файлы нужно подтягивать. В пути к файлу вы должны указать статическую часть пути (@/assets/logos/). После чего webpack объединит все файлы, которые соответствуют этому пути*. Вот почему в нашем примере часть пути @/assets/logos жестко запрограммирована. Кстати, @ по сути означает «относительно папки src» (alias). Вы можете использовать его независимо от того, где находится файл, который вы ищите, и я настоятельно рекомендую использовать его вместо объявления уродливых путей в относительной форме, например ./../../../. Еще одно преимущество: если вы когда-нибудь решите переместить свой компонент / файл куда-нибудь еще, то путь, обозначенный с помощью @ останется рабочим.

* Примечание: это может повлиять на производительность, так как во время сборки приложения, webpack возьмет все файлы из указанного вами пути папки. Если это так, убедитесь, что ваш путь содержит в себе как можно меньшее количество файлов или посмотрите возможные варианты оптимизации, предлагаемые webpack'ом.

Послесловие

Подписывайся на нас в социальных сетях:
Vue.js

Nuxt.js

Наши друзья uWebDesign: