跨自定义元素的共享行为状态

los*_*ime 2 javascript internationalization polymer polymer-1.0

我有这两个自定义聚合物元素(聚合物1.0.3):

  1. 显示要翻译的文本.
  2. 显示按钮以触发翻译加载.

我还有一个行为,它包含翻译(json对象)并包含使翻译成为可能的所有函数.

这就是我期望发生的事情:

  1. 单击元素2中的按钮
  2. 翻译加载到行为中
  3. 语言选择在"行为"中设置
  4. 元素1中的文本使用已翻译的等效项进行更新

步骤1 - 3发生,但4没有.文本永远不会更新.如果将元素1和元素2组合为相同的元素,我可以使它工作,但如果它们是分开的(它们需要分开),则不能.

如果你想知道"kick"属性,那就是我从Polymer 0.5中学到的东西.当两个元素组合在一起时,事情就会起作用,所以我认为当元素是分开的时候它是必要的.

知道如何才能实现这一目标吗?我对替代范式持开放态度.

这大致就是我的代码的布局方式.我还制作了一个带有单页测试用例plunker.

的index.html

<!doctype html>
<html>

<head>
  <script src="http://www.polymer-project.org/1.0/samples/components/webcomponentsjs/webcomponents-lite.js"></script>
  <link rel="import" href="http://www.polymer-project.org/1.0/samples/components/polymer/polymer.html">
  <link rel="import" href="behavior.html">
  <link rel="import" href="element1.html">
  <link rel="import" href="element2.html">
</head>

<body>
  <my-element></my-element>
  <another-element></another-element>
</body>

</html>
Run Code Online (Sandbox Code Playgroud)

要素1

<dom-module id="my-element">
  <template>
    <p>{{localize(label, kick)}}</p>
  </template>
</dom-module>

<script>
  Polymer({
    is: 'my-element',
    behaviors: [
      behavior
    ],
    properties: {
      label: {
        type: String,
        value: 'original'
      }
    }
  });
</script>
Run Code Online (Sandbox Code Playgroud)

要素2

<dom-module id="another-element">
  <template>
    <button on-click="buttonClicked">load</button>
  </template>
</dom-module>
<script>
  Polymer({
    is: 'another-element',
    behaviors: [
      behavior
    ],
    buttonClicked: function() {
      this.registerTranslation('en', {
        original: 'changed'
      })
      this.selectLanguage('en');
    }
  });
</script>
Run Code Online (Sandbox Code Playgroud)

行为

<script>
  var behavior = {
    properties: {
      kick: {
        type: Number,
        value: 0
      },
      language: {
        type: String,
        value: 'fun'
      },
      translations: {
        type: Object,
        value: function() {
          return {};
        }
      }
    },
    localize: function(key, i) {
      if (this.translations[this.language] && this.translations[this.language][key]) {
        return this.translations[this.language][key];
      }
      return key;
    },
    registerTranslation: function(translationKey, translationSet) {
      this.translations[translationKey] = translationSet;
    },
    selectLanguage: function(newLanguage) {
      this.language = newLanguage;
      this.set('kick', this.kick + 1);
    }
  };
</script>
Run Code Online (Sandbox Code Playgroud)

Sco*_*les 5

首先,虽然这个概念应该是behavior实例之间共享数据的管道,但是如同编写的那样,每个实例都将拥有它自己的translations对象和kick属性的副本.

其次,即使数据被私有化以便可以共享,通过kick绑定进行的绑定localize(label, kick)也与修改的表达式不同kick(即this.set('kick', this.kick + 1);[{sic}这可能只是this.kick++;]).

要通知N个实例共享数据的更改,必须跟踪这些实例.执行此操作的一种好方法是附加事件侦听器.另一种方法是简单地保留一份清单.

以下是您的设计的示例实现:

    <script>
      (function() {
        var instances = [];
        var translationDb = {};
        var language = '';

        window.behavior = {
          properties: {
            l10n: {
              value: 0
            }  
          },
          attached: function() {
            instances.push(this);
          },
          detached: function() {
            this.arrayDelete(instances, this);
          },
          _broadcast: function() {
            instances.forEach(function(i) {
              i.l10n++;
            });
          },
          localize: function(key, i) {
            if (translationDb[language] && translationDb[language][key]) {
              return translationDb[language][key];
            }
            return key;
          },
          registerTranslation: function(translationKey, translationSet) {
            translationDb[translationKey] = translationSet;
          },
          selectLanguage: function(newLanguage) {
            language = newLanguage;
            this._broadcast();
          }
        };
      })();
  </script>

  <dom-module id="my-element">
    <template>
      <p>{{localize(label, l10n)}}</p>
    </template>
    <script>
      Polymer({
        behaviors: [
          behavior
        ],
        properties: {
          label: {
            type: String,
            value: 'original'
          }
        }
      });
    </script>
  </dom-module>

  <dom-module id="another-element">
    <template>
      <button on-tap="buttonClicked">load</button>
    </template>
    <script>
      Polymer({
        behaviors: [
          behavior
        ],
        buttonClicked: function() {
          this.registerTranslation('en', {
            original: 'changed'
          });
          this.selectLanguage('en');
        }
      });
    </script>
  </dom-module>
Run Code Online (Sandbox Code Playgroud)