You're viewing an older version of Polymer. Please see Polymer 3.0 for the latest.

您可以在元素上声明属物以添加默认值并启用数据系统中的各种功能。

声明的属物可以指定:

  • 属物类型。
  • 默认值。
  • 属物变更观察者。每次当属物值变更时会调用一个方法。
  • 只读的状态。防止意外地改变属物的值。
  • 双向数据绑定支持。每次当属性值变更时会触发一个事件。
  • 被计算的属物。根据其他属物动态地计算一个属物的值。
  • 属物反射到属性。当属物的值变更时更新相应的属性的值。

许多这些功能被紧密地集成到 数据系统 中,在数据系统的章节中进行详细描述。

此外,也可以使用属性从标识来配置声明的属物(有关详细信息,请参阅 属性反序列化)。

在大多数情况下,属于元素的公共 API 的一部分的属物,应在 properties 对象中进行声明。

要声明属物,在元素的类中添加一个静态的 properties getter。该 getter 应返回一个包含属物声明的对象。

示例

class XCustom extends Polymer.Element {

  static get properties() {
    return {
      user: String,
      isHappy: Boolean,
      count: {
        type: Number,
        readOnly: true,
        notify: true
      }
    }
  }
}

customElements.define('x-custom', XCustom);

properties 对象中的每个属物都支持以下的一些键:

KeyDetails
type Type: constructor

Attribute type, used for deserializing from an attribute. Polymer supports deserializing the following types: Boolean, Date, Number, String, Array and Object. You can add support for other types by overriding the element's _deserializeValue method.

Unlike 0.5, the property's type is explicit, specified using the type's constructor. See attribute deserialization for more information.

value Type: boolean, number, string or function.

Default value for the property. If value is a function, the function is invoked and the return value is used as the default value of the property. If the default value should be an array or object unique to the instance, create the array or object inside a function. See Configuring default property values for more information.

reflectToAttribute Type: boolean

Set to true to cause the corresponding attribute to be set on the host node when the property value changes. If the property value is Boolean, the attribute is created as a standard HTML boolean attribute (set if true, not set if false). For other property types, the attribute value is a string representation of the property value. Equivalent to reflect in Polymer 0.5. See Reflecting properties to attributes for more information.

readOnly Type: boolean

If true, the property can't be set directly by assignment or data binding. See Read-only properties.

notify Type: boolean

If true, the property is available for two-way data binding. In addition, an event, property-name-changed is fired whenever the property changes. See Property change notification events (notify) for more information.

computed Type: string

The value is interpreted as a method name and argument list. The method is invoked to calculate the value whenever any of the argument values changes. Computed properties are always read-only. See Computed properties for more information.

observer Type: string

The value is interpreted as a method name to be invoked when the property value changes. Note that unlike in 0.5, property change handlers must be registered explicitly. The propertyNameChanged method will not be invoked automatically. See Property change callbacks (observers) for more information.

For data binding, deserializing properties from attributes, and reflecting properties back to attributes, Polymer maps attribute names to property names and the reverse.

When mapping attribute names to property names:

  • Attribute names are converted to lowercase property names. For example, the attribute firstName maps to firstname.

  • Attribute names with dashes are converted to camelCase property names by capitalizing the character following each dash, then removing the dashes. For example, the attribute first-name maps to firstName.

The same mappings happen in reverse when converting property names to attribute names (for example, if a property is defined using reflectToAttribute: true.)

Compatibility note: In 0.5, Polymer attempted to map attribute names to corresponding properties. For example, the attribute foobar would map to the property fooBar if it was defined on the element. This does not happen in 1.0—attribute to property mappings are set up on the element at registration time based on the rules described above.

If a property is configured in the properties object, an attribute on the instance matching the property name will be deserialized according to the type specified and assigned to a property of the same name on the element instance.

If no other properties options are specified for a property, the type (specified using the type constructor, e.g. Object, String, etc.) can be set directly as the value of the property in the properties object; otherwise it should be provided as the value to the type key in the properties configuration object.

Boolean properties are set based on the presence of the attribute: if the attribute exists at all, the property is set to true, regardless of the attribute value. If the attribute is absent, the property gets its default value.

Example:

<script>
  class XCustom extends Polymer.Element {

    static get properties() {
      return {
        user: String,
        manager: {
          type: Boolean,
          notify: true
        }
      }
    }

    connectedCallback() {
      super.connectedCallback();
      
      // render
      this.textContent = 'Hello World, my user is ' + (this.user || 'nobody') + '.\n' +
        'This user is ' + (this.manager ? '' : 'not') + ' a manager.';
    }
  }

  customElements.define('x-custom', XCustom);
</script>

<x-custom user="Scott" manager></x-custom>
<!--
<x-custom>'s text content becomes:
Hello World, my user is Scott.
This user is a manager.
-->

To configure camel-case properties of elements using attributes, dash- case should be used in the attribute name.

Example:

<script>

  class XCustom extends Polymer.Element {

    static get properties() {
      return {
        userName: String
      }
    }
  }

  customElements.define('x-custom', XCustom);
</script>

<x-custom user-name="Scott"></x-custom>
<!-- Sets <x-custom>.userName = 'Scott';  -->

Note: Deserialization occurs both at create time, and at runtime (for example, when the attribute is changed using setAttribute). However, it is encouraged that attributes only be used for configuring properties in static markup, and instead that properties are set directly for changes at runtime.

For a Boolean property to be configurable from markup, it must default to false. If it defaults to true, you cannot set it to false from markup, since the presence of the attribute, with or without a value, equates to true. This is the standard behavior for attributes in the web platform.

If this behavior doesn't fit your use case, you can use a string-valued or number-valued attribute instead.

For object and array properties you can pass an object or array in JSON format:

<my-element book='{ "title": "Persuasion", "author": "Austen" }'></my-element>

Note that JSON requires double quotes, as shown above.

The type system includes built-in support for Boolean and Number values, Object and Array values expressed as JSON, or Date objects expressed as any Date-parsable string representation. To support other types, you can override the element's _deserializeValue method.

_deserializeValue(value, type) {
  if (type == MyCustomType) {
    return stringToMyCustomType(value);
  } else {
    return super._deserializeValue(value, type);
  }
}

Default values for properties may be specified in the properties object using the value field, or set imperatively in the element's constructor.

The value in the properties object may either be a primitive value, or a function that returns a value.

If you provide a function, Polymer calls the function once per element instance.

When initializing a property to an object or array value, either initialize the property in the constructor, or use a function to ensure that each element gets its own copy of the value, rather than having an object or array shared across all instances of the element.

Default in properties object

class XCustom extends Polymer.Element {

  static get properties() {
    return {
      mode: {
        type: String,
        value: 'auto'
      },

      data: {
        type: Object,
        notify: true,
        value: function() { return {}; }
      }
    }
  }
}

Default in constructor

constructor() {
  super();  
  this.mode = 'auto';
  this.data = {};
}

static get properties() {
  return {
    mode: String,

    data: {
      type: Object,
      notify: true
    }
  }
}

When a property is set to notify: true, an event is fired whenever the property value changes. The event name is:

property-name-changed

Where property-name is the dash-case version of the property name. For example, a change to this.firstName fires first-name-changed.

These events are used by the two-way data binding system. External scripts can also listen for events (such as first-name-changed) directly using addEventListener. Property change events don't bubble, so the event listener must be added directly to the element generating the event.

For more on property change notifications and the data system, see Data flow.

When a property only "produces" data and never consumes data, this can be made explicit to avoid accidental changes from the host by setting the readOnly flag to true in the properties property definition. In order for the element to actually change the value of the property, it must use a private generated setter of the convention _setProperty(value) where Property is the property name, with the first character converted to uppercase (if alphabetic). For example, the setter for oneProperty is _setOneProperty, and the setter for _privateProperty is _set_privateProperty.

class XCustom extends Polymer.Element {

  static get properties() {
    return {
      response: {
        type: Object,
        readOnly: true,
        notify: true
      }
    }
  }

  responseHandler(response) {
    // set read-only property
    this._setResponse(response);
  }
}

For more on read-only properties and data binding, see How data flow is controlled.

In specific cases, it may be useful to keep an HTML attribute value in sync with a property value. This may be achieved by setting reflectToAttribute: true on a property in the properties configuration object. This causes any observable change to the property to trigger an update to the corresponding attribute (as described in Property name to attribute name mapping). Since attributes only take string values, the property value is serialized to a string, as described in Attribute serialization.

class XCustom extends Polymer.Element {

  static get properties() {
    return {
      loaded: {
        type: Boolean,
        reflectToAttribute: true
      }
    }
  }

  _onLoad() {
    this.loaded = true;
    // results in this.setAttribute('loaded', true);
  }
}

When reflecting a property to an attribute or binding a property to an attribute, the property value is serialized to the attribute.

By default, values are serialized according to value's current type, regardless of the property's type value:

  • String. No serialization required.
  • Date or Number. Serialized using toString.
  • Boolean. Results in a non-valued attribute to be either set (true) or removed (false).
  • Array or Object. Serialized using JSON.stringify.

To add custom serialization for other data types, override your element's _serializeValue method.

_serializeValue(value) {
  if (value instanceof MyCustomType) {
    return value.toString();
  }
  return super._serializeValue(value);
}

A property is declared implicitly if you add it to a data binding or add it as a dependency of an observer, computed property, or computed binding.

Polymer automatically creates setters for these implicitly declared properties. However, implicitly declared properties can't be configured from markup.

JavaScript doesn't have any true protection for properties. By convention, Polymer elements usually use a single underscore (_protectedProp) to indicate a protected property or method (intended to be used or overridden by subclasses, but not for public use), and a double underscore (__privateProp) for members that are private to the class.