javascript
  • data-binding
  • polymer
  • immutable.js
  • custom-element
  • 2015-10-20 96 views 1 likes 
    1

    考慮定製的聚合物元件聚合物數據綁定和Immutable.js一起

    <app-header bar-foo="[[abc.def.ghi]]" app-title="[[appTitle]]"></app-header> 
    

    這裏的以下使用我結合兩個變量來定製元素app-header。現在,當我想更新的值,您可能希望這樣做如下(在app-header父!):

    this.abc.def.ghi = 10; 
    this.appTitle = 'New title'; 
    

    然而,這僅更新appTitleabc.def.ghi。爲了更新這個值,以及你需要做的具體步驟如下:

    this.abc = {def: {ghi: 10}}; 
    

    如果有人知道這是爲什麼,請讓我知道!我想用Immutable! 然而,這引起一些問題,如何將數據綁定到定製元素

    下面是一個例子片段:

    <dom-module id="my-app"> 
        <template> 
         <app-header hits="[[state.get('page').get('hits')]]"></app-header> 
        </template> 
        <script> 
         (function() { 
          class MyApp { 
           beforeRegister() { 
            this.is = 'my-app'; 
    
            this.properties = { 
             state: { 
              type: Object, 
              notify: true, 
              value: Immutable.Map({ 
               page: Immutable.Map({hits: 10}) 
              }) 
             } 
            }; 
           } 
          } 
    
          Polymer(MyApp); 
         })(); 
        </script> 
    </dom-module> 
    

    所以結合數據時,一個元件發生問題:

    ​​

    這樣的事情是甚至可能的,還是我在做其他事情完全錯誤?

    回答

    1

    更新結構數據時,應該使用Polymer API。這將觸發更改的事件,綁定的數據將更新。查看路徑更改通知this article。在這種情況下,您需要將代碼改成這樣:

    this.set('abc.def.ghi', 10); 
    

    我不熟悉一成不變的,然而,這種表達不支持的聚合物。

    hits="[[state.get('page').get('hits')]]" 
    

    您可以綁定到元素或計算函數的(子)屬性。計算功能必須在元素中定義。您不能在數據綁定中的任意對象上調用任意函數。 也許,使用set API將消除使用Immutable的需要。

    1

    我知道這個帖子是有點老了,但我想回答,因爲我想用永恆JS和聚合物一起探討,因爲:

    1. 我的團隊使用聚合物來構建應用程序,不能改變的
    2. 一成不變的品牌實現索馬里發展事務處和重做操作瑣碎,這是一個要求

    我發現結合在聚合物不變JS對象的方式,但被警告,它的醜陋,哈克。


    綁定到一個不可變對象

    爲了得到聚合物訪問一成不變的JS性能,你需要在充當某種之間的「適配器」的元素原型創建Object類型的屬性不可變的js和聚合物。

    此屬性必須使用javascript getters(或Object.defineProperty),以便聚合物API可以以object.property的形式訪問對象,但實際實現將訪問不可變對象。

    let immutableMap = Immutable.map({count: 0, text: 'world'}); 
    
    Polymer({ 
        // ... 
        properties: { 
        /** 
        * This property is an 'adapter' to assign a property path to access the immutablejs object. 
        * The property starts with an underscore because we don't want the user to set it 
        */ 
        _adapter: { 
         type: Object, 
         value: { 
         /** 
         * the properties of this object use 
         * [getters](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/get) 
         * so that polyer can access the object like `obj.count` 
         */ 
         get count() { return immutableMap.get('count'); }, 
         get text() { return immutableMap.get('text'); } 
         } 
        } 
        } 
        // ... 
    }); 
    

    因此,在上面的例子中,我創建了有兩個方法Object類型的屬性:counttext。由於這些方法是以get爲前綴的,因此它們應該僅通過方法名稱訪問 - 它是getter

    這樣做可以使聚合物綁定到_adapter對象,然後該對象從immutableMap'獲取'值。

    改變不變對象

    需要得到這個工作是改變不可變的對象的第二片。由於該對象是不可變的,因此雙向綁定不是一種選擇。當使用immutable時,你必須添加事件偵聽器,它將重新分配不可變的對象並重新渲染。

    爲此,您必須登錄override dirty checking in polymer 我試過使用 notifyPath,但我發現那不起作用。 notifyPath應該工作。

    買者

    由於我們覆蓋髒檢查和我們不使用虛擬-DOM庫(等反應),利用一個不變的對象需要重新呈現使用該_adapter每次變化的任何元件發生在一個不可變的對象中。雖然這可以通過使用notifyPath來改善。

    完整演示(與撤消)

    這裏是不可變的JS和聚合物的完整演示在一起。我已經添加了撤消功能使用不可改變的一點獎勵 - 不變的JS,使索馬里發展事務處和重做操作很簡單:d

    <base href="https://cdn.rawgit.com/download/polymer-cdn/1.7.0/lib/"> 
     
    <script src="webcomponentsjs/webcomponents-lite.min.js"></script> 
     
    <link rel="import" href="polymer/polymer.html"> 
     
    <script src="https://cdnjs.cloudflare.com/ajax/libs/immutable/3.8.1/immutable.min.js"></script> 
     
    
     
    <!-- Defines element markup --> 
     
    <dom-module id="hello-world"> 
     
        <template> 
     
        <div> 
     
         <!--use only one-way binding because the object is immutable--> 
     
         <button on-tap="onButtonClick">clicks <span>[[_adapter.count]]</span></button> 
     
        </div> 
     
        <div> 
     
         <input on-input="onInput" type="text" value="[[_adapter.text]]"> 
     
         <h1>hello, <span>[[_adapter.text]]</span>!</h1> 
     
        </div> 
     
        <div> 
     
         <button on-tap="onUndo">Undo</button> 
     
        </div> 
     
        </template> 
     
    
     
        <!-- Registers custom element --> 
     
        <script> 
     
        // immutable map is defined out of the scope of the polymer object 
     
        let immutableMap = Immutable.Map({ 
     
         count: 0, 
     
         text: 'world' 
     
        }); 
     
        // add undos 
     
        let undos = []; 
     
    
     
        Polymer({ 
     
         is: 'hello-world', 
     
         /** 
     
         * every event should reassign the `immutableMap` then manually `notifyPath` 
     
         */ 
     
         onButtonClick: function() { 
     
         undos.push(immutableMap); 
     
         immutableMap = immutableMap.update('count', count => count + 1); 
     
         this.notifyPath('_adapter.count'); 
     
         }, 
     
         onInput: function (event) { 
     
         undos.push(immutableMap); 
     
         immutableMap = immutableMap.set('text', event.target.value); 
     
         this.notifyPath('_adapter.text'); 
     
         }, 
     
         onUndo: function() { 
     
         if (undos.length) { 
     
          immutableMap = undos.pop(); 
     
         } 
     
         const obj = this._adapter; 
     
         this._adapter = {}; 
     
         this._adapter = obj; 
     
         }, 
     
         properties: { 
     
         /** 
     
         * This property is an 'adapter' to assign a property path to access the immutablejs object. 
     
         * The property starts with an underscore because we don't want the user to set it 
     
         */ 
     
         _adapter: { 
     
          type: Object, 
     
          value: { 
     
          /** 
     
          * the properties of this object use 
     
          * [getters](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/get) 
     
          * so that polymer can access the object like `obj.count` 
     
          */ 
     
          get count() { return immutableMap.get('count'); }, 
     
          get text() { return immutableMap.get('text'); } 
     
          } 
     
         } 
     
         } 
     
        }); 
     
        </script> 
     
    </dom-module> 
     
    
     
    <hello-world></hello-world>

    相關問題