1

我正在尝试将 Vaadin 6 应用程序(使用复杂的对话框窗口)重写为 Vaadin Fusion 22。初始化对话框时出现问题。例如在 DatePicker 中设置 i18n。TestView.datePicker 在 firstUpdated() 上初始化,但 TestDateDialog.datePicker 始终未定义或为空。

测试视图.ts

@customElement('test-view')
export class TestView extends View {

    @state()
    private dialogOpened = false;

    @query('#date1')
    private datePicker?: DatePicker;

    @query('#test-date')
    private dialog?: TestDateDialog;

    render() {
        return html`<vaadin-vertical-layout class="w-full h-full" theme="padding">
                    <vaadin-date-picker id="date1">
                    </vaadin-date-picker>
                    <vaadin-button @click=${this.openDialog}>Open dialog</vaadin-button>
                </vaadin-vertical-layout>
      <test-date-dialog id="test-date" .dialogOpened="${this.dialogOpened}" @test_dialog_closed="${this.onDialogOpenedChanged}" ></test-date-dialog>
     `;
    }

    protected firstUpdated() {
        this.initDates();
    }

    private initDates() {
        const i18n = {
            today: '___TODAY___',
        };
        if (this.datePicker) {
            this.datePicker.i18n = {
                ...this.datePicker.i18n,
                ...i18n
            }
        }
    }

    private openDialog() {
        this.dialogOpened = true
        if(this.dialog){
            this.dialog.initDates() //1 Is this okay?
        }
    }

    onDialogOpenedChanged(e: CustomEvent) {
        this.dialogOpened = e.detail.value;
    }

测试日期dialog.ts

@customElement('test-date-dialog')
export class TestDateDialog extends View {

    @state()
    private dialogOpened = false;

    @query('#date11')
    private datePicker?: DatePicker;

    render() {
        return html`      
      <vaadin-dialog id="testD" no-close-on-outside-click no-close-on-esc  .opened=${this.dialogOpened}
         @opened-changed="${(e: CustomEvent) => this.openDialog(e.detail.value)}"        
        .renderer="${guard([], () => (root: HTMLElement) => {
            render(html`<vaadin-vertical-layout>
                 <vaadin-horizontal-layout class="w-full">                   
                    <vaadin-button theme="icon tertiary contrast" @click="${() => this.cancel()}">
                    <vaadin-icon slot="prefix" icon="vaadin:close-big"></vaadin-icon></vaadin-button>
                </vaadin-horizontal-layout>
               <vaadin-date-picker id="date11">
                                </vaadin-date-picker>
              </vaadin-vertical-layout>
            `, root);
        })}"></vaadin-dialog>    
     `;
    }

    private openDialog(open: boolean) {
        this.dialogOpened = open;
        //if (open) {
            //this.initDates(); //2   Is this okay?
        //}
    }

    //protected firstUpdated() {
    //    this.initDates(); 
    //}

    initDates() {
        console.log(this.shadowRoot?.querySelector('#date11')) //undefined
        console.log(this.querySelector('#date11')) //null
        console.log(this.datePicker)  //null

        const i18n = {
            today: '___TODAY___'
        };
        if (this.datePicker) {
            this.datePicker.i18n = {
                ...this.datePicker.i18n,
                ...i18n
            }
        }
    }

    cancel() {
        const options = {
            detail: {
                opened: false
            },
            bubbles: true,
            composed: true
        };
        this.dispatchEvent(new CustomEvent<CancelButtonEvent>('test_dialog_closed', options));

        this.dialogOpened = false;
    }

打开对话框后如何做一些初始化工作(使用异步后端调用),不仅使用@property,还使用@query 组件?

我在 JS / TS / Lit 方面经验很少,也许我做错了什么。

4

1 回答 1

1

装饰器不适用于渲染器函数生成的@query对话框内容,因为所有对话框内容都被传输到单独的覆盖元素中,该元素不是test-date-dialog. 例如,您可以通过检查浏览器开发工具中的对话框内容来确认这一点。装饰器在这种@query情况下不起作用,因为它只查找应用它的元素的子元素。

这里的一种解决方案可能是将对话框内容从渲染器函数中提取到单独的 Lit 组件中(例如TestDateDialogContent),然后在渲染器函数中渲染该组件。然后TestDateDialogContent,您可以使用@query装饰器访问日期选择器。您还可以使用常规生命周期方法(例如firstUpdated)进行其他初始化,例如在日期选择器上设置 I18N 设置,或对后端进行异步调用。

test-date-dialog-content.ts

@customElement('test-date-dialog-content')
class TestDialogContent extends LitElement {
  @query('#date11')
  private datePicker!: DatePicker;

  protected firstUpdated() {
    this.initDates();
  }

  private initDates() {
    const i18n = {
      today: '___TODAY___'
    };
    this.datePicker.i18n = {
      ...this.datePicker.i18n,
      ...i18n
    };
  }

  render() {
    return html`
      <vaadin-vertical-layout>
        ...
        <vaadin-date-picker id="date11"></vaadin-date-picker>
        ...
      </vaadin-vertical-layout>
    `;
  }
}

test-date-dialog.ts

<vaadin-dialog
  .renderer="${guard([], () => (root: HTMLElement) => render(html` <test-date-dialog-content></test-date-dialog-content>`, root))}"
>
</vaadin-dialog>

理想情况下,您希望尽可能避免以命令方式访问日期选择器等单个元素,并改用 Lit 属性绑定 ( <some-element .some-property="${this.someValue}">)。但是在这种情况下,如果您想使用一些自定义值来扩展日期选择器的 I18N 设置,这是不可避免的。结合对话框将其内容传输到单独的元素中,这使得这个用例更加复杂。

于 2021-12-07T16:25:22.173 回答