jmix2.2如何创建自定义组件(已解决,附剪贴板实现)

如1.5的功能,在2.2是否有呢?
https://docs.jmix.cn/1.x/jmix/1.5/ui/custom-components/js-component.html

看这里:https://demo.jmix.io/ui-samples/sample/custom-component

1 个赞

附上刚实现的一个 复制到剪切板 功能的代码,设置值这一块有点奇怪,有更好的方式吗?

clipboard.js

import {PolymerElement} from '@polymer/polymer/polymer-element.js';
import {ElementMixin} from '@vaadin/component-base/src/element-mixin.js';

class Clipboard extends ElementMixin(PolymerElement) {

    static get is() {
        return 'td-clipboard';
    }

    static get properties() {
        return {
            value: {
                type: String,
                notify: true,
                observer: '_onValueChange'
            }
        }
    }
    
    ready() {
        super.ready();
        // todo 进入时执行

    }

    _onValueChange(content) {

        if (content === "Copy successful" || content === "Copy failed") {
            return
        }

        // console.log('要复制的内容', content);

        // 设置想要复制的文本内容
        const text = content;
        // 判断是否支持clipboard方式
        if (!!window.navigator.clipboard) {
            // 利用clipboard将文本写入剪贴板(这是一个异步promise)
            window.navigator.clipboard.writeText(text).then((res) => {
                // console.log('复制成功', text);
                // 返回复制操作的最终结果
                this.dispatchEvent(new CustomEvent('custom-clipboard-changed', {detail: {value: "Copy successful"}}));
            }).catch((err) => {
                // console.log('复制失败', text, err);
                // 返回复制操作的最终结果
                this.dispatchEvent(new CustomEvent('custom-clipboard-changed', {detail: {value: "Copy failed"}}));
            })
        } else {
            // 不支持clipboard方式 则采用document.execCommand()方式
            // 创建一个input元素
            let inputDom = document.createElement('textarea');
            // 设置为只读 防止移动端手机上弹出软键盘
            inputDom.setAttribute('readonly', 'readonly');
            // 给input元素赋值
            inputDom.value = text;
            // 将创建的input添加到body
            document.body.appendChild(inputDom);
            // 选中input元素的内容
            inputDom.select();
            // 执行浏览器复制命令
            // 复制命令会将当前选中的内容复制到剪切板中(这里就是创建的input标签中的内容)
            // Input要在正常的编辑状态下原生复制方法才会生效
            const result = document.execCommand('copy')
            // 判断是否复制成功
            if (result) {
                // console.log('复制成功', text);
                this.dispatchEvent(new CustomEvent('custom-clipboard-changed', {detail: {value: "Copy successful"}}));
            } else {
                // console.log('复制失败', text);
                this.dispatchEvent(new CustomEvent('custom-clipboard-changed', {detail: {value: "Copy failed"}}));
            }
            // 复制操作后再将构造的标签 移除
            document.body.removeChild(inputDom);
        }
    }
}

customElements.define(Clipboard.is, Clipboard);

export {Clipboard};

clipboard.xsd

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<xs:schema xmlns="http://cn.treedeep.component/clipboard.xsd"
           elementFormDefault="qualified"
           targetNamespace="http://cn.treedeep.component/clipboard.xsd"
           xmlns:xs="http://www.w3.org/2001/XMLSchema"
           xmlns:layout="http://jmix.io/schema/flowui/layout">

    <xs:element name="clipboard">
        <xs:complexType>
            <xs:complexContent>
                <xs:extension base="layout:baseComponent">
                    <xs:attribute name="value" type="xs:integer"/>

                    <xs:attributeGroup ref="layout:hasSize"/>
                </xs:extension>
            </xs:complexContent>
        </xs:complexType>
    </xs:element>

</xs:schema>

Clipboard.java

package xxx.ui.component;

import com.vaadin.flow.component.*;
import com.vaadin.flow.component.dependency.JsModule;
import com.vaadin.flow.shared.Registration;


@Tag("td-clipboard")
@JsModule("./component/clipboard/clipboard.js")
public class Clipboard extends Component implements HasSize {
    public static final String VALUE_PROPERTY = "value";
    public static final String SLIDE_CHANGED_EVENT = "custom-clipboard-changed";

    public Registration addValueChangeListener(ComponentEventListener<ClipboardResultEvent> listener) {
        return addListener(ClipboardResultEvent.class, listener);
    }

    @Synchronize(property = VALUE_PROPERTY, value = SLIDE_CHANGED_EVENT)
    public String getValue() {
        return getElement().getProperty(VALUE_PROPERTY, "");
    }

    public void setValue(String value) {
        getElement().setProperty(VALUE_PROPERTY, value);
    }

    @DomEvent(SLIDE_CHANGED_EVENT)
    public static class ClipboardResultEvent extends ComponentEvent<Clipboard> {

        protected String value;

        public ClipboardResultEvent(Clipboard source, boolean fromClient, @EventData("event.detail.value") String value) {
            super(source, fromClient);
            this.value = value;
        }

        public String getValue() {
            return value;
        }
    }
}

ClipboardComponentRegistration.java

package xxx.ui.component;

import io.jmix.flowui.sys.registration.ComponentRegistration;
import io.jmix.flowui.sys.registration.ComponentRegistrationBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class ClipboardComponentRegistration {

    @Bean
    public ComponentRegistration slider() {
        return ComponentRegistrationBuilder.create(Clipboard.class)
                .withComponentLoader("clipboard", ClipboardLoader.class)
                .build();
    }
}

ClipboardLoader.java

package xxx.ui.component;

import io.jmix.flowui.xml.layout.loader.AbstractComponentLoader;

public class ClipboardLoader extends AbstractComponentLoader<Clipboard> {

    @Override
    protected Clipboard createComponent() {
        return factory.create(Clipboard.class);
    }

    @Override
    public void loadComponent() {
        loadString(element, "value", resultComponent::setValue);

        componentLoader().loadSizeAttributes(resultComponent, element);
    }
}

使用

image