Для чего нужны «значения по умолчанию» для импорта / экспорта в объекте uiElement?

8

Во многих конструкторах модели представления пользовательского интерфейса Magento 2 defaultsмассив будет иметь свойство importsили exports.

return Collection.extend({
    defaults: {
        //...
        imports: {
            rows: '${ $.provider }:data.items'
        },

return Insert.extend({
    defaults: {
        //...
        exports: {
            externalFiltersModifier: '${ $.externalProvider }:params.filters_modifier'
        },

Глядя на источник uiElementмодуля,

#File: vendor/magento/module-ui/view/base/web/js/lib/core/element/element.js
    initLinks: function () {
        return this.setListeners(this.listens)
                   .setLinks(this.links, 'imports')
                   .setLinks(this.links, 'exports')
                   .setLinks(this.exports, 'exports')
                   .setLinks(this.imports, 'imports');
    },

Этот импорт / экспорт, похоже, как-то связан с «связыванием» информации между объектами при создании экземпляра объекта. Однако неясно, как работает эта связь (на основе uiRegistry?) Или каков синтаксис для строк ${ $.provider }:data.items. Понятно, что в этих строках используются литералы шаблонов, которые расширяются в нечто вроде

foo_bar:data.items

Но смысл этой последней строки все еще остается загадочным.

Кто-нибудь знает, как работают свойства импорта / экспорта этих объектов?

Алан Сторм
источник
Не отправить ответ , так как я на самом деле не использовал их, но devdocs дать немного больше понимания: devdocs.magento.com/guides/v2.1/ui-components/...
Vinai

Ответы:

21

Эти свойства позволяют компонентам соединяться, чтобы они могли взаимодействовать друг с другом. Принцип несколько прост: импортировать (принимать) значение из другого компонента или экспортировать (отправлять) значение в другой компонент, или делать то и другое.


Примечание: для ясности в этом ответе «компонент» - это объект Javascript, который возвращается RequireJS, имеет определенное имя и может быть доступен по этому имени через UIRegistry.

Кроме того, все приведенные ниже примеры будут находиться внутри defaults: {}свойства компонента.


С изложенным принципом давайте начнем с того, что я считаю самой простой концепцией:

импорт

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

imports: {
    message: '${ $.provider }:data.message'
}

Когда Magento инициализирует этот компонент, он попытается присвоить значение messageсвойству. Это свойство будет доступно в контексте KnockoutJS. Однако, как мы знаем , он imports.messageсначала оценит значение как буквенное выражение шаблона. В этом случае Magento проанализирует $.providerи должен получить значение. Хотя это может быть любое количество вещей, в этом примере и согласно многим основным сценариям использования Magento, это имя компонента, которое находится в реестре пользовательского интерфейса. Это будет проанализировано до следующего шага.

Поскольку messageсвойство находится в importsсвойстве, оно будет передано setLinks()методу в uiElement.initLinks(). setLinks()Метод в Magento/Ui/view/base/web/js/lib/core/element/links.js. Там он перебирает все свойства (только messageздесь) в объекте, который был передан ( importsв данном случае). На этих свойствах он будет пытаться передать данные из одного компонента в другой.

transfer()Функция является следующим местом интереса. Здесь в реестре выполняется поиск компонента, который является «владельцем», в случае импорта. Этот компонент является тем, который в настоящее время «владеет» или имеет данные и будет $.providerв приведенном выше примере. Если компонент найден, он продолжит связывать данные с setLink()функцией.

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

Затем данные устанавливаются на (или, проще говоря: «возвращено») компоненту, у которого было imports: {}свойство. Как я упоминал ранее, он затем присваивается непосредственно объявленному свойству компонента - по существу, this.messageв приведенном выше примере, а не так this.defaults.imports.message. В результате data-bind="text: messageдолжно отображаться значение, возвращаемое из data.messageсвойства связанного компонента .

Этот подход позволяет определить, какое имя свойства содержится в исходном компоненте. В приведенном выше примере вы можете использовать alertMessage: ...вместо имени messageсвойства вашего компонента.

экспорт

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

exports: {
    phoneNumber: '${ $.contactForm }:phone'
}

В этом примере setLinks()принимает значение свойства этого компонентаphoneNumber и присваивает его phoneсвойству формы контакта . Это то же самое, что явно объявить phoneсвойство в $.contactFormкомпоненте. Без какой-либо конкретной настройки в $.contactForm, вы можете получить доступ к этим данным напрямую. Возможно, так в шаблоне нокаута data-bind="text: phone.

связи

Наконец, linksсвойство такое же, как объявление обоих importsи exportsдля одного и того же свойства. На первый взгляд это может показаться круговой ссылкой. Хотя в некотором смысле это может быть полезным. Хотя я уверен, что есть еще много вариантов использования, я вижу, что один компонент может динамически манипулировать данными из другого компонента. В этом случае ComponentA является источником некоторых данных и отображает их на странице. Компонент B должен манипулировать этими данными и таким образом обращаться linksк этому свойству. Он может как отображать данные, так и манипулировать фактическими данными в ComponentA, не расширяя и не изменяя ComponentA.

Однако следует отметить, что по умолчанию linksэто не способ соединения двух других модулей. Другими словами, ComponentC не может от linkComponentA до ComponentB. Это метод двунаправленной синхронизации одного компонента с другим.


Связывание ( imports, exportsи links) почти всегда может облегчить функции , возложенные на эти свойства , а также. Я столкнулся с каким-то странным поведением, создавая наблюдаемые и используя, linksно в целом это работало довольно хорошо.

Связывание предоставляет значения, которые доступны в области действия KnockoutJS и могут управляться так же, как и любое другое свойство. И, чтобы подтвердить ясно: помните , что imports, exportsи linksобъект ключи всегда относятся к свойствам компонента тока (тот , в котором были объявлены эти свойства), в то время как значение относится к имени и свойствам удаленного компонента .


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

bassplayer7
источник
Отличное объяснение @ bassplayer7 - У вас есть примеры этого? Я понимаю, как это работает, но ради жизни я не могу заставить два моих простых компонента пользовательского интерфейса разделить наблюдаемую нокаут.
Бен Крук
@BenCrook, к сожалению, я уже давно ничего с этим не сделал, так что у меня ничего нет. Теперь я уверен , что вы поняли это, но я предлагаю работать с importsи exportsвместо links. Я нашел, linksчтобы быть более неясным и хрупким. Если вы сталкивались с примером, не могли бы вы поделиться ссылкой?
bassplayer7
Я попытался и не смог заставить работать импорт / экспорт / ссылки, Vinai ответил здесь на вопрос, хотя у меня еще не было возможности попробовать это.
Бен Крук
Эта информация будет полезна для официальных разработчиков документации. Процесс пользовательского интерфейса - просто страшный зверь.
Натаниэль Роджерс