【问题标题】:Polymer Dart, global variables and data bindings (observable)Polymer Dart,全局变量和数据绑定(可观察)
【发布时间】:2015-07-03 23:46:42
【问题描述】:

我阅读了 Polymer API 开发人员指南,但不幸的是它只为 JavaScript 开发人员提供了示例。我尝试将一些示例移植到 Dart 中,但在这种情况下我失败了。请转至https://www.polymer-project.org/0.5/docs/polymer/polymer.html#global支持全局变量部分)。这是文档中的一段剪辑:

elements.html

<polymer-element name="app-globals">
  <script>
    (function() {
      var values = {};

      Polymer({
       ready: function() {
         this.values = values;
         for (var i = 0; i < this.attributes.length; ++i) {
           var attr = this.attributes[i];
           values[attr.nodeName] = attr.value;
         }
       }
      });
    })();
  </script>
</polymer-element>

<polymer-element name="my-component">
  <template>
    <app-globals id="globals"></app-globals>
    <div id="firstname">{{$.globals.values.firstName}}</div>
    <div id="lastname">{{$.globals.values.lastName}}</div>
  </template>
  <script>
    Polymer({
      ready: function() {
        console.log('Last name: ' + this.$.globals.values.lastName);
      }
    });
  </script>
</polymer-element>

index.html

<app-globals id="globals" firstname="Addy" lastname="Osmani"></app-globals>

问题:

  • 如何在 Dart 中实现这段代码?
  • 阅读有关 Dart Polymer 使用的不同问答的代码,我遇到了@observable 注释、toObserve() 函数和class CustomElement extends PolymerElement with Observable {..}。我知道它们在某种程度上与数据绑定有关,但我不知道具体如何。

【问题讨论】:

    标签: dart dart-polymer shadow-dom


    【解决方案1】:

    app_gobals.html

    <link rel="import" href="packages/polymer/polymer.html">
    
    <polymer-element name="app-globals">
      <template>
        <style>
          :host {
            display: none;
          }
        </style>
      </template>
      <script type="application/dart" src="app_globals.dart"></script>
    </polymer-element>
    

    app_gobals.dart

    import 'package:polymer/polymer.dart';
    import 'dart:async' show Timer;
    
    @CustomTag('app-globals')
    class AppGlobals extends PolymerElement {
      static final ObservableMap _staticValues = toObservable({});
    
      Map get values => _staticValues;
    
      AppGlobals.created() : super.created();
    
      ready() {
        attributes.keys.forEach((k) {
          values[k] = attributes[k];
        });
    
        // just to demonstrate that value changes are reflected
        // in the view
        new Timer.periodic(new Duration(seconds: 2),
            (_) => values['periodic'] = new DateTime.now());
      }
    }
    

    app_element.html(你的我的组件)

    <link rel="import" href="packages/polymer/polymer.html">
    <link rel="import" href="app_globals.html">
    <polymer-element name="app-element">
      <template>
        <style>
          :host {
            display: block;
          }
        </style>
        <app-globals id="globals"></app-globals>
        <div>{{$["globals"].values["firstname"]}}</div>
        <div>{{$["globals"].values["lastname"]}}</div>
        <div>{{$["globals"].values["periodic"]}}</div>
      </template>
      <script type="application/dart" src="app_element.dart"></script>
    </polymer-element>
    

    app_element.dart

    导入'package:polymer/polymer.dart';

    @CustomTag('app-element')
    class AppElement extends PolymerElement {
      AppElement.created() : super.created();
    
      ready() {
        print('Last name: ${$["globals"].values["lastName"]}');
      }
    }
    

    @observable 表示当值更改时应通知 Polymer,以便它可以更新视图。 如果您有一个集合,这还不够,因为 Polymer 仅在字段更改时才会收到通知(分配了另一个集合或 null)。 toObservable(list|map) 确保在集合中的元素发生更改(删除/添加/替换)时通知 Polymer。 PolymerElement 包括 Observable 因此在课堂上没有什么特别的事情要做。当你扩展一个 DOM 元素时,这看起来有点不同,请参阅https://stackoverflow.com/a/20383102/217408

    更新
    这是很多问题。我使用static final ObservableMap _staticValues = toObservable({}); 来确保所有值都存储在一个位置,无论您的应用程序包含多少&lt;app-globals&gt; 元素。静态存储在类中而不是实例中,因此存在多少实例并不重要。 @ComputedProperty(expression) var someField; 监视 expression 的值更改并通知 Polymer 将绑定更新为 someField@observable 是更简单的版本,但仅适用于字段。 @published 类似于 @observable,但还允许从元素外部绑定到字段。 @PublishedProperty()@published 相同,但这种注释形式允许传递参数。 @PublishedProperty(reflect: true)@published 类似,但另外更新了实际的 DOM 属性,以使绑定值不仅可用于其他要绑定的 Polymer 元素,还可用于 CSS 或其他不知道如何绑定到 Polymer 字段的框架。

    【讨论】:

    • Gunter,你能解释一下为什么使用MapObservable get values =&gt; toObservable({}) 它不起作用吗?除此之外,我真的很困惑在哪些情况下使用@ComputedProperty()@observable@published。我不知道notifyPropertyChange(#values, ...) 是什么意思以及如何使用它。即使一遍又一遍地阅读您的帖子 10 次,我也几乎不明白这里发生了什么。也许你举一些例子来驱散迷雾?如果需要,我可以创建新的答案。
    • 我将您的问题的答案添加到我的答案中,因为它太渴望评论了。请尽量使后续问题更具体。很难知道我应该更好地解释什么。
    • 很高兴听到 :) 一个额外的说明。您可能总是想使用@PublishedProperty(reflect: true) 来获得全功率,但尽量避免使用它,因为它比没有reflect: true 慢得多。例如,当您在使用 &lt;template repeat&gt; 创建数百个实例的元素中使用它时,这会显着降低您的应用程序的速度。
    • 感谢您的建议!如果说实话我还没有达到这个水平))
    • 好的,但我认为这有助于理解为什么开发人员会被这么多不同的选项所困扰。
    【解决方案2】:

    我找到了另一个适合我的解决方案:
    只需为您的全局变量定义一个类。使用工厂构造函数,以便类的每个表示都是相同的实例。该类必须使用 Observable 扩展 Object:
    globals.dart:

    library globals;
    import 'package:polymer/polymer.dart';
    
    class Globals extends Object with Observable {
    
      static Globals oneAndOnlyInstance;
      @observable String text; // a "global" variable
      @observable int integer; // another "global" variable
    
      factory Globals() {
        if (oneAndOnlyInstance==null) {
          oneAndOnlyInstance=new Globals.init();
        } 
        return oneAndOnlyInstance;    
      }
    
      Globals.init();
    
    }
    

    现在您可以在所有自定义元素中使用此类。只需要导入 globals.dart 并创建它的一个对象:
    内部:ma​​in_app.dart:

    import 'dart:html';
    
    import 'package:polymer/polymer.dart';   
    import 'package:abundan/classes/globals.dart';
    
    /// A Polymer `<main-app>` element.
    @CustomTag('main-app')
    class MainApp extends PolymerElement {      
      Globals globals=new Globals();    
    
      /// Constructor used to create instance of MainApp.
      MainApp.created() : super.created();
    
    attached() {
      super.attached();
      globals.text="HELLO!";
    }
    

    ma​​in_app.html 内部:

    {{globals.text}}
    

    这对我有用,它似乎是使用聚合物自定义元素的全局变量的最简单方法。

    【讨论】:

    • 嗯...解决方案看起来不错!谢谢,我稍后再试)
    • 这当然有效。我的方法提供了一种方法,您无需更改任何元素的代码即可使全局变量可用。只需在&lt;template&gt;(您需要访问全局变量的位置)内的某处添加&lt;app-globals id="globals"&gt;&lt;/app-globals&gt; 标签,然后您就可以像&lt;div&gt;{{$["globals"].values["firstname"]}}&lt;/div&gt; 一样访问它们
    猜你喜欢
    • 1970-01-01
    • 2016-09-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-10-18
    • 1970-01-01
    • 2019-02-16
    • 2014-10-10
    相关资源
    最近更新 更多