Как разделить наблюдаемые компоненты Knockout JS между компонентами пользовательского интерфейса

12

Я понимаю, как использовать imports: {}иexports: {} делиться свойствами компонентов пользовательского интерфейса, такими как:

defaults: {
    exports: {
        shouldShowMessage: '${$.component}'
    }
}

Который возвращает имя компонента в экспорте.

введите описание изображения здесь

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

defaults: {
    exports: {
        shouldShowMessage: '${$.shouldShowMessage}'
    }
}

...

setupKoBindings: function() {
    this.shouldShowMessage = ko.observable('Testing');
}

введите описание изображения здесь

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

Бен Крук
источник

Ответы:

12

Значения объекта экспорта должны соответствовать имени и свойству экземпляра UiComponent, разделенных, например, знаком «:» checkout.cart.total:title.
Имя цели экспорта должно включать компонент пространства имен интерфейса пользователя.

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

Вот пример, который работает:

defaults: {
    exportTarget: "foo.bar",
    exportTargetProperty: "showMessage",

    tracks: {
        shouldShowMessage: true
    },

    exports: {
        shouldShowMessage: '${$.exportTarget}:${$.exportTargetProperty}'
    }
}
...

Выше будет копировать значение shouldShowMessageсвойства в свойство showMessageUiComponent с полным именем foo.barкаждый раз, когда значение изменяется.
Обратите внимание, что это автоматически не сделает целевое свойство также наблюдаемым. Это должно быть объявлено в явном виде, если изменение значения должно привести к тому, что KO повторно отобразит узлы DOM, которые обращаются к этому свойству.

Кстати, добавление shouldShowMessageк tracksобъекту сделает его автоматически видимым в ko-es5. Использование буквальных ko.observable()произведений тоже.

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

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

Vinai
источник
Отличное объяснение, спасибо @Vinai! Я попробую, когда у меня будет время, и отметлю это как принятое, если это сработает.
Бен Крук
Я столкнулся с некоторыми проблемами при использовании tracks, ручная подписка на observables больше не работает this.shouldShowMessage.subscribe is not a functionпри использовании. this.shouldShowMessage.subscribe(function() { ... }); Это прекрасно работает при установке observables любым другим способом. Такое ощущение, что я пропускаю шаг или tracksне создаю наблюдаемое таким же образом.
Бен Крук
Вы правы, свойства больше не являются обычными ko наблюдаемыми, только пары ES5 getter / setter. Если вы хотите получить доступ к исходной наблюдаемой функции, вы можете ввести ko и использовать ko.getObservable(this, 'shouldShowMessage').subscribe(function(newValue) { ...});(первый аргумент - viewmodel ( this), а второй - имя отслеживаемого свойства. Подробнее здесь: github.com/SteveSanderson/knockout-es5
Vinai).
Ах, это имеет смысл, ты лучший <3
Бен Крук
1
После того, как я поигрался с импортом и экспортом, но все еще потерпел неудачу, я согласен, что это код спагетти, я отказался и буду придерживаться ручных подписок и модели хранилища.
Бен Крук