【发布时间】:2015-07-21 02:54:18
【问题描述】:
助焊剂架构是 Web 应用程序的趋势,聚合物元素也是如此。
是否有任何示例如何制作使用助焊剂架构的聚合物应用?
【问题讨论】:
助焊剂架构是 Web 应用程序的趋势,聚合物元素也是如此。
是否有任何示例如何制作使用助焊剂架构的聚合物应用?
【问题讨论】:
我一直在考虑将 Flux 模式与(聚合物)Web 组件一起使用。到目前为止,我已经提出了三种可能的解决方案,都与你的方式不同,所以它们是:
免责声明我使用 Reflux 库而不是 Facebook 的库。
我的第一次尝试是将 Flux 模式制作成元素,以便任何需要访问商店并调用操作的视图都可以简单地导入它们。
<dom-module id="a-view">
<template>
<my-actions id="actions"></my-actions>
<my-store model="{{model}}"></my-store>
<span>{{model.property}}</span>
<button on-click="executeAction"></button>
</template>
</dom-module>
<script>
Polymer({
is: 'a-view',
executeAction: function() {
this.$.actions.doSomething({});
}
});
</script>
<my-actions> 和<my-store> 只是封装了动作和存储。这种方法有一些缺点。首先,可能会创建许多非视觉元素,这会对性能产生不利影响。如果它们应该是 Polymer 元素,那么创建这些元素也可能会很棘手,因为它们需要静态。完整示例见this repo
最近我再次意识到 Web 组件的真正含义。使用 WC,您的主要 API 是浏览器,即元素、属性和事件。而 Flux 本质上是一个事件驱动的数据流。那么为什么不使用Custom Events 在自定义元素之间进行通信呢?这是我的yesterday's plunk的摘录
<template is="dom-bind">
<a-view clicks="[[clicks]]" id="one"></a-view>
<a-view clicks="[[clicks]]" id="two"></a-view>
<a-view clicks="[[clicks]]" id="three"></a-view>
<a-store click-history="{{clicks}}"></a-store>
</template>
<script>
Polymer({
is: 'a-view',
properties: { clicks: Object },
fireClick: function() {
// invoking action is simply firing an event
this.fire('a-view-click', {});
}
});
Polymer({
is: 'a-store',
attached: function(){
document.addEventListener('a-view-click', function(ev) {
// do work and update store here
}.bind(this));
}
});
</script>
这很好,因为不限于 Polymer。可以使用本机 API 或其他库创建自定义元素,并且只需与充当调度程序的浏览器进行通信。当然,这并没有为您提供开箱即用的同步方式,而是一种简单而干净的方式,没有任何混乱。
正如您将在 Plunker 上看到的,通过数据绑定存储更新。另一种可能性是触发另一个事件,但我不确定哪个会更好或何时
最后,我刚刚有了一个想法,它在第一个的基础上进行了改进,将操作/存储自定义元素替换为行为。目前还没有代码,但这里有一个草图:
var MyActionsBehaviour = PolymerFlux.createActions({ /*...*/ });
var MyStore = PolymerFlux.createStore({ /*...*/ });
Polymer({
is: 'a-view',
behaviours: [ MyActionsBehaviour, MyStore ],
onClick: function() {
this.behaviourAction.invoke({});
}
}});
Polymer({
is: 'a-store',
behaviours: [ MyActionsBehaviour, MyStore ],
attached: function() {
this.behaviourAction.listen(function() {
// 1. do work
// 2. update views
});
}
}});
我将视图更新部分留空。它可能通过发出事件信号来发生,但另一种可能性是触发另一个动作(Reflux 有一个很好的概念 nested actions)。另外,我目前将PolymerFlux.createActions 和PolymerFlux.createStore 留给您的想象力;)。确切的内部结构取决于您选择的 Flux 实现。
【讨论】:
我尝试在聚合物应用中使用助焊剂型架构。
这里是main-app.html:
<link rel="import" href="./bower_components/polymer/polymer.html">
<link rel="import" href="store-cart.html">
<link rel="import" href="store-cart2.html">
<link rel="import" href="view-cart.html">
<link rel="import" href="view-additems.html">
<dom-module id="main-app">
<style>
</style>
<template>
<!-- Stores-->
<store-cart id="cart1" action=[[action]]></store-cart>
<store-cart2 id="cart2" action=[[action]]></store-cart2>
<!--Views and other stuff-->
<view-additems cart="cart1"></view-additems>
<view-additems cart="cart2" add="3"></view-additems>
<view-cart update="[[updateView]]"></view-cart>
</template>
</dom-module>
<script>
Polymer({
is: 'main-app',
properties: {
action: {
type: Object,
value: {}
},
updateView: {
value: ""
}
},
listeners: { //dispatcher event -> action
'viewAction': 'viewAction', // Action from view to be dispatched to the store/stores
'storeUpdated': 'storeUpdated' // storeUpdated-event from store to views
},
viewAction: function(e) {
action = e.detail;
switch (action.type) {
// "CombineCarts" is needed because both of the stores needs to be updated in order
case 'combineCarts':
this.$.cart1.addItems(this.$.cart2.nbItems);
this.$.cart1.updateViews();
this.$.cart2.emptyCart();
this.$.cart2.updateViews();
break;
// default action when store/stores can be updated independently
default:
this.action = action;
}
},
storeUpdated: function(e) {
this.updateView = e.detail;
}
});
</script>
整个例子:https://github.com/grohjy/polymer_flux_example
主要思想是“调度程序”位于聚合物应用程序的最顶层,它的作用是将消息从商店重定向到视图,反之亦然。每个商店和视图都定义了它们对哪些消息做出反应以及如何做出反应。在调度程序中,还有一个示例如何按需要的顺序更新多个商店。
商店和一些视图也位于应用程序的最顶层。一个视图也可以有子视图。商店不应该有任何视觉 dom 元素。
请随时发表评论和分享想法。
【讨论】: