如何在从DOM中删除并再次插入后更新聚合物元素绑定

Ale*_*sky 6 dart dart-polymer

假设我们有容器聚合物元件和另一个虚设聚合物元件.容器聚合物元件具有用于插入另外聚合物的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>
Run Code Online (Sandbox Code Playgroud)

插入虚拟聚合物有三个按钮:

  1. 第一个按钮将第一个虚设聚合物插入容器
  2. 第二个按钮还插入第一个虚设聚合物,并调用 prepareElement()该聚合物.
  3. 第三按钮将第二虚设聚合物插入容器中

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);
    }
  }

}
Run Code Online (Sandbox Code Playgroud)

假聚合物具有几种可观察的性质,以测试粘合作用.当您在此聚合物内部单击时,它会更改根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>
Run Code Online (Sandbox Code Playgroud)

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;
  }

}
Run Code Online (Sandbox Code Playgroud)

此处托管的测试页面http://dart-style-binding-test.herokuapp.com/

因此,要重现我的问题,请执行以下操作:

  1. 点击"首先显示"按钮.确保单击内部更改背景颜色并增加计数器.
  2. 在输入字段中输入内容
  3. 点击"显示第二个"
  4. 点击"先显示".确保第一个聚合物具有与以前相同的状态:背景颜色,计数器和输入字段文本.
  5. 点击第一聚合物内部.现在它不会改变背景颜色和计数器,但它会改变顶部区域的背景颜色.

绑定到可观察的属性不再起作用.但是on-click处理程序工作,当顶部区域的背景颜色改变时,你可以看到它.它是通过backgroundColor直接更改元素的属性来实现的:

titleElement.style.backgroundColor = color;
Run Code Online (Sandbox Code Playgroud)

所以,我的问题是:如何在现有聚合物再次插入DOM后正确更新绑定机制?

有一种方法可以使用"show first prepared"按钮进行脏污.它prepareElement()在插入容器之前调用第一个元素.所以,请做以下事项:

  1. 点击"首先显示"按钮.确保单击内部更改背景颜色并增加计数器.
  2. 在输入字段中输入内容
  3. 点击"显示第二个"
  4. 点击"show first prepared".您可以看到输入元素为空,但计数器和背景颜色是最新的.(如果您在dartium中运行此演示,也会使用白色块将其背景颜色更改为父级,因为未应用父级样式)
  5. 点击第一聚合物内部.现在它改变了背景颜色和计数器.绑定工作正常,但我们丢失输入字段内的文本.

注意:在使用"show first prepared"按钮插入第一个元素后,即使在使用"show first"按钮插入第一个元素后,绑定也能正常工作.

代码在这里https://github.com/petalvlad/dart-style-binding-test

Gün*_*uer 4

我自己没有尝试过,但似乎很合理。我希望作者在重用元素时不介意从 Detached observables 中得到答案。

查看了polymer.js信息位后,我发现有一个cancelUnbindAll函数,必须在创建元素或将preventDispose属性设置为true时调用该函数。

对于任何可能需要执行相同操作的人,在 Dart 实现中,您必须在 super 调用之后在分离函数中调用 cancelUnbindAll,如下所示:

void detached()
{
    super.detached();
    this.cancelUnbindAll(preventCascade: true);
}
Run Code Online (Sandbox Code Playgroud)

或者,您可以简单地覆盖自定义元素中的 PreventDispose 属性:

bool get preventDispose => true;
Run Code Online (Sandbox Code Playgroud)