3.5.17.4.3. 使用 JavaScript 库

在此示例中,我们将使用 jQuery UI 库中的 Slider 组件。拥有两个拖拽手柄的滑动条,用于定义取值范围。

在 CUBA Studio 中创建一个新项目,并将其命名为 jscomponent

为了使用 Slider 组件,需要创建以下文件:

  • SliderServerComponent - 与 JavaScript 集成的 Vaadin 组件。

  • SliderState - Vaadin 组件的状态类。

  • slider-connector.js - Vaadin 组件的 JavaScript 连接器。

集成至通用 UI 的过程跟集成 Vaadin 组件到通用 UI 中描述的一致,这里就不再重复了。

下面在 web 模块的 toolkit/ui/slider 子目录创建需要的文件,并做相应修改。

  • SlideState 状态类定义在服务器和客户端之间传输的数据。在这个例子中,它是最小值、最大值和选定值。

    1. package com.company.jscomponent.web.toolkit.ui.slider;
    2. import com.vaadin.shared.ui.JavaScriptComponentState;
    3. public class SliderState extends JavaScriptComponentState {
    4. public double[] values;
    5. public double minValue;
    6. public double maxValue;
    7. }
  • Vaadin 服务端组件 SliderServerComponent

    1. package com.company.jscomponent.web.toolkit.ui.slider;
    2. import com.haulmont.cuba.web.widgets.WebJarResource;
    3. import com.vaadin.annotations.JavaScript;
    4. import com.vaadin.ui.AbstractJavaScriptComponent;
    5. import elemental.json.JsonArray;
    6. @WebJarResource({"jquery:jquery.min.js", "jquery-ui:jquery-ui.min.js", "jquery-ui:jquery-ui.css"})
    7. @JavaScript({"slider-connector.js"})
    8. public class SliderServerComponent extends AbstractJavaScriptComponent {
    9. public interface ValueChangeListener {
    10. void valueChanged(double[] newValue);
    11. }
    12. private ValueChangeListener listener;
    13. public SliderServerComponent() {
    14. addFunction("valueChanged", arguments -> {
    15. JsonArray array = arguments.getArray(0);
    16. double[] values = new double[2];
    17. values[0] = array.getNumber(0);
    18. values[1] = array.getNumber(1);
    19. getState(false).values = values;
    20. listener.valueChanged(values);
    21. });
    22. }
    23. public void setValue(double[] value) {
    24. getState().values = value;
    25. }
    26. public double[] getValue() {
    27. return getState().values;
    28. }
    29. public double getMinValue() {
    30. return getState().minValue;
    31. }
    32. public void setMinValue(double minValue) {
    33. getState().minValue = minValue;
    34. }
    35. public double getMaxValue() {
    36. return getState().maxValue;
    37. }
    38. public void setMaxValue(double maxValue) {
    39. getState().maxValue = maxValue;
    40. }
    41. @Override
    42. protected SliderState getState() {
    43. return (SliderState) super.getState();
    44. }
    45. @Override
    46. public SliderState getState(boolean markAsDirty) {
    47. return (SliderState) super.getState(markAsDirty);
    48. }
    49. public ValueChangeListener getListener() {
    50. return listener;
    51. }
    52. public void setListener(ValueChangeListener listener) {
    53. this.listener = listener;
    54. }
    55. }

    服务端组件定义了 getter 方法和 setter 方法来处理滑块状态,也定义了一个值更改监听器接口。该类继承自 AbstractJavaScriptComponent

    在类构造器中的调用 addFunction() 方法为客户端的 valueChanged() 方法的 RPC 调用定义了一个处理程序。

    @JavaScript@StyleSheet 注解指向的文件,必须在网页上加载。在这个的示例中,这些是 jquery-ui 库的 JavaScript 文件、位于WebJar 资源的 jquery-ui 的样式表以及 Vaadin 服务组件 Java 包里面的连接器。

  • JavaScript 连接器 slider-connector.js.

    1. com_company_jscomponent_web_toolkit_ui_slider_SliderServerComponent = function() {
    2. var connector = this;
    3. var element = connector.getElement();
    4. $(element).html("<div/>");
    5. $(element).css("padding", "5px 0px");
    6. var slider = $("div", element).slider({
    7. range: true,
    8. slide: function(event, ui) {
    9. connector.valueChanged(ui.values);
    10. }
    11. });
    12. connector.onStateChange = function() {
    13. var state = connector.getState();
    14. slider.slider("values", state.values);
    15. slider.slider("option", "min", state.minValue);
    16. slider.slider("option", "max", state.maxValue);
    17. $(element).width(state.width);
    18. }
    19. }

    连接器是一个在加载网页时初始化 JavaScript 组件的函数。该函数名称必须与服务端组件类名对应,其中包名中的点用下划线代替。

    Vaadin 为连接器函数添加了几种有用的方法。this.getElement() 返回组件的 HTML DOM 元素,this.getState() 返回一个状态对象。

    这里的连接器执行以下操作:

    • 初始化 jQuery UI 库的 slider 组件。当滑块的位置发生任何变化时,将调用 slide() 函数,该函数又调用连接器的 valueChanged() 方法。valuedChanged() 是在服务端 SliderServerComponent 类中定义的方法。

    • 定义 onStateChange() 函数。在服务端更改状态对象时调用它。

为了演示组件的工作原理,我们创建有三个属性的 Product 实体:

  • String 类型的 name

  • Double 类型的 minDiscount

  • Double 类型的 maxDiscount

为实体生成标准界面。确保 Module 字段的值为 Module: 'app-web_main'(只有在项目添加了 gui 模块之后才会显示这个字段)。

slider 组件将设置产品的最小和最大折扣值。

打开 product-edit.xml 文件。通过将 editable="false" 属性添加到相应的元素,使 minDiscountmaxDiscount 字段不可编辑。然后添加一个 box,将作为 Vaadin 组件的容器使用。

这时,编辑界面的 XML 描述应如下所示:

  1. <?xml version="1.0" encoding="UTF-8" standalone="no"?>
  2. <window xmlns="http://schemas.haulmont.com/cuba/screen/window.xsd"
  3. caption="msg://editorCaption"
  4. focusComponent="form"
  5. messagesPack="com.company.jscomponent.web.product">
  6. <data>
  7. <instance id="productDc"
  8. class="com.company.jscomponent.entity.Product"
  9. view="_local">
  10. <loader/>
  11. </instance>
  12. </data>
  13. <dialogMode height="600"
  14. width="800"/>
  15. <layout expand="editActions" spacing="true">
  16. <form id="form" dataContainer="productDc">
  17. <column width="250px">
  18. <textField id="nameField" property="name"/>
  19. <textField id="minDiscountField" property="minDiscount" editable="false"/>
  20. <textField id="maxDiscountField" property="maxDiscount" editable="false"/>
  21. <hbox id="sliderBox" width="100%"/>
  22. </column>
  23. </form>
  24. <hbox id="editActions" spacing="true">
  25. <button action="windowCommitAndClose"/>
  26. <button action="windowClose"/>
  27. </hbox>
  28. </layout>
  29. </window>

打开 ProductEit.java 文件。用以下代码替换其内容:

  1. package com.company.jscomponent.web.product;
  2. import com.company.jscomponent.entity.Product;
  3. import com.company.jscomponent.web.toolkit.ui.slider.SliderServerComponent;
  4. import com.haulmont.cuba.gui.components.HBoxLayout;
  5. import com.haulmont.cuba.gui.screen.*;
  6. import com.vaadin.ui.Layout;
  7. import javax.inject.Inject;
  8. @UiController("jscomponent_Product.edit")
  9. @UiDescriptor("product-edit.xml")
  10. @EditedEntityContainer("productDc")
  11. @LoadDataBeforeShow
  12. public class ProductEdit extends StandardEditor<Product> {
  13. @Inject
  14. private HBoxLayout sliderBox;
  15. @Subscribe
  16. protected void onInitEntity(InitEntityEvent<Product> event) {
  17. event.getEntity().setMinDiscount(15.0);
  18. event.getEntity().setMaxDiscount(70.0);
  19. }
  20. @Subscribe
  21. protected void onBeforeShow(BeforeShowEvent event) {
  22. SliderServerComponent slider = new SliderServerComponent();
  23. slider.setValue(new double[]{
  24. getEditedEntity().getMinDiscount(),
  25. getEditedEntity().getMaxDiscount()
  26. });
  27. slider.setMinValue(0);
  28. slider.setMaxValue(100);
  29. slider.setWidth("250px");
  30. slider.setListener(newValue -> {
  31. getEditedEntity().setMinDiscount(newValue[0]);
  32. getEditedEntity().setMaxDiscount(newValue[1]);
  33. });
  34. sliderBox.unwrap(Layout.class).addComponent(slider);
  35. }
  36. }

onInitEntity() 方法为新产品的折扣设置初始值。

onBeforeShow() 方法初始化 slider 组件,设置 slider 的当前值、最小值和最大值,并定义值更改监听器。当滑块移动时,可编辑实体的相应字段将被设置成新值。

启动应用程序服务并打开产品编辑界面。更改滑块位置时会改变文本框的值。

product edit