通用 JavaScript 组件

JavaScriptComponent 是个简单的 UI 组件,通过它可以使用 JavaScript 组件,不需要通过 Vaadin 实现。因此,通过这个组件可以很容易地在基于 Jmix 的项目中集成任何纯 JavaScript 组件。

该组件可以在界面的 XML 描述中以声明的方式定义,因此可以在 XML 中配置动态属性和 JavaScript 依赖。

组件的 XML 名称:jsComponent

定义依赖

可以为该组件定义一个依赖列表(JavaScript、CSS)。依赖从下列源获取:

  • WebJar 资源 - 以 webjar:// 开头。

  • VAADIN 目录下的文件 - 以 vaadin:// 开头。

  • Web 资源 - 以 http://https:// 开头。

依赖列表定义在 dependencies 元素中。每个依赖通过内部的 dependency 元素进行描述。

path 属性用于定义依赖的路径。

在 XML 中定义依赖的示例:

<jsComponent id="timePicker"
             initFunctionName="ui_ex1_components_javascript_TimePicker">
    <dependencies>
        <dependency path="webjar://jquery:jquery.min.js"
                    type="JAVASCRIPT"/>
        <dependency path="vaadin://timepicker/wickedpicker.min.js"/>
        <dependency path="vaadin://timepicker/wickedpicker.min.css"/>
        <dependency path="vaadin://timepicker/time-picker-connector.js"/>
    </dependencies>
</jsComponent>

如果依赖的类型不能从文件后缀推断,则需要在 XML 的 type 属性中指定类型。

如需在 Jmix Studio 中添加依赖,可以在界面 XML 或者 Component Hierarchy 面板中选择 jsComponent,然后点击 Component Inspector 面板的 Add→Dependency 按钮。

你也可以使用 addDependency() 方法编程式添加依赖。方法接收 DependencyType 枚举值指定依赖的类型。

以编程方式添加依赖的示例:

timePicker.addDependencies(
        "webjar://jquery:jquery.min.js",
        "vaadin://timepicker/wickedpicker.min.js",
        "vaadin://timepicker/time-picker-connector.js");
timePicker.addDependency("vaadin://timepicker/wickedpicker.min.css",
        JavaScriptComponent.DependencyType.STYLESHEET);

定义初始化函数

该组件需要一个初始化函数。框架用此函数的名称查找 JavaScript 组件连接器(connector)的入口。

初始化函数的名称在一个浏览器窗口内必须唯一。

jsComponentinitFunctionName 属性可用于指定该函数名称。

函数名称也可以通过 setInitFunctionName() 方法传递给组件:

timePicker.setInitFunctionName("ui_ex1_components_javascript_TimePicker");

定义 JavaScript 连接器

如需使用 JavaScriptComponent 包装 JavaScript 库,需要定义 JavaScript 连接器,其功能主要是初始化 JavaScript 组件并且处理服务端和 JavaScript 代码之间的通信。

连接器函数中可以使用下列方法:

  • this.getElement() 返回组件的 HTML DOM 元素。

  • this.getState() 返回当前状态的共享状态对象,此状态与服务端同步。

JavaScriptComponent 的功能

JavaScriptComponent 有下列功能:

  • 设置一个状态对象,该对象可以在客户端层的 JavaScript 连接器中使用,并且可以通过组件状态的 data 字段访问,示例:

    TimePickerState state = new TimePickerState();
    
    state.now = "12:35:57";
    state.showSeconds = true;
    state.twentyFour = true;
    
    timePicker.setState(state);
  • 注册一个函数,该函数可以在 JavaScript 中使用提供的名称进行调用,示例:

    timePicker.addFunction("onBeforeShow", callbackEvent ->
            notifications.create()
                    .withCaption("Before Show Event")
                    .withPosition(Notifications.Position.MIDDLE_RIGHT)
                    .show());
  • 调用命名的函数,该函数由连接器的 JavaScript 代码添加到包装的对象中。

    timePicker.callFunction("showValue");
    connector.showValue = function () {
        alert(timepicker.wickedpicker('time'));
    };

示例

本节介绍如何在基于 Jmix 的应用中集成第三方 JavaScript 库,使用 Quill 富文本编辑器 作为示例。请按照下面的步骤集成。

  1. build.gradle 文件添加以下依赖:

    implementation 'org.webjars.npm:quill:1.3.6'
  2. src/main/resources/VAADIN/quill 目录内创建 quill-connector.js 文件。

  3. 在此文件内,添加连接器的实现:

    ui_ex1_components_javascript_RichTextEditor = function () {
        var connector = this;
        var element = connector.getElement();
        element.innerHTML = "<div id=\"editor\">" +
            "<p>Hello World!</p>" +
            "<p>Some initial <strong>bold</strong> text</p>" +
            "<p><br></p>" +
            "</div>";
    
        connector.onStateChange = function () { (1)
            var state = connector.getState();
            var data = state.data;
    
            var quill = new Quill('#editor', data.options);
    
            quill.on('text-change', function (delta, oldDelta, source) { (2)
                if (source === 'user') {
                    connector.valueChanged(quill.getText(), quill.getContents());
                }
            });
        }
    };
    1 处理服务端的状态变更。
    2 订阅 textChange 事件。
  4. 创建一个界面,包含以下 jsComponent 定义:

    <?xml version="1.0" encoding="UTF-8" standalone="no"?>
    <window xmlns="http://jmix.io/schema/ui/window"
            caption="msg://richTextEditorScreen.caption">
        <layout>
            <jsComponent id="quill"
                         initFunctionName="ui_ex1_components_javascript_RichTextEditor"
                         height="200px"
                         width="400">
                <dependencies>
                    <dependency path="webjar://quill:dist/quill.js"/>
                    <dependency path="webjar://quill:dist/quill.snow.css"/>
                    <dependency path="vaadin://quill/quill-connector.js"/>
                </dependencies>
            </jsComponent>
        </layout>
    </window>
  5. 添加下面的界面控制器实现:

    @UiController("sample_RichTextEditorScreen")
    @UiDescriptor("rich-text-editor-screen.xml")
    public class RichTextEditorScreen extends Screen {
        @Autowired
        private JavaScriptComponent quill;
    
        @Autowired
        private Notifications notifications;
    
        @Subscribe
        protected void onInit(InitEvent event) {
            QuillState state = new QuillState();
            state.options = ParamsMap.of("theme", "snow",
                    "placeholder", "Compose an epic...");
    
            quill.setState(state);
    
            quill.addFunction("valueChanged", javaScriptCallbackEvent -> {
                String value = javaScriptCallbackEvent.getArguments().getString(0);
                notifications.create()
                        .withCaption(value)
                        .withPosition(Notifications.Position.BOTTOM_RIGHT)
                        .show();
            });
        }
    
        class QuillState {
            public Map<String, Object> options;
        }
    }

执行结果,界面中可以看到 Quill 富文本编辑器:

java script component

XML 属性

可以使用 Studio 界面设计器的 Jmix UI 组件面板查看和编辑组件的属性。

JavaScriptComponent XML 元素

Dependency XML 属性