Vaadin 14: изменить размер TextArea после изменения размера окна - PullRequest
0 голосов
/ 13 марта 2020

с Vaadin 14.1.19 и Vaadin "My Starter 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);
    }
}

Когда я открываю представление с широким окном, это выглядит примерно так:

Vaadin 14.1.19 TextArea with a lot of text at a wide screen

Когда я изменяю размер окна, оно выглядит так, что это не так, потому что читается только начало текста. Я даже не могу прокрутить в TextAreas.

Vaadin 14.1.19 TextArea with a lot of text at a small screen

Только DIV изменяет размеры так, как я ожидал.

Как я могу получить TextArea Vaadin для изменения размера при изменении размера окна?

1 Ответ

1 голос
/ 19 марта 2020

Это похоже на ошибку. Я только что сообщил об этом здесь https://github.com/vaadin/vaadin-text-field/issues/460

В качестве обходного пути вы можете установить окно resize listener, которое запускает textArea._updateHeight(); на стороне клиента для запуска обновления высоты. Или вы можете использовать ResizeObserver , но он все еще имеет несколько ограниченную поддержку браузера

Вот наивный пример добавления обходного пути слушателя изменения размера в Flow:

textArea.getElement().executeJs(
    "window.addEventListener('resize', function() { $0._updateHeight(); });",
    textArea.getElement());

Но вы должны обернуть этот обработчик изменения размера в некоторый базовый c debouncer, чтобы он не запускался _updateHeight() слишком часто во время изменения размера, чтобы избежать проблем с производительностью.

В качестве альтернативы вы можете сделать это :

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

Я не уверен, что в addBrowserWindowResizeListener встроен какой-либо способ устранения неполадок или нет, но я думаю, что это, по крайней мере, вызовет обходные пути сервера при изменении размера, которых, по возможности, следует избегать.

Редактировать:

Вот более универсальный подход, создав новый компонент, расширяющий Vaadin TextArea и использующий ResizeObserver в поддерживаемых браузерах (с setInterval в качестве отступление для других браузеров).

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 = $0;" +
                    "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, и оно должно работать.

...