Skip to content

Входные параметры

Эта страница предполагает, что вы уже прочитали Основы компонентов. Сначала прочитайте это, если вы новичок в работе с компонентами.

Объявление входных параметров

Компоненты Vue требуют явного объявления входных параметров, чтобы Vue знал, какие внешние входные параметры, переданны компоненту, следует рассматривать как обычные атрибуты (которые будут рассмотрены в отдельном разделе).

В SFC использующих <script setup>, входные параметры могут быть объявлены с помощью макроса defineProps():

vue
<script setup>
const props = defineProps(['foo'])

console.log(props.foo)
</script>

В компонентах не имеющих<script setup>, входные параметры объявляются с помощью props:

js
export default {
  props: ['foo'],
  setup(props) {
    // setup() получает входной параметр в качестве первого аргумента.
    console.log(props.foo)
  }
}

Обратите внимание, что аргумент, передаваемый в defineProps(), совпадает со значением, предоставляемым props: один и тот же API props разделяется между двумя стилями декларации.

Входные параметры объявляются с помощью опции props:

js
export default {
  props: ['foo'],
  created() {
    // входной парметр доступен в `this`
    console.log(this.foo)
  }
}

В дополнение к объявлению входных параметров с использованием массива строк, мы также можем использовать объектный синтаксис:

js
export default {
  props: {
    title: String,
    likes: Number
  }
}
js
// С использованием <script setup>
defineProps({
  title: String,
  likes: Number
})
js
// Без использования <script setup>
export default {
  props: {
    title: String,
    likes: Number
  }
}

Для каждого свойства в синтаксисе объявления объекта ключом является имя входного параметра, а значением должна быть функция-конструктор ожидаемого типа.

Это не только документирует ваш компонент, но и предупредит других разработчиков, использующих ваш компонент, в консоли браузера, если они передадут неверный тип. Более подробно валидацию входных параметров мы рассмотрим далее на этой странице.

Если вы используете TypeScript с <script setup>, можно также объявлять входные параметры с помощью аннотаций чистого типа:

vue
<script setup lang="ts">
defineProps<{
  title?: string
  likes?: number
}>()
</script>

Подробнее: Типизирование входных параметров

Reactive Props Destructure

Vue's reactivity system tracks state usage based on property access. E.g. when you access props.foo in a computed getter or a watcher, the foo prop gets tracked as a dependency.

So, given the following code:

js
const { foo } = defineProps(['foo'])

watchEffect(() => {
  // runs only once before 3.5
  // re-runs when the "foo" prop changes in 3.5+
  console.log(foo)
})

In version 3.4 and below, foo is an actual constant and will never change. In version 3.5 and above, Vue's compiler automatically prepends props. when code in the same <script setup> block accesses variables destructured from defineProps. Therefore the code above becomes equivalent to the following:

js
const props = defineProps(['foo'])

watchEffect(() => {
  // `foo` transformed to `props.foo` by the compiler
  console.log(props.foo)
})

In addition, you can use JavaScript's native default value syntax to declare default values for the props. This is particularly useful when using the type-based props declaration:

ts
const { foo = 'hello' } = defineProps<{ foo?: string }>()

If you prefer to have more visual distinction between destructured props and normal variables in your IDE, Vue's VSCode extension provides a setting to enable inlay-hints for destructured props.

Passing Destructured Props into Functions

When we pass a destructured prop into a function, e.g.:

js
const { foo } = defineProps(['foo'])

watch(foo, /* ... */)

This will not work as expected because it is equivalent to watch(props.foo, ...) - we are passing a value instead of a reactive data source to watch. In fact, Vue's compiler will catch such cases and throw a warning.

Similar to how we can watch a normal prop with watch(() => props.foo, ...), we can watch a destructured prop also by wrapping it in a getter:

js
watch(() => foo, /* ... */)

In addition, this is the recommended approach when we need to pass a destructured prop into an external function while retaining reactivity:

js
useComposable(() => foo)

The external function can call the getter (or normalize it with toValue) when it needs to track changes of the provided prop, e.g. in a computed or watcher getter.

Детали передачи входных параметров

Именование входных параметров

Мы объявляем длинные имена свойств, используя camelCase, поскольку это позволяет избежать необходимости использовать кавычки при использовании их в качестве ключей свойств, а также позволяет нам ссылаться на них непосредственно в выражениях шаблона, поскольку они являются валидными идентификаторами JavaScript:

js
defineProps({
  greetingMessage: String
})
js
export default {
  props: {
    greetingMessage: String
  }
}
template
<span>{{ greetingMessage }}</span>

Технически, вы также можете использовать camelCase при передаче входных параметров дочернему компоненту (за исключением шаблонов DOM). Тем не менее, общепринятым является использование kebab-case во всех случаях для согласования с атрибутами HTML:

template
<MyComponent greeting-message="hello" />

Мы используем PascalCase для тегов компонентов, когда это возможно, потому что это улучшает читаемость шаблона, отличая компоненты Vue от собственных элементов. Однако практическая польза от использования camelCase при передаче входных параметров не так велика, поэтому мы предпочитаем следовать соглашениям каждого языка.

Статические и динамические входные параметры

До сих пор вы встречали, что входные параметры передаются как статические значения, например:

template
<BlogPost title="Как изучить Vue" />

Вы также встречали входные параметры, присваивающие динамическое значение с помощью v-bind или сокращения :, например:

template
<!-- Динамически присваиваем значение переменной -->
<BlogPost :title="post.title" />

<!-- Динамически присваиваем значение комплексного выражения -->
<BlogPost :title="post.title + ' by ' + post.author.name" />

Передача значений различных типов

В двух приведенных выше примерах мы передаем строковые значения, но любой тип значения может быть передан во входной параметр.

Числа

template
<!-- Несмотря на то, что `42` статическое значение, нам нужен v-bind, -->
<!-- чтобы сообщить Vue, что это выражение JavaScript, а не строка.    -->
<BlogPost :likes="42" />

<!-- Динамическое присвоение значения переменной. -->
<BlogPost :likes="post.likes" />

Булевы значения

template
<!-- Указание входного параметра без значения будет означать `true`. -->
<BlogPost is-published />

<!-- Несмотря на то, что `false` статическое значение, нам нужен v-bind, -->
<!-- чтобы сообщить Vue, что это выражение JavaScript, а не строка.      -->
<BlogPost :is-published="false" />

<!-- Динамическое присвоение значения переменной. -->
<BlogPost :is-published="post.isPublished" />

Массивы

template
<!-- Несмотря на то, что указан статический массив, нам нужен v-bind, -->
<!-- чтобы сообщить Vue, что это выражение JavaScript, а не строка.   -->
<BlogPost :comment-ids="[234, 266, 273]" />

<!-- Динамическое присвоение значения переменной. -->
<BlogPost :comment-ids="post.commentIds" />

Объекты

template
<!-- Несмотря на то, что указан статический объект, нам нужен v-bind, -->
<!-- чтобы сообщить Vue, что это выражение JavaScript, а не строка.   -->
<BlogPost
  :author="{
    name: 'Veronica',
    company: 'Veridian Dynamics'
  }"
 />

<!-- Динамическое присвоение значения переменной. -->
<BlogPost :author="post.author" />

Передача нескольких свойств с помощью объекта

Если хотите передать все свойства объекта в качестве входных параметров, то можно использовать v-bind без аргументов (v-bind вместо :prop-name). Например, для объекта post:

js
export default {
  data() {
    return {
      post: {
        id: 1,
        title: 'Как изучить Vue'
      }
    }
  }
}
js
const post = {
  id: 1,
  title: 'Как изучить Vue'
}

Следующий шаблон:

template
<BlogPost v-bind="post" />

Будет аналогичен такой записи:

template
<BlogPost :id="post.id" :title="post.title" />

Однонаправленный поток данных

Все входные параметры образуют одностороннюю привязку между дочерним свойством и родительским: когда родительское свойство обновляется — оно будет передаваться дочернему, но не наоборот. Это предотвращает случайное изменение дочерними компонентами родительского состояния, что может затруднить понимание потока данных приложения.

Кроме того, каждый раз, когда обновляется родительский компонент, все входные параметры дочернего компонента будут обновлены актуальными значениями. Это означает, что не должны пытаться изменять входной параметр внутри дочернего компонента. Если это сделать, Vue отобразит предупреждение в консоли.

js
const props = defineProps(['foo'])

// ❌ предупреждение, входные параметры доступны только для чтения!
props.foo = 'bar'
js
export default {
  props: ['foo'],
  created() {
    // ❌ предупреждение, входные параметры доступны только для чтения!
    this.foo = 'bar'
  }
}

Обычно встречаются два случая, когда возникает соблазн изменять входной параметр:

  1. Входной параметр используется для передачи начального значения; дочерний компонент хочет использовать его как локальное свойство данных в дальнейшем. В этом случае лучше всего определить локальное свойство в данных, которое использует значение входного параметра в качестве начального:

    js
    const props = defineProps(['initialCounter'])
    
    // counter использует только props.initialCounter в качестве начального значения;
    // он не будет получать будущие обновления входного параметра.
    const counter = ref(props.initialCounter)
    js
    export default {
      props: ['initialCounter'],
      data() {
        return {
          // counter использует только this.initialCounter в качестве начального значения;
          // он не будет получать будущие обновления входного параметра.
          counter: this.initialCounter
        }
      }
    }
  2. Входной параметр передаётся как необработанное значение, которое необходимо преобразовать. В таком случае лучше всего объявить вычисляемое свойство с использованием входного параметра:

    js
    const props = defineProps(['size'])
    
    // вычисляемое свойство автоматически обновится при изменении входного параметра
    const normalizedSize = computed(() => props.size.trim().toLowerCase())
    js
    export default {
      props: ['size'],
      computed: {
        // вычисляемое свойство автоматически обновится при изменении входного параметра
        normalizedSize() {
          return this.size.trim().toLowerCase()
        }
      }
    }

Мутация объектов / массивов из входных параметров

Когда объекты и массивы передаются как входные параметры, дочерний компонент не может изменить привязку входного параметра, но он сможет изменить вложенные свойства объекта или массива. Это связано с тем, что в JavaScript объекты и массивы передаются по ссылке, и предотвращение таких мутаций для Vue неоправданно дорого.

Основным недостатком таких мутаций является то, что они позволяют дочернему компоненту влиять на родительское состояние способом, который не очевиден для родительского компонента, что может затруднить анализ потока данных в будущем. Для лучшей практики следует избегать таких мутаций, если только родительский и дочерний элементы не тесно связаны по замыслу. В большинстве случаев дочерний компонент должен выдать событие, чтобы позволить родительскому элементу выполнить мутацию.

Валидация входных параметров

Компоненты могут указывать требования к своим входным параметрам, такие как определение типа, которые уже видели выше. Если эти требования не выполнены — Vue предупредит сообщением в JavaScript-консоли браузера. Это особенно полезно при разработке компонента, который предназначен для использования другими.

Чтобы указать валидации входного параметра, вы можете предоставить в defineProps()опцию props, объект с валидациями для проверки значения, вместо массива строк. Например:

js
defineProps({
  // Базовая проверка типов
  //  (`null` и `undefined` проходят проверку для любого типа)
  propA: Number,
  // Несколько допустимых типов
  propB: [String, Number],
  // Обязательное значение строкового типа
  propC: {
    type: String,
    required: true
  },
  // Обязательное, но нулевое значение строкового типа
  propD: {
    type: [String, null],
    required: true
  },
  // Число со значением по умолчанию
  propE: {
    type: Number,
    default: 100
  },
  // Объект со значением по умолчанию
  propF: {
    type: Object,
    // Для объектов или массивов значения по умолчанию
    // должны возвращаться из функции. Функция получает необработанные
    // входные параметры, полученные компонентом в качестве аргумента.
    default(rawProps) {
      return { message: 'привет' }
    }
  },
  // Пользовательская функция для валидации
  // полный перечень входных параметров передается в качестве 2-го аргумента в 3.4+
  propG: {
    validator(value, props) {
      // Значение должно соответствовать одной из этих строк
      return ['success', 'warning', 'danger'].includes(value)
    }
  },
  // Функция с значением по умолчанию
  propH: {
    type: Function,
    // В отличие от объекта или массива по умолчанию, это не фабричная функция — это функция, 
    // служащая в качестве значения по умолчанию
    default() {
      return 'Функция по умолчанию'
    }
  }
})

Совет

Код внутри аргумента defineProps() не может получить доступ к другим переменным, объявленным в <script setup> поскольку при компиляции все выражение перемещается во внешнюю область видимости функции.

js
export default {
  props: {
    // Базовая проверка типов
    //  (`null` и `undefined` проходят проверку для любого типа)
    propA: Number,
    // Несколько допустимых типов
    propB: [String, Number],
    // Обязательное значение строкового типа
    propC: {
      type: String,
      required: true
    },
    // Обязательное, но нулевое значение строкового типа
    propD: {
      type: [String, null],
      required: true
    },
    // Число со значением по умолчанию
    propE: {
      type: Number,
      default: 100
    },
    // Объект со значением по умолчанию
    propF: {
      type: Object,
      // Для объектов или массивов значения по умолчанию
      // должны возвращаться из функции. Функция получает необработанные
      // входные параметры, полученные компонентом в качестве аргумента.
      default(rawProps) {
        return { message: 'hello' }
      }
    },
    // Пользовательская функция для валидации
    // полный перечень входных параметров передается в качестве 2-го аргумента в 3.4+
    propG: {
      validator(value, props) {
        // Значение должно соответствовать одной из этих строк
        return ['success', 'warning', 'danger'].includes(value)
      }
    },
    // Функция с значением по умолчанию
    propH: {
      type: Function,
      // В отличие от объекта или массива по умолчанию, это не фабричная функция — это функция, 
      // служащая в качестве значения по умолчанию
      default() {
        return 'Функция по умолчанию'
      }
    }
  }
}

Дополнительные сведения:

  • Все входные параметры по умолчанию являются необязательными, если не указано required: true.

  • Отсутствующий необязательный входной параметр, отличный от Boolean будет иметь значение undefined.

  • Отсутствующий входной параметр Boolean будет приведен к false. Вы можете изменить это, задав для него значение по умолчанию. Например: default: undefined, чтобы он вел себя как не булево значение.

  • Если указано значение по умолчанию, оно будет использоваться, если разрешенное значение входного параметра undefined - это включает в себя как отсутствие входного параметра, так и явное undefined значение.

Когда проверка свойства завершается неудачей, Vue выдает консольное предупреждение (если используется сборка для разработки).

Если вы используете объявления свойств на основе типов , Vue сделает все возможное, чтобы скомпилировать аннотации типов в эквивалентные объявления свойств во время выполнения. Например, defineProps<{ msg: string }> будет скомпилирован в { msg: { type: String, required: true }}.

Примечание

Обратите внимание, что входные параметры проверяются до создания экземпляра компонента, поэтому свойства экземпляра (например data, computed, и т.д.) не будут доступны в функциях default и validator.

Проверка типа во время выполнения

Значением type может быть одним из следующих собственных конструкторов:

  • String
  • Number
  • Boolean
  • Array
  • Object
  • Date
  • Function
  • Symbol
  • Error

Кроме того, type может быть пользовательским классом или функцией конструктора, и утверждение будет сделано с помощью проверки instanceof. Например, дан следующий класс:

js
class Person {
  constructor(firstName, lastName) {
    this.firstName = firstName
    this.lastName = lastName
  }
}

Вы можете использовать его как тип входного параметра:

js
defineProps({
  author: Person
})
js
export default {
  props: {
    author: Person
  }
}

Vue будет использовать instanceof Person для проверки того, действительно ли значение входного параметра author является экземпляром класса Person.

Обнуляемый Тип

Если тип является обязательным, но допускает значение null, вы можете использовать синтаксис массива, который включает null:

js
defineProps({
  id: {
    type: [String, null],
    required: true
  }
})
js
export default {
  props: {
    id: {
      type: [String, null],
      required: true
    }
  }
}

Обратите внимание, что если type просто равен null без использования синтаксиса массива, то будет разрешен любой тип.

Булево преобразование

Входные параметры с типом Boolean имеют специальные правила приведения, чтобы имитировать поведение собственных булевых атрибутов. Дан <MyComponent> со следующим объявлением:

js
defineProps({
  disabled: Boolean
})
js
export default {
  props: {
    disabled: Boolean
  }
}

Компонент можно использовать следующим образом:

template
<!-- эквивалентно :disabled="true" -->
<MyComponent disabled />

<!-- эквивалентно :disabled="false" -->
<MyComponent />

Когда входной параметр объявлен с использованием нескольких типов, правила приведения для Boolean также будут применяться. Однако есть нюанс - когда есть и String, и Boolean, то правило приведения для Boolean применяется только в том случае, если Boolean находится раньше, чем String:

js
// disabled будет преобразован в true
defineProps({
  disabled: [Boolean, Number]
})

// disabled будет преобразован в true
defineProps({
  disabled: [Boolean, String]
})

// disabled будет преобразован в true
defineProps({
  disabled: [Number, Boolean]
})

// disabled будет разобран как пустая строка (disabled="")
defineProps({
  disabled: [String, Boolean]
})
js
// disabled будет преобразован в true
export default {
  props: {
    disabled: [Boolean, Number]
  }
}

// disabled будет преобразован в true
export default {
  props: {
    disabled: [Boolean, String]
  }
}

// disabled будет преобразован в true
export default {
  props: {
    disabled: [Number, Boolean]
  }
}

// disabled будет разобран как пустая строка (disabled="")
export default {
  props: {
    disabled: [String, Boolean]
  }
}
Входные параметрыУже загружено