Vaadin 14:调整大小后调整 TextArea window

Vaadin 14: Resize TextArea after resizing window

使用 Vaadin 14.1.19 和 Vaadin "My Starter Project"-project 我试图创建一个多行 TextArea。乍一看它工作正常,但在调整 TextArea 大小时,它不会调整行数。 这是我的代码:

package com.packagename.myapp;
import org.springframework.beans.factory.annotation.Autowired;
import com.vaadin.flow.component.html.Div;
import com.vaadin.flow.component.orderedlayout.VerticalLayout;
import com.vaadin.flow.component.textfield.TextArea;
import com.vaadin.flow.router.Route;
import com.vaadin.flow.server.PWA;
@Route(layout = DesktopLayout.class)
@PWA(name = "Project Base for Vaadin Flow with Spring", shortName = "Project Base")
public class MainView extends VerticalLayout {
    public MainView(@Autowired MessageBean bean) {
        String loremIpsum = "Lorem ipsum dolor sit amet, [....].";
        TextArea readOnlyTA = new TextArea();
        readOnlyTA.setLabel("Read-only");
        readOnlyTA.setWidth("1500px");
        readOnlyTA.setMaxWidth("80vw");
        readOnlyTA.setValue(loremIpsum);
        readOnlyTA.setReadOnly(true);
        add(readOnlyTA);

        TextArea readWriteTA = new TextArea();
        readWriteTA.setLabel("normal");
        readWriteTA.setWidth("1500px");
        readWriteTA.setMaxWidth("80vw");
        readWriteTA.setValue(loremIpsum);
        add(readWriteTA);

        Div readOnlyDiv = new Div();
        readOnlyDiv.setWidth("1500px");
        readOnlyDiv.setMaxWidth("80vw");
        readOnlyDiv.add(loremIpsum);
        add(readOnlyDiv);
    }
}

当我用宽 window 打开视图时,它看起来像这样很好:

当我调整 window 大小时,它看起来不太好,因为只有文本的开头是可读的。 我什至无法在 TextAreas 中滚动。

只有 DIV 调整大小符合我的预期。

如何让 Vaadin 的 TextArea 以 window 调整大小?

这似乎是一个错误。我刚刚在这里报告了 https://github.com/vaadin/vaadin-text-field/issues/460

作为解决方法,您可以在客户端设置 window resize 侦听器 运行s textArea._updateHeight(); 以触发高度更新。或者您可以使用 ResizeObserver but it still has somewhat limited browser support

这是一个在 Flow 中添加调整大小侦听器解决方法的简单示例:

textArea.getElement().executeJs(
    "window.addEventListener('resize', function() { [=10=]._updateHeight(); });",
    textArea.getElement());

但是您应该将此调整大小处理程序包装在一些基本的去抖动器中,这样它就不会 运行 _updateHeight() 在调整大小时发生的频率太高以避免性能问题。

或者你可以这样做:

UI.getCurrent().getPage().addBrowserWindowResizeListener(event -> {
    textArea.getElement().executeJs("this._updateHeight();");
});

我不确定 addBrowserWindowResizeListener 是否内置了某种去抖动功能,但我认为这至少会导致服务器在调整大小时往返,这应该尽可能避免。

编辑:

这是一种更通用的方法,它通过创建一个新组件来扩展 Vaadin TextArea 并在支持的浏览器中使用 ResizeObserversetInterval 作为其他浏览器的后备)。

import com.vaadin.flow.component.AttachEvent;
import com.vaadin.flow.component.textfield.TextArea;

public class CustomTextArea extends TextArea {
    private boolean initDone = false;

    @Override
    protected void onAttach(AttachEvent attachEvent) {
        super.onAttach(attachEvent);
        if (!initDone) {
            // debounce method borrowed from: https://davidwalsh.name/essential-javascript-functions
            getElement().executeJs(
                    "const debounce = function(func, wait, immediate) {" +
                    "  var timeout;" +
                    "  return function() {" +
                    "    var context = this, args = arguments;" +
                    "    var later = function() {" +
                    "      timeout = null;" +
                    "      if (!immediate) func.apply(context, args);" +
                    "    };" +
                    "    var callNow = immediate && !timeout;" +
                    "    clearTimeout(timeout);" +
                    "    timeout = setTimeout(later, wait);" +
                    "    if (callNow) func.apply(context, args);" +
                    "  };" +
                    "};" +
                    "const textArea = [=12=];" +
                    "const updateTextAreaHeight = function() { textArea._updateHeight(); };" +
                    "const debounceTimeout = 50;" +
                    "const intervalTimeout = 500;" +
                    "" +
                    "if (window.ResizeObserver) {" +
                    "  let textAreaDebouncer;" +
                    "  const resizeObserver = new ResizeObserver(debounce(updateTextAreaHeight, debounceTimeout));" +
                    "  resizeObserver.observe(textArea);" +
                    "} else {" +
                    "  let textAreaWidth = textArea.clientWidth;" +
                    "  window.setInterval(function() {" +
                    "    if (textAreaWidth !== textArea.clientWidth) {" +
                    "      updateTextAreaHeight();" +
                    "      textAreaWidth = textArea.clientWidth;" +
                    "    }" +
                    "  }, intervalTimeout);" +
                    "}", getElement());
            initDone = true;
        }
    }
}

然后只需使用这个 CustomTextArea 而不是 TextArea 就可以了。