Vue 2의 약속 기반 대화 상자

11876 단어 vuejavascript
대화 상자는 응용 프로그램 "외부"에 시각적으로 존재하며, 그 때문에 대화 상자가 속하지 않는 위치에 대화 상자를 포함시키는 것이 옳다고 느껴본 적이 없습니다. 대화 상자에 관한 HTML은 종종 응용 프로그램의 루트 또는 대화 상자가 호출되는 구성 요소에 배치되고 일반적으로 포털에 의해 맨 위로 전송됩니다. 어떤 대화 상자가 언제 팝업되어야 하는지를 제어하는 ​​논리도 저장소나 구성 요소에 있거나 자체 서비스가 있을 수 있습니다. 때로는 대화를 제어하기 위한 논리가 기능에 부족하여 다른 대화 상자 내에서 대화를 열 수 없는 경우가 있습니다. 우리가 그것을 필요로 하는 경우에 너무 나쁩니다.

대화 상자를 함수로 처리하는 것만으로 모든 문제를 해결할 수 있다고 생각합니다. 대화를 원하십니까? 이를 호출하고 매개변수로 표시하려는 구성 요소를 넣습니다. 프라미스로 래핑할 수 있으므로 대화 상자가 언제 닫히고 어떤 결과가 나오는지 정확히 알고 이를 기반으로 몇 가지 호출을 수행합니다.

내가 어떻게 작업하는지 시각화하기 위해 아래 스니펫을 만들었습니다.

const success = await openDialog(ConfirmDialog)
if (success) {
  this.fetchData()
}


대화와 관련된 모든 논리를 스스로 수행할 때의 이점은 우리가 이를 완전히 제어할 수 있고 필요에 따라 새로운 기능을 추가하고 대화를 원하는 대로 만들 수 있다는 것입니다. 그럼 빌드를 해보자.

먼저 Dialog Wrapper 컴포넌트를 생성해야 합니다. 그 목적은 대화 상자를 닫기 위한 기본 스타일과 일부 논리를 제공하는 것입니다.

<template>
  <div class="dialog-container">
    <span class="dialog-mask" @click="$emit('close')"></span>
    <component :is="dialogComponent" @close="response => $emit('close', response)"
               v-bind="props"/>
  </div>
</template>
<script>
export default {
  name: 'DialogWrapper',
  props: ['dialogComponent', 'props']
}
</script>
<style>
.dialog-container {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 1001;
}
.dialog-mask {
  position: fixed;
  width: 100%;
  height: 100%;
  background-color: rgba(0, 0, 0, 0.4);
}
</style>


자신에게 맞게 스타일을 변경할 수 있습니다. 추가 로직을 추가할 수도 있고 애니메이션 및 기타 기능을 추가할 수도 있지만 단순하게 유지하고 싶었습니다. 당신은 dialogComponentprops (혼란스러운, 나는 안다)의 두 가지 소품을 얻게 될 것입니다.
  • dialogComponent는 내부에서 렌더링될 Vue 구성 요소입니다
  • .
  • 소품은 dialogComponent에 전달된 소품입니다.

  • 이벤트 닫기를 내보내서 대화 상자를 닫고 약속을 해결할 때 사용할 값을 전달하려면 이벤트와 함께 데이터를 전달합니다. $emit('close', 'success!') .

    이제 함수를 만들어 봅시다.

    export function openDialog (dialogComponent, props) {
      return new Promise((resolve) => {
        const Wrapper = Vue.extend(DialogWrapper)
        const dialog = new Wrapper({
          propsData: {
            dialogComponent,
            props,
          },
          router, // optional, instance of vue router
          store, // optional, instance of vuex store
        }).$mount()
        document.body.appendChild(dialog.$el);
    
        dialog.$on('close', function (value) {
          dialog.$destroy();
          dialog.$el.remove();
          resolve(value)
        })
      })
    }
    


    새 Vue 인스턴스를 만들고 document.body 에 추가합니다. DialogWrapper를 메인 컴포넌트로 사용하고 propsData 속성을 사용하여 함수 매개변수를 props로 전달합니다. 또한 자신을 파괴할 위치를 알기 위해 close 이벤트를 수신합니다.

    사용하는 경우 구성 요소를 초기화할 때 routerstore 속성을 추가하는 것이 중요합니다. 그렇지 않으면 구성 요소가 $store$router 에 액세스할 수 없기 때문입니다.

    그래서 우리는 대화 기능이 작동하고 있지만 이 기사의 편의를 위해 사용하는 많은 코드를 잘라내고 핵심 로직만 남겨두었습니다. 다른 구성 요소를 만드는 것이 좋습니다. DialogLayout라고 하면 패딩이 있는 실제 흰색 상자가 만들어집니다. 원한다면 더 많은 노력을 기울일 수 있습니다. 예를 들어 대화 제목 또는 닫기 버튼을 추가합니다.

    <template>
      <div class="dialog-content">
        <slot></slot>
      </div>
    </template>
    
    <style scoped>
    .dialog-content {
      width: 60%;
      position: relative;
      margin: 100px auto;
      padding: 20px;
      background-color: #fff;
      z-index: 20;
    }
    </style>
    


    이제 기사의 테스트 부분으로 이동할 수 있습니다.

    나중에 openDialog 매개 변수로 전달할 예제 구성 요소를 만들어 보겠습니다.

    <template>
      <DialogLayout>
        <button @click="$emit('close', 'wow! success')">Close dialog</button>
      </DialogLayout>
    </template>
    


    확인된 값'wow! success으로 대화 상자를 닫는 버튼이 있습니다. 또한 몇 가지 기본 스타일링에 DialogLayout를 사용합니다.

    응용 프로그램의 어딘가에서 함수를 호출할 수 있습니다.

        async onBtnClick () {
          const result = await openDialog(DialogExample)
          // dialog is now closed
          console.log(result) // 'wow! success'
        }
    


    약간의 초기 구성이 필요하지만 투자 회수가 막대합니다. 나는 몇 년 동안 그것을 사용하고 있으며 내 요구에 완벽하게 맞습니다. 또한 추가 기능으로 쉽게 확장할 수 있습니다.

    이 대화 상자는 애니메이션되지 않는다는 점에 유의하는 것이 중요합니다. 애니메이션은 아주 쉽게 추가할 수 있지만 이 기사의 범위를 벗어납니다.

    읽어주셔서 감사합니다. 질문이 있으시면 댓글이나 이메일을 보내주세요 - [email protected] . 좋은 하루 되세요!

    좋은 웹페이지 즐겨찾기