Docs

Documentation versions (currently viewingVaadin 24)
Documentation translations (currently viewingChinese)

此页面是从官方文档 http://vaadin.com/docs 机器翻译而来,其中可能包含错误、不准确或误导性的陈述。Vaadin 无法保证翻译的准确性、可靠性或及时性。

扩展组件

通过扩展现有组件创建新组件。

您可以通过扩展现有组件来创建一个新组件。对于大多数组件来说,都会存在一个客户端组件和与之对应的服务器端组件:

  • 客户端组件:包含 HTML、CSS 和 JavaScript,并定义一系列用于确定组件在客户端行为的属性。

  • 服务器端组件:包含 Java 代码,该代码允许修改客户端属性,并管理组件在服务器端的行为。

您可以在服务器端或客户端扩展一个组件。这两种扩展方式相互可替代且互斥。

本节展示了使用两种不同方式实现对预置文本框组件*相同修改*的方法。

使用服务器端方式扩展组件

当您希望向现有组件添加新的功能(而非视觉方面的)时,扩展服务器端组件十分有用。例如,自动处理数据时、添加默认的校验器时,或者组合多个简单组件到一个用于管理复杂数据的字段时,都可以使用这种方法。

Tip
请考虑使用Web组件
如果您的组件包含许多适合于在客户端执行的逻辑,请考虑将其实现为Web组件并为其创建包装器。 这种方法可能提供更佳的用户体验,并能减少服务器端负载。

以下示例通过扩展`TextField`组件创建了一个`NumericField`组件。新组件内包含了一个默认数字,用户可通过 +- 控件更改该数字。

服务器端数字字段扩展

示例:通过扩展`TextField`创建`NumericField`组件。

Source code
Java
@CssImport(value = "./styles/numeric-field-styles.css")
public class NumericField extends TextField {

    private Button substractBtn;
    private Button addBtn;

    private static final int DEFAULT_VALUE = 0;
    private static final int DEFAULT_INCREMENT = 1;

    private int numericValue;
    private int incrementValue;
    private int decrementValue;

    public NumericField() {
        this(DEFAULT_VALUE, DEFAULT_INCREMENT,
                -DEFAULT_INCREMENT);
    }

    public NumericField(int value, int incrementValue,
                        int decrementValue) {
        setNumericValue(value);
        this.incrementValue = incrementValue;
        this.decrementValue = decrementValue;

        setPattern("-?[0-9]*");
        setPreventInvalidInput(true);

        addChangeListener(event -> {
            String text = event.getSource().getValue();
            if (StringUtils.isNumeric(text)) {
                setNumericValue(Integer.parseInt(text));
            } else {
                setNumericValue(DEFAULT_VALUE);
            }
        });

        substractBtn = new Button("-", event -> {
            setNumericValue(numericValue +
                    decrementValue);
        });

        addBtn = new Button("+", event -> {
            setNumericValue(numericValue +
                    incrementValue);
        });

        addClassName("numeric");
        styleBtns();

        addToPrefix(substractBtn);
        addToSuffix(addBtn);
    }

    private void styleBtns() {
        substractBtn.addThemeName("icon");
        addBtn.addThemeName("icon");
    }

    public void setNumericValue(int value) {
        numericValue = value;
        setValue(value + "");
    }

    // getters and setters
}

作为另一种选择,您也可以扩展[classname]`Composite`类,该类有一个较小的API。 如果您的自定义组件扩展了一个继承自[classname]`Component`的实现,此方式可以隐藏扩展API中提供的方法。

Note
访问、更新和查询元素
Element API提供用于更新和查询元素各个部分(例如属性)的方法。 每个组件都有一个[methodname]`getElement()`方法,这允许您访问该元素。 参见使用多个元素创建组件了解更多信息。

使用`@CssImport`注解导入组件的其他样式。 请注意,必须使用CSS选择器(基于应用于组件的`numeric`类名)来限定样式在本组件内的范围。

示例:创建[filename]`numeric-field-styles.css`以定制自定义`vaadin-text-field`组件的外观。

Source code
styles/numeric-field-styles.css
vaadin-text-field.numeric::part(input-field) {
    background-color: var(--lumo-base-color);
    border: 1px solid var(--lumo-contrast-30pct);
    box-sizing: border-box;
}

vaadin-text-field.numeric::part(value) {
    text-align: center;
}

请参阅Styling Vaadin Components获取更多信息。

使用客户端方式扩展组件

Vaadin客户端组件基于http://polymer-library.polymer-project.org/3.0/docs/about_30[Polymer 3],后者支持扩展已有组件。 您可以使用`extends`属性来扩展现有的Polymer元素。

模板继承自另一个Polymer元素可以通过五种方式实现:

  1. 继承但不修改基类模板。

  2. 在子类中覆盖基类模板。

  3. 修改超类模板的副本。

  4. 在子类中扩展一个基类模板。

  5. 在基类中提供模板扩展点,以供子类内容使用。

通过修改超类模板副本进行扩展

该示例展示了如何通过修改超类模板的副本来创建一个新组件。 您通过扩展`TextField`创建一个`NumberField`组件。新组件包含一个默认数字,用户可使用 +- 控件进行更改。

客户端数字字段扩展

请注意,当一个组件的模板被扩展时,父模板的属性和方法会变得可用于子模板。

Note
子组件默认使用父组件的模板
默认情况下,子组件使用其父组件的模板,除非子组件通过覆盖静态getter方法[methodname]`template()`提供自己的模板。可以通过[methodname]`super.template()`访问父模板。

接下来,需要指定子组件继承的元素。 在本例中,需要说明`NumberField`从`TextField`继承,包括其属性和方法:

Source code
JavaScript
import { html } from
   '@polymer/polymer/lib/utils/html-tag.js';
import { TextField } from '@vaadin/text-field';

let memoizedTemplate;

class NumberField extends TextField {

    static get template() {
        if (!memoizedTemplate) {
            const superTemplate = super.template
                    .cloneNode(true);
            const inputField = superTemplate.content
                .querySelector('[part="input-field"]');
            const prefixSlot = superTemplate.content
            .querySelector('[name="prefix"]');
            const decreaseButton = html`<div
                part="decrease-button"
                on-click="_decreaseValue"></div>`;
            const increaseButton = html`<div
                part="increase-button"
                on-click="_increaseValue"></div>`;
            inputField.insertBefore(
                decreaseButton.content, prefixSlot);
            inputField.appendChild(
                increaseButton.content);
            memoizedTemplate = html`<style>
                 [part="decrease-button"]::before {
                   content: "−";
                 }

                 [part="increase-button"]::before {
                   content: "+";
                 }
               </style>
               ${superTemplate}`;
        }
        return memoizedTemplate;
    }

    static get is() {
        return 'vaadin-number-field';
    }

    static get properties() {
        return {
            decrementValue: {
              type: Number,
              value: -1,
              reflectToAttribute: true,
              observer: '_decrementChanged'
            },
            incrementValue: {
              type: Number,
              value: 1,
              reflectToAttribute: true,
              observer: '_incrementChanged'
            }
        };
    }

    _decreaseValue() {
        this.__add(this.decrementValue);
    }

    _increaseValue() {
        this.__add(this.incrementValue);
    }

    __add(value) {
        this.value = parseInt(this.value, 10) + value;
        this.dispatchEvent(
            new CustomEvent('change', {bubbles: true}));
    }

    _valueChanged(newVal, oldVal) {
        this.value = this.focusElement.value;
        super._valueChanged(this.value, oldVal);
    }

    /* ... */
}

欲修改模板,只需重写静态getter template()。 表达式`${super.template}`将基类模板插入新构建的模板中。 新构建的模板会被缓存以供[methodname]`template()`的后续调用。

如需更多信息,请参阅 Polymer 文档的 从另一个 Polymer 元素继承模板

42913850-FAD3-4184-9B69-02F29B1A14CE