从 DOM 中删除并再次插入后如何更新聚合物元素绑定
Posted
技术标签:
【中文标题】从 DOM 中删除并再次插入后如何更新聚合物元素绑定【英文标题】:How to update polymer element bindings after it was removed from DOM and inserted again 【发布时间】:2014-01-15 07:41:33 【问题描述】:假设我们有容器聚合物元素和另一个虚拟聚合物元素。容器聚合物元素具有用于插入其他聚合物的 div 块。
container_polymer.html
<polymer-element name='container-polymer'>
<template>
<div id="container">
</div>
<button on-click="first">show first</button>
<button on-click="firstPrepared">show first prepared</button>
<button on-click="second">show second</button>
</template>
<script type="application/dart" src="container_polymer.dart">
</script>
</polymer-element>
有三个用于插入虚拟聚合物的按钮:
-
第一个按钮将第一个虚拟聚合物插入容器。
第二个按钮也插入第一个虚拟聚合物,并调用
prepareElement()
在这种聚合物上。
第三个按钮将第二个虚拟聚合物插入容器中
container_polymer.dart
import 'package:polymer/polymer.dart';
import 'dart:html';
import 'dummy_polymer.dart';
@CustomTag('container-polymer')
class ContainerPolymer extends PolymerElement
PolymerElement firstPolymer, secondPolymer, currentPolymer;
Element container;
ContainerPolymer.created() : super.created();
void enteredView()
super.enteredView();
container = $['container'];
void first(Event e, var detail, Node target)
showFirst(false);
void firstPrepared(Event e, var detail, Node target)
showFirst(true);
void showFirst(bool prepare)
if (firstPolymer == null)
DummyPolymer dummyPolymer = new Element.tag("dummy-polymer");
dummyPolymer.title = "first";
firstPolymer = dummyPolymer;
if (currentPolymer != firstPolymer)
if (secondPolymer != null)
secondPolymer.remove();
if (prepare)
firstPolymer.prepareElement();
currentPolymer = firstPolymer;
container.children.add(firstPolymer);
void second(Event e, var detail, Node target)
if (currentPolymer != secondPolymer)
DummyPolymer dummyPolymer = new Element.tag("dummy-polymer");
dummyPolymer.title = "second";
secondPolymer = dummyPolymer;
if (firstPolymer != null)
firstPolymer.remove();
currentPolymer = secondPolymer;
container.children.add(secondPolymer);
虚拟聚合物具有几个可观察到的特性,可用于测试粘合效果。当您在该聚合物内部单击时,它会更改根 div 的背景颜色、标题 div 的背景颜色并增加计数器。它还具有用于检测聚合物元素状态是否已更改的输入,并带有白色背景的块以测试父样式的使用情况。
dummy_polymer.html
<polymer-element name='dummy-polymer'>
<template>
<div style="width: 500px; height: 300px; background-color: color" on-click="changeColor">
<div id="title">
<h1>title</h1>
<span>Clicks: clicks</span>
</div>
<input type="text" />
<div class="external">Parent style block: background should be white</div>
</div>
</template>
<script type="application/dart" src="dummy_polymer.dart">
</script>
</polymer-element>
dummy_polymer.dart
import 'package:polymer/polymer.dart';
import 'dart:html';
@CustomTag('dummy-polymer')
class DummyPolymer extends PolymerElement
@observable String color = "red";
@observable String title;
@observable num clicks = 0;
Element titleElement;
DummyPolymer.created() : super.created()
var root = getShadowRoot('dummy-polymer');
root.applyAuthorStyles = true;
void enteredView()
super.enteredView();
titleElement = $['title'];
void changeColor(Event e, var detail, Node target)
clicks++;
if (color == "red")
color = "green";
else if (color == "green")
color = "blue";
else
color = "red";
titleElement.style.backgroundColor = color;
测试页面托管在这里http://dart-style-binding-test.herokuapp.com/
所以,要重现我的问题,请执行以下操作:
-
单击“首先显示”按钮。确保单击内部会更改背景颜色并增加计数器。
在输入字段中输入内容
点击“显示第二个”
单击“首先显示”。确保第一个聚合物具有与以前相同的状态:背景颜色、计数器和输入字段文本。
在第一个聚合物内单击。现在它不会改变背景颜色和计数器,但会改变顶部区域的背景颜色。
绑定到可观察属性不再起作用。但是on-click
处理程序有效,您可以在顶部区域的背景颜色发生变化时看到它。它是通过直接改变元素的backgroundColor
属性来实现的:
titleElement.style.backgroundColor = color;
那么,我的问题是:如何在现有聚合物再次插入 DOM 后正确更新绑定机制?
有一种方法可以使用“显示第一个准备好的”按钮来处理它。在插入容器之前,它会在第一个元素上调用 prepareElement()
。因此,请执行以下操作:
-
单击“首先显示”按钮。确保单击内部会更改背景颜色并增加计数器。
在输入字段中输入内容
点击“显示第二个”
单击“显示首先准备好的”。您可以看到输入元素为空,但计数器和背景颜色是最新的。 (如果您在 dartium 中运行此演示,白色块也会将其背景颜色更改为父样式,因为父样式未应用)
在第一个聚合物内单击。现在它改变了背景颜色和计数器。绑定正常工作,但我们在输入字段中丢失了文本。
注意:在使用“显示第一个准备”按钮插入第一个元素后,即使在使用“显示第一个”按钮插入第一个元素后,绑定也能正常工作。
代码在这里https://github.com/petalvlad/dart-style-binding-test
【问题讨论】:
【参考方案1】:我自己没有尝试过,但它似乎是合理的。 希望作者不介意回复Detached observables when re-using element.
查看了 polymer.js 信息位后,我发现有一个 cancelUnbindAll 函数,必须在创建元素或将 preventDispose 属性设置为 true 时调用该函数。
对于任何可能需要这样做的人,在 Dart 实现中,您必须在 super 调用之后在分离的函数中调用 cancelUnbindAll,如下所示:
void detached()
super.detached();
this.cancelUnbindAll(preventCascade: true);
或者,您可以简单地覆盖自定义元素中的 preventDispose 属性:
bool get preventDispose => true;
【讨论】:
以上是关于从 DOM 中删除并再次插入后如何更新聚合物元素绑定的主要内容,如果未能解决你的问题,请参考以下文章
Angular - 如何从 DOM 中删除我使用过 $compile 的元素?