Прототип объекта

Binding Native Events to Components

There may be times when you want to listen directly to a native event on the root element of a component. In these cases, you can use the modifier for :


<base-input v-on:focus.native="onFocus"></base-input>

This can be useful sometimes, but it’s not a good idea when you’re trying to listen on a very specific element, like an . For example, the component above might refactor so that the root element is actually a element:

<label>  {{ label }}  <input    v-bind="$attrs"    v-bind:value="value"    v-on:input="$emit('input', $event.target.value)"  ></label>

In that case, the listener in the parent would silently break. There would be no errors, but the handler wouldn’t be called when we expected it to.

To solve this problem, Vue provides a property containing an object of listeners being used on the component. For example:

{  focus: function (event) {  }  input: function (value) {  },}

Using the property, you can forward all event listeners on the component to a specific child element with . For elements like , that you also want to work with , it’s often useful to create a new computed property for listeners, like below:

Vue.component('base-input', {  inheritAttrs: false,  props: ,  computed: {    inputListeners: function () {      var vm = this      return Object.assign({},        this.$listeners,        {          input: function (event) {            vm.$emit('input', event.target.value)          }        }      )    }  },  template: `    <label>      {{ label }}      <input        v-bind="$attrs"        v-bind:value="value"        v-on="inputListeners"      >    </label>  `})

Now the component is a fully transparent wrapper, meaning it can be used exactly like a normal element: all the same attributes and listeners will work.

Dynamic Components

Sometimes, it’s useful to dynamically switch between components, like in a tabbed interface:

{{ tab }}

The above is made possible by Vue’s element with the special attribute:

In the example above, can contain either:

  • the name of a registered component, or
  • a component’s options object

See this example to experiment with the full code, or this version for an example binding to a component’s options object, instead of its registered name.

Keep in mind that this attribute can be used with regular HTML elements, however they will be treated as components, which means all attributes will be bound as DOM attributes. For some properties such as to work as you would expect, you will need to bind them using the .

That’s all you need to know about dynamic components for now, but once you’ve finished reading this page and feel comfortable with its content, we recommend coming back later to read the full guide on Dynamic & Async Components.

Organizing Components

It’s common for an app to be organized into a tree of nested components:

For example, you might have components for a header, sidebar, and content area, each typically containing other components for navigation links, blog posts, etc.

To use these components in templates, they must be registered so that Vue knows about them. There are two types of component registration: global and local. So far, we’ve only registered components globally, using :

Globally registered components can be used in the template of any root Vue instance () created afterwards – and even inside all subcomponents of that Vue instance’s component tree.

That’s all you need to know about registration for now, but once you’ve finished reading this page and feel comfortable with its content, we recommend coming back later to read the full guide on Component Registration.

DOM Template Parsing Caveats

Some HTML elements, such as , , and have restrictions on what elements can appear inside them, and some elements such as , , and can only appear inside certain other elements.

This will lead to issues when using components with elements that have such restrictions. For example:

The custom component will be hoisted out as invalid content, causing errors in the eventual rendered output. Fortunately, the special attribute offers a workaround:

It should be noted that this limitation does not apply if you are using string templates from one of the following sources:

  • String templates (e.g. )
  • Single-file () components

That’s all you need to know about DOM template parsing caveats for now – and actually, the end of Vue’s Essentials. Congratulations! There’s still more to learn, but first, we recommend taking a break to play with Vue yourself and build something fun.

Once you feel comfortable with the knowledge you’ve just digested, we recommend coming back to read the full guide on Dynamic & Async Components, as well as the other pages in the Components In-Depth section of the sidebar.

##company## — ##description##

Edit this on GitHub! Netlify

Usage

PropTypes was originally exposed as part of the React core module, and is commonly used with React components. Here is an example of using PropTypes with a React component, which also documents the different validators provided:

importReactfrom'react';importPropTypesfrom'prop-types';classMyComponentextendsReact.Component{render(){}}MyComponent.propTypes={  optionalArrayPropTypes.array,  optionalBoolPropTypes.bool,  optionalFuncPropTypes.func,  optionalNumberPropTypes.number,  optionalObjectPropTypes.object,  optionalStringPropTypes.string,  optionalSymbolPropTypes.symbol,  optionalNodePropTypes.node,  optionalElementPropTypes.element,  optionalElementTypePropTypes.elementType,  optionalMessagePropTypes.instanceOf(Message),  optionalEnumPropTypes.oneOf('News','Photos'),  optionalUnionPropTypes.oneOfType(PropTypes.string,PropTypes.number,PropTypes.instanceOf(Message)),  optionalArrayOfPropTypes.arrayOf(PropTypes.number),  optionalObjectOfPropTypes.objectOf(PropTypes.number),  optionalObjectWithShapePropTypes.shape({    optionalPropertyPropTypes.string,    requiredPropertyPropTypes.number.isRequired}),  optionalObjectWithStrictShapePropTypes.exact({    optionalPropertyPropTypes.string,    requiredPropertyPropTypes.number.isRequired}),  requiredFuncPropTypes.func.isRequired,  requiredAnyPropTypes.any.isRequired,customPropfunction(props,propName,componentName){if(!matchme.test(propspropName)){returnnewError('Invalid prop `'+ propName +'` supplied to'+' `'+ componentName +'`. Validation failed.');}},  customArrayPropPropTypes.arrayOf(function(propValue,key,componentName,location,propFullName){if(!matchme.test(propValuekey)){returnnewError('Invalid prop `'+ propFullName +'` supplied to'+' `'+ componentName +'`. Validation failed.');}})};

Binding Native Events to Components

There may be times when you want to listen directly to a native event on the root element of a component. In these cases, you can use the modifier for :

This can be useful sometimes, but it’s not a good idea when you’re trying to listen on a very specific element, like an . For example, the component above might refactor so that the root element is actually a element:

In that case, the listener in the parent would silently break. There would be no errors, but the handler wouldn’t be called when we expected it to.

To solve this problem, Vue provides a property containing an object of listeners being used on the component. For example:


Using the property, you can forward all event listeners on the component to a specific child element with . For elements like , that you also want to work with , it’s often useful to create a new computed property for listeners, like below:

Now the component is a fully transparent wrapper, meaning it can be used exactly like a normal element: all the same attributes and listeners will work, without the modifier.

Arrow Functions

Arrow functions were introduced in ES6.

Arrow functions allow us to write shorter function syntax:

With Arrow Function:

It gets shorter! If the function has only one statement, and the statement returns a value, you can remove the brackets and the keyword:

Arrow Functions Return Value by Default:

Note: This works only if the function has only one statement.

If you have parameters, you pass them inside the parentheses:

What About ?

The handling of is also different in arrow functions compared to regular functions.

In short, with arrow functions there are no binding of .

In regular functions the keyword represented the object that called the function, which could be the window, the document, a button or whatever.

With arrow functions, the keyword always represents the object that defined the arrow function.

Let us take a look at two examples to understand the difference.

Both examples call a method twice, first when the page loads, and once again when the user clicks a button.

The first example uses a regular function, and the second example uses an arrow function.

The result shows that the first example returns two different objects (window and button), and the second example returns the Header object twice.

Example

With a regular function, represents the object that called the function:

Example

With an arrow function, represents the Header object no matter who called the function:

Remember these differences when you are working with functions. Sometimes the behavior of regular functions is what you want, if not, use arrow functions.

One-Way Data Flow

All props form a one-way-down binding between the child property and the parent one: when the parent property updates, it will flow down to the child, but not the other way around. This prevents child components from accidentally mutating the parent’s state, which can make your app’s data flow harder to understand.

In addition, every time the parent component is updated, all props in the child component will be refreshed with the latest value. This means you should not attempt to mutate a prop inside a child component. If you do, Vue will warn you in the console.

There are usually two cases where it’s tempting to mutate a prop:

  1. The prop is used to pass in an initial value; the child component wants to use it as a local data property afterwards. In this case, it’s best to define a local data property that uses the prop as its initial value:

    props: ,data: function () {  return {    counter: this.initialCounter  }}
  2. The prop is passed in as a raw value that needs to be transformed. In this case, it’s best to define a computed property using the prop’s value:

    props: ,computed: {  normalizedSize: function () {    return this.size.trim().toLowerCase()  }}

Note that objects and arrays in JavaScript are passed by reference, so if the prop is an array or object, mutating the object or array itself inside the child component will affect parent state.

Getting Started

Example Sandbox

If you want to dive right in and start playing with single-file components, check out this simple todo app on CodeSandbox.

For Users New to Module Build Systems in JavaScript

With components, we’re entering the realm of advanced JavaScript applications. That means learning to use a few additional tools if you haven’t already:

  • Node Package Manager (NPM): Read the Getting Started guide section about how to get packages from the registry.

  • Modern JavaScript with ES2015/16: Read through Babel’s Learn ES2015 guide. You don’t have to memorize every feature right now, but keep this page as a reference you can come back to.

After you’ve taken a day to dive into these resources, we recommend checking out Vue CLI 3. Follow the instructions and you should have a Vue project with components, ES2015, Webpack and hot-reloading in no time!

For Advanced Users

The CLI takes care of most of the tooling configurations for you, but also allows fine-grained customization through its own config options.

In case you prefer setting up your own build setup from scratch, you will need to manually configure webpack with vue-loader. To learn more about webpack itself, check out their official docs and Webpack Academy.

##company## — ##description##

Edit this on GitHub! Netlify

Извлечение компонентов

Не бойтесь разделить компоненты на более мелкие компоненты. Например, рассмотрим компонент Comment:

function Comment(props) {
  return (
    <div className="Comment">
      <div className="UserInfo">
        <img className="Avatar"
          src={props.author.avatarUrl}
          alt={props.author.name}
        />
        <div className="UserInfo-name">
          {props.author.name}
        </div>
      </div>
      <div className="Comment-text">
        {props.text}
      </div>
      <div className="Comment-date">
        {formatDate(props.date)}
      </div>
    </div>
  );
}

Он принимает (объект), (строку) и (дату) в качестве props и описывает комментарий социальной сети. Этот компонент сложно изменить из-за всех вложенных элементов, а также трудно повторно использовать отдельные его части. Давайте извлечем из него несколько компонентов. Во-первых, мы извлечем:

function Avatar(props) {
  return (
    <img className="Avatar"
      src={props.user.avatarUrl}
      alt={props.user.name}
    />

  );
}

не должен знать, что он отображается внутри. Вот почему мы передали в props более общее параметры:, вместо . Мы рекомендуем называть protps с точки зрения компонента, а не контекста, в котором он используется. Теперь мы можем упростить:

function Comment(props) {
  return (
    <div className="Comment">
      <div className="UserInfo">
        <Avatar user={props.author} />
        <div className="UserInfo-name">
          {props.author.name}
        </div>
      </div>
      <div className="Comment-text">
        {props.text}
      </div>
      <div className="Comment-date">
        {formatDate(props.date)}
      </div>
    </div>
  );
}

Затем мы извлечем компонент, который выводит  рядом с именем пользователя:

function UserInfo(props) {
  return (
    <div className="UserInfo">
      <Avatar user={props.user} />
      <div className="UserInfo-name">
        {props.user.name}
      </div>
    </div>
  );
}

Это позволяет нам упростить еще больше:

function Comment(props) {
  return (
    <div className="Comment">
      <UserInfo user={props.author} />
      <div className="Comment-text">
        {props.text}
      </div>
      <div className="Comment-date">
        {formatDate(props.date)}
      </div>
    </div>
  );
}

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

Named Slots

There are times when it’s useful to have multiple slots. For example, in a component with the following template:

For these cases, the element has a special attribute, , which can be used to define additional slots:


A outlet without implicitly has the name “default”.

To provide content to named slots, we can use the directive on a , providing the name of the slot as ‘s argument:

Now everything inside the elements will be passed to the corresponding slots. Any content not wrapped in a using is assumed to be for the default slot.

However, you can still wrap default slot content in a if you wish to be explicit:

Either way, the rendered HTML will be:

Note that can only be added to a (with ), unlike the deprecated .

Component Names

When registering a component, it will always be given a name. For example, in the global registration we’ve seen so far:

The component’s name is the first argument of .

The name you give a component may depend on where you intend to use it. When using a component directly in the DOM (as opposed to in a string template or single-file component), we strongly recommend following the for custom tag names (all-lowercase, must contain a hyphen). This helps you avoid conflicts with current and future HTML elements.

You can see other recommendations for component names in the .

With kebab-case

When defining a component with kebab-case, you must also use kebab-case when referencing its custom element, such as in .

With PascalCase

When defining a component with PascalCase, you can use either case when referencing its custom element. That means both and are acceptable. Note, however, that only kebab-case names are valid directly in the DOM (i.e. non-string templates).

How to Depend on This Package?

For apps, we recommend putting it in with a caret range. For example:

"dependencies"{"prop-types""^15.5.7"}

For libraries, we also recommend leaving it in :

"dependencies"{"prop-types""^15.5.7"},"peerDependencies"{"react""^15.5.0"}

Note: there are known issues in versions before 15.5.7 so we recommend using it as the minimal version.

Make sure that the version range uses a caret () and thus is broad enough for npm to efficiently deduplicate packages.

For UMD bundles of your components, make sure you don’t include in the build. Usually this is done by marking it as an external (the specifics depend on your bundler), just like you do with React.

Что такое функция рендеринга?

Каждый компонент Vue реализует функцию рендеринга. В большинстве случаев функция создается компилятором Vue. Когда вы определяете шаблон (template) для вашего компонента, содержимое этого шаблона обрабатываться компилятором Vue (Vue.compile()), который возвращает функцию рендеринга. Функция рендеринга по существу возвращает виртуальный узел DOM, который будет визуализирован Vue в DOM вашего браузера.

Хорошо, а что такое виртуальный DOM?

Виртуальная объектная модель документа (или «DOM») позволяет Vue визуализировать ваш компонент в его памяти перед обновлением браузера. В виртуальном DOM это делается быстрее, потому что, в нем нет прямого взаимодействия с DOM браузером. Когда Vue обновляет DOM вашего браузера, он сравнивает обновленный виртуальный DOM с его предыдущим состоянием и обновляет в реальном DOM только те части, которые были изменены.

Функция рендеринга возвращает виртуальный узел DOM, обычно называемый VNode в экосистеме Vue, который является интерфейсом, который позволяет Vue записывать эти объекты в DOM вашего браузера. Они содержат всю информацию, необходимую для работы с Vue. Следующая версия Vue будет включать в себя совершенно новую виртуальную реализацию DOM, которая будет еще быстрее, чем сейчас. React, Riot, Inferno и многие другие также используют концепцию Virtual DOM.

Это изображение было найдено и изменено из статьи Майкла Галлахера Low Verbosity i18n

Более подробно о виртуальном DOM можно почитать тут

Вы можете реализовать свою функцию рендеринга Vue в любом компоненте Vue. Также, учитывая реактивность Vue, функция рендеринга будет вызываться всякий раз, когда реактивное свойство компонента будет обновлено. Вот краткий пример того, как можно визуализировать тег H1 непосредственно из функции рендеринга компонента:

new Vue({
  el: '#app',
  render(createElement) {
    return createElement('h1', 'Hello world');
  }
});

Есть некоторые встроенные компоненты, которые используют все мощь функций рендеринга, таких как transition и keep-alive. Эти компоненты управляют VNodes непосредственно в функции рендеринга.

# trigger

Triggers an event asynchronously on the DOM node.

takes an optional object. The properties in the object are added to the Event. returns a Promise, which when resolved, guarantees the component is updated. only works with native DOM events. To emit a custom event, use

  • Arguments:

    • required
    • optional
  • Example:

Setting the event target:


Under the hood, creates an object and dispatches the event on the Wrapper element.

It’s not possible to edit the value of an object, so you can’t set in the options object.

To add an attribute to the , you need to set the value of the Wrapper element before calling . You can do this with the property.

Реальный сценарий использования переопределения шаблонов

Я думаю, что очень интересно понять, как Vue работает под капотом. Как говориться, единственный способ узнать, используете ли вы инструмент наиболее эффективно, — это точно знать, как он работает.

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

В приведенном примере я покажу вам, как использовать пользовательскую функцию рендеринга в компоненте.

Сначала давайте создадим нашу начальную разметку.

<div id="app">
  <heading>
    <span>Heading title is: {{ title }}</span>
  </heading>
</div>

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

Первое, что мы сделаем, это просканируем пользовательские шаблоны и предварительно скомпилируем их с помощью компилятора Vue:

const templates = [];
const templatesContainer = document.getElementById('app');

// We iterate through each custom templates and precompile them
for (var i = 0; i < templatesContainer.children.length; i++) {
  const template = templatesContainer.children.item(i);
  templates.push({
    name: template.nodeName.toLowerCase(),
    renderFunction: Vue.compile(template.innerHTML),
  });
}

Затем давайте создадим компонент heading:

Vue.component('heading', {
  props: ,
  template: `
  <overridable name="heading">
    <h1>
      {{ title }}
    </h1>
  </overridable>`
});

Это просто простой компонент, который имеет входящее props с именем title. Шаблон по умолчанию будет отображать тег h1 с title. Этот компонент будет состоять из компонента overridable, который мы создадим.

В нем мы будем использовать пользовательскую функцию рендеринга.

Vue.component('overridable', {
  props: ,
  render(createElement) {
    // We use the templates array we created when the application was initialized.
    const template = templates.find(x => x.name === this.name);

    // We return the default content using the default slot when there are no custom templates.
    if (!template) {
      return this.$slots.default;
    }
    
    // Using the precompiled render function
    return template.renderFunction.render.call(this.$parent, createElement);
  }
});

Затем смонтируем наше приложение Vue:

new Vue({
  el: '#app',
  template: `<heading title="Hello world"></heading>`
});

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

Если мы добавим пользовательский шаблон в div#app, то увидим, что компонент heading теперь будет отображать пользовательский шаблон, который мы указали.

createElement Arguments

The next thing you’ll have to become familiar with is how to use template features in the function. Here are the arguments that accepts:

The Data Object In-Depth

One thing to note: similar to how and have special treatment in templates, they have their own top-level fields in VNode data objects. This object also allows you to bind normal HTML attributes as well as DOM properties such as (this would replace the directive):

VNodes Must Be Unique

All VNodes in the component tree must be unique. That means the following render function is invalid:

If you really want to duplicate the same element/component many times, you can do so with a factory function. For example, the following render function is a perfectly valid way of rendering 20 identical paragraphs:

Prop Validation

Components can specify requirements for its props. If a requirement isn’t met, Vue will warn you in the browser’s JavaScript console. This is especially useful when developing a component that’s intended to be used by others.

To specify prop validations, you case provide an object with validation requirements to the value of , instead of an array of strings. For example:

Vue.component('my-component', {  props: {    propA: Number,    propB: ,    propC: {      type: String,      required: true    },    propD: {      type: Number,      default: 100    },    propE: {      type: Object,      default: function () {        return { message: 'hello' }      }    },    propF: {      validator: function (value) {        return .indexOf(value) !== -1      }    }  }})

When prop validation fails, Vue will produce a console warning (if using the development build).

Note that props are validated before a component instance is created, so instance properties (e.g. , , etc) will not be available inside or functions.

Type Checks

The can be one of the following native constructors:

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

In addition, can also be a custom constructor function and the assertion will be made with an check. For example, given the following constructor function exists:

function Person (firstName, lastName) {  this.firstName = firstName  this.lastName = lastName}

You could use:

Vue.component('blog-post', {  props: {    author: Person  }})

to validate that the value of the prop was created with .


С этим читают