扩展组件
您可以通过扩展现有组件来创建一个新组件。对于大多数组件来说,都会存在一个客户端组件和与之对应的服务器端组件:
-
客户端组件:包含 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
styles/numeric-field-styles.cssvaadin-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元素可以通过五种方式实现:
-
继承但不修改基类模板。
-
在子类中覆盖基类模板。
-
修改超类模板的副本。
-
在子类中扩展一个基类模板。
-
在基类中提供模板扩展点,以供子类内容使用。
通过修改超类模板副本进行扩展
该示例展示了如何通过修改超类模板的副本来创建一个新组件。 您通过扩展`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