Компоненты - это способ написания модульного многоразового кода для вашего приложения Vue.js. Компоненты можно рассматривать как настраиваемые элементы HTML, которые могут использоваться вашим основным Vue экземпляром и / или другими компонентами. Их также можно рассматривать как мини- или под- Vue экземпляры.

Чтобы создать компонент, вы можете зарегистрировать его глобально с помощью метода component конструктора Vue.

Vue.component('some-component', {
    /* data, methods, etc. go here */
});

Первый аргумент - это строка для использования в качестве имени компонента. Вы используете имя как имя тега в вашем HTML для визуализации компонента.

<some-component></some-component>

Принято, что имя должно быть полностью строчными и иметь дефисы, разделяющие слова (kebab-case).

Второй аргумент - это объект конфигурации, который вы также передаете конструктору Vue. Практически все, что можно передать конструктору Vue, можно передать и Vue.component. Двумя важными исключениями являются el и data.

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

При необходимости вы передаете data, но он принимает другую форму, чем data, который вы передаете конструктору Vue. Вместо того, чтобы быть объектом, data, который вы передаете Vue.component, должен быть функцией, возвращающей объект.

Vue.component('some-component', {
    data: function() {
        return {
            heading: 'Some Component'
        };
    }
});

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

Шаблоны

Есть несколько способов указать шаблон для компонента.

Один из способов - поместить содержимое шаблона внутрь тега самого компонента. Чтобы это работало, вам нужно добавить к тегу атрибут с именем inline-template.

<some-component inline-template>
    <div>
        <h1>{{heading}}</h1>
        <p>This is a component</p>
    </div>
</some-component>

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

Другой вариант - использовать тег <script> для вашего шаблона.

<some-component></some-component>
<script id="some-template" type="text/x-template">
<div>
    <h1>{{ heading }}</h1>
    <p>This is a component!!!</p>
</div>
</script>
Vue.component('some-component', {
    data: function() {
        return {
            heading: 'Some Component'
        };
    },
    template: '#some-template'
});

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

Vue.component('some-component', {
    data: function() {
        return {
            heading: 'Some Component'
        };
    },
    template: '<h1>{{heading}}</h1>'
});

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

props

Данные могут быть переданы компонентам как настраиваемые атрибуты. Эти данные обозначаются как props в терминологии Vue.js. Чтобы передать опору компоненту, вы должны объявить для него имя, указав его в массиве с именем props.

<div id="main">
    <ul>
        <li v-for="city in cities">
            <individual-city v-bind:id="city.id" v-bind:name="city.name" v-bind:country="city.country"></individual-city>
        </li>
    </ul>
</div>
Vue.component('individual-city', {
    props: ['id', 'name', 'country'],
    template: '<span>{{name}}, {{country}}</span>'
});

new Vue({
    el: '#main',
    data: {
        cities: [
            {
                id: 1,
                name: 'Berlin',
                country: 'Germany'
            },
            {
                id: 2,
                name: 'Hamburg',
                country: 'Germany'
            }
        ]
    }
});

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

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

Если компонент действительно изменяет значение одного из своих свойств, и этот параметр является примитивным значением, соответствующее свойство родительского элемента не изменится. Неспособность компонента изменить своего родителя является преднамеренной. Гарантируя, что данные передаются в одном направлении - от родителя к компоненту - Vue.js устраняет множество потенциальных путаниц.

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

<div id="main">
    <ul>
        <li v-for="city in cities">
            <strong>Component for {{city.name}}:</strong>
            <individual-city
                  v-bind:id="city.id"
                  v-bind:name="city.name"
                  v-bind:country="city.country"
                  v-on:changed="updateCityName"></individual-city>
        </li>
    </ul>
</div>
Vue.component('individual-city', {
        props: ['id', 'name', 'country'],
        methods: {
            changed: function(e) {
                this.$emit('changed', this.id, e.target.value);
            }
        },
        template:
            '<span>{{name}}, {{country}} <input v-bind:value="name" v-on:input="changed"></span>'
    });

    new Vue({
        el: '#main',
        data: {
            cities: [
                {
                    id: 1,
                    name: 'Berlin',
                    country: 'Germany'
                },
                {
                    id: 2,
                    name: 'Hamburg',
                    country: 'Germany'
                }
            ]
        },
        methods: {
            updateCityName: function(id, name) {
                for (var i = 0; i < this.cities.length; i++) {
                    if (this.cities[i].id == id) {
                        this.cities[i].name = name;
                        return;
                    }
                }
            }
        }
    });

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

Спасибо за чтение!

Примечание из JavaScript In Plain English

Мы запустили три новых издания! Проявите любовь к нашим новым публикациям, подписавшись на них: AI на простом английском, UX на простом английском, Python на простом английском - спасибо и продолжайте учиться!

Мы также всегда заинтересованы в содействии продвижению качественного контента. Если у вас есть статья, которую вы хотите отправить в какую-либо из наших публикаций, отправьте нам электронное письмо по адресу [email protected] с вашим именем пользователя Medium, и мы добавим вас в качестве автора. Также сообщите нам, к каким публикациям вы хотите быть добавлены.