【问题标题】:2-way data binding in native web components本机 Web 组件中的 2 路数据绑定
【发布时间】:2014-11-10 14:05:20
【问题描述】:
我一直在阅读有关 Web 组件的内容,并且对新生规范非常感兴趣。有谁知道 DOM 中是否支持 2 路数据绑定,而不必使用 Polymer?一个例子将不胜感激。
【问题讨论】:
-
你可以试试Slim.js。我不是一个大粉丝。我仍在寻找解决问题的好方法,同时避免使用任何库(我厌倦了一个接一个地学习 DSL)。到目前为止,我的方法是 init() 使用模板字符串和 update(),老式的,类似于 D3 图表。
标签:
html
web-component
2-way-object-databinding
【解决方案1】:
Object.observe 是一种在 javascript 中进行数据绑定的潜在新方法。此功能计划用于 Ecmascript 7(javascript),但目前一些浏览器支持它,请查看 here。另请查看关于 object.observe 的 html5rocks 文章
【解决方案2】:
不,数据绑定不是 Web 组件规范的一部分。
您当然可以使用本机 JavaScript event listeners 和可能的 Proxy 对象自己实现数据绑定,但最好不要重新发明轮子:如果您想要数据绑定,请选择众多 JavaScript 中的一种支持这一点的框架。 Polymer、React、Angular 和 Vue 是此类库的一些最新示例。
【解决方案3】:
过去几天我一直在玩这个。您可以创建一个 StateObserver 类,并从中扩展您的 Web 组件。一个最小的实现如下所示:
// create a base class to handle state
class StateObserver extends HTMLElement {
constructor () {
super()
StateObserver.instances.push(this)
}
stateUpdate (update) {
StateObserver.lastState = StateObserver.state
StateObserver.state = update
StateObserver.instances.forEach((i) => {
if (!i.onStateUpdate) return
i.onStateUpdate(update, StateObserver.lastState)
})
}
}
StateObserver.instances = []
StateObserver.state = {}
StateObserver.lastState = {}
// create a web component which will react to state changes
class CustomReactive extends StateObserver {
onStateUpdate (state, lastState) {
if (state.someProp === lastState.someProp) return
this.innerHTML = `input is: ${state.someProp}`
}
}
customElements.define('custom-reactive', CustomReactive)
class CustomObserved extends StateObserver {
connectedCallback () {
this.querySelector('input').addEventListener('input', (e) => {
this.stateUpdate({ someProp: e.target.value })
})
}
}
customElements.define('custom-observed', CustomObserved)
<custom-observed>
<input>
</custom-observed>
<br />
<custom-reactive></custom-reactive>
fiddle here
我喜欢这种方法,因为它直接发生在您想要与之通信的那些元素之间,无需通过 dom 遍历来查找 data- 属性或其他任何内容。
【解决方案4】:
一种方式:$0.model = {data}; $0 上的 setter 分配 $0.data,响应更新,另一种方式:$1.dispatchEvent(new CustomEvent('example', {detail: $1.data, cancelable: true, composed: true, bubbles: true})); 和 $0.addEventListenever('example', handler) 提供 2 路数据绑定。数据对象是相同的,在 2 个元素上共享,事件和设置器允许响应更新。为了拦截对对象的更新,代理可以使用model = new Proxy(data, {set: function(data, key, value){ data[key] = value; ...respond... return true; }}) 或other techniques。这解决了简单的场景。你也可以考虑查看和阅读 Redux 的源代码,它提供了看起来比较流行的约定。正如 Ajedi32 提到的那样,为更复杂的场景重新发明轮子并不是那么实际,除非它是一种学术兴趣。