欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

用vue3封裝一個(gè)符合思維且簡單實(shí)用的彈出層

 更新時(shí)間:2022年05月26日 08:59:03   作者:LinkandZelda  
最近新項(xiàng)目中需要一個(gè)彈窗組件,所以我就做了一個(gè),下面這篇文章主要給大家介紹了關(guān)于如何利用vue3封裝一個(gè)符合思維且簡單實(shí)用的彈出層,文中通過實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下

前言

在平常開發(fā)中,彈出層算是一個(gè)最常用的組件了,尤其是后臺的表單頁,詳情頁,用戶端的各種確認(rèn)都很適合使用彈出層組件展示,但是一般組件庫提供給我們的一般還是組件的形式,或者是一個(gè)簡單的服務(wù)。

組件形式的彈出層,在我看來應(yīng)該是組件庫提供給我們二次封裝用的,如果直接其實(shí)很不符合直覺

  • 寫在頁面結(jié)構(gòu)里,但是卻不是在頁面結(jié)構(gòu)中展示,放在那個(gè)位置都不合適只能放在最下邊

  • 一個(gè)頁面如果只有一個(gè)彈出層還好維護(hù),多幾個(gè)先不說放在那里,光維護(hù)彈出層的展示隱藏變量都是件頭大的事情

  • 彈出層中間展示的如果是一個(gè)表單或者一個(gè)業(yè)務(wù)很重的頁面,邏輯就會跟頁面混在一起不好維護(hù),如果抽離成組件,在后臺這種全是表格表單的時(shí)候,都抽離成組件太過麻煩

那么有沒有更符合思維的方式使用彈窗呢,嘿嘿還真有,那就是服務(wù)創(chuàng)建彈出層

服務(wù)式彈出層

等等!如果是服務(wù)創(chuàng)建彈出層每個(gè)ui組件庫基本都提供了,為什么還要封裝呢?因?yàn)榻M件庫提供的服務(wù)一般都是用于簡單的確認(rèn)彈窗,如果是更重的表單彈窗就難以用組件庫提供的服務(wù)創(chuàng)建了,我們以ant-design-vue的modal為例子看看。

<template> 
    <a-button @click="showConfirm">Confirm</a-button>
</template>
<script lang="ts">
import { ExclamationCircleOutlined } from '@ant-design/icons-vue';
import { createVNode, defineComponent } from 'vue';
import { Modal } from 'ant-design-vue';

export default defineComponent({ 
    setup() {
     const showConfirm = () => { 
       Modal.confirm({ 
          title: 'Do you want to delete these items?',
          icon: createVNode(ExclamationCircleOutlined),
          content: 'When clicked the OK button, this dialog will be closed after 1 second', 
          onOk() { 
            return new Promise((resolve, reject) => { 
              setTimeout(Math.random() > 0.5 ? resolve : reject, 1000); 
             }).catch(() => console.log('Oops errors!')); }, 
              // eslint-disable-next-line @typescript-eslint/no-empty-function 
          onCancel() {},
        });
       }; 
     return { showConfirm, };
     },
    }); 
</script>

可以看到modal提供了屬性content,在文檔里我們可以看到他的類型是可以傳vue組件,但是這樣寫是有弊端的,我們無法在content中的組件關(guān)閉modal,想要在子組件關(guān)閉Modal需要把Modal本身傳遞給子組件,然后觸發(fā)destroy();。

顯然modal中是一個(gè)表單和重業(yè)務(wù)的組件時(shí),是很難支持我們的工作的,一是沒法簡單直接的在子組件關(guān)閉彈出層,二是content中的組件傳遞值給父組件使用也比較麻煩。

用Promise來創(chuàng)建吧!

promise來創(chuàng)建,我們通過在close時(shí)觸發(fā)resolve,還可以通過resolve傳值,來觸發(fā)then,這樣非常符合邏輯和語意。
事不宜遲我們以element-plusdialog為例子,來看看如何用Promise封裝彈出層。

// useDialog.ts
import {
  createApp,
  createVNode,
  defineComponent,
  h,
  ref,
  onUnmounted,
} from "vue";

import { ElDialog } from "element-plus";

import type { App, Component, ComputedOptions, MethodOptions } from "vue";
//引入dialog的類型
import type { DialogProps } from "element-plus";

export type OverlayType = {
  component: Component<any, any, any, ComputedOptions, MethodOptions>;
  options?: Partial<DialogProps>;
  params?: any;
};

export class OverlayService {
  //overlay的vue實(shí)例
  private OverlayInstance!: App;
  
  // ui庫的組件一般都帶有動畫效果,所以需要維護(hù)一個(gè)布爾值,來做展示隱藏
  public show = ref<boolean>(false);

  // 組件庫的options
  private options: Partial<DialogProps> = {};

  //在open中傳遞給子組件的參數(shù)
  private params: any = {};

  //掛載的dom
  public overlayElement!: Element | null;

  //子組件
  private childrenComponent!: Component<
    any,
    any,
    any,
    ComputedOptions,
    MethodOptions
  >;

  //close觸發(fā)的resolve,先由open創(chuàng)建賦予
  private _resolve: (value?: unknown) => void = () => {};

  private _reject: (reason?: any) => void = () => {};

  constructor() {
    this.overlayElement = document.createElement("div");
    document.body.appendChild(this.overlayElement);
    onUnmounted(() => {
      //離開頁面時(shí)卸載overlay vue實(shí)例
      this.OverlayInstance?.unmount();
      if (this.overlayElement?.parentNode) {
        this.overlayElement.parentNode.removeChild(this.overlayElement);
      }
      this.overlayElement = null;
    });
  }
 
  private createdOverlay() {
    const vm = defineComponent(() => {
      return () =>
        h(
          ElDialog,
          {
            //默認(rèn)在彈窗關(guān)閉時(shí)銷毀子組件
            destroyOnClose: true,
            ...this.options,
            modelValue: this.show.value,
            onClose: this.close.bind(this),
          },
          {
            default: () =>
              createVNode(this.childrenComponent, {
                close: this.close.bind(this),
                params: this.params,
              }),
          }
        );
    });
    if (this.overlayElement) {
      this.OverlayInstance = createApp(vm);
      this.OverlayInstance.mount(this.overlayElement);
    }
  }
  //打開彈窗的方法 返回promsie
  public open(overlay: OverlayType) {
    const { component, params, options } = overlay;
    this.childrenComponent = component;
    this.params = params;
    if (options) {
      this.options = options;
    }
    return new Promise((resolve, reject) => {
      this._resolve = resolve;
      this._reject = reject;
      //判斷是否有overlay 實(shí)例
      if (!this.OverlayInstance) {
        this.createdOverlay();
      }
      this.show.value = true;
    });
  }

  //彈窗的關(guān)閉方法,可以傳參觸發(fā)open的promise下一步
  public close(msg?: any) {
    if (!this.overlayElement) return;
    this.show.value = false;
    if (msg) {
      this._resolve(msg);
    } else {
      this._resolve();
    }
  }
}

//創(chuàng)建一個(gè)hooks 好在setup中使用
export const useDialog = () => {
  const overlayService = new OverlayService();
  return {
    open: overlayService.open.bind(overlayService),
    close: overlayService.close.bind(overlayService),
  };
};

封裝好dialog服務(wù)之后,現(xiàn)在我們先創(chuàng)建一個(gè)子組件,傳遞給open的子組件會接受到close,params兩個(gè)props

<!--ChildDemo.vue -->
<template>
  <div>
   {{params}}
   
   <button @click="close('關(guān)閉了彈窗')" >關(guān)閉彈窗</button>
  </div>
</template>
<script lang="ts" setup>
const props = defineProps<{
  close: (msg?: any) => void;
  params: any;
}>();
</script>

然后我們在頁面使用open

<template>
  <div>
   <button @click="openDemo" >打開彈窗</button>
  </div>
</template>
<script lang="ts" setup>
import ChildDemo from './ChildDemo.vue' 
import { useDialog } from "./useDialog";

const { open } = useDialog();

const openDemo = () => {
  open({
    component: ChildDemo,
    options: { title: "彈窗demo" },
    params:{abc:'1'}
  }).then((msg)=>{
    console.log('關(guān)閉彈窗觸發(fā)',msg)
  });
};
</script>

好了到此我們就封裝了一個(gè)簡單實(shí)用的彈窗服務(wù)。

寫在后頭

其實(shí)這樣封裝的還是有一個(gè)小問題,那就是沒法拿到vue實(shí)例,只能拿到overlay的實(shí)例,因?yàn)閛verlay是重新創(chuàng)建的vue實(shí)例,所以不要使用全局注冊的組件,在子組件上單獨(dú)引入,pinia,vuex,router這些當(dāng)params做傳入子組件。

如果不想自己封裝,可以用我寫的庫vdi useOverlay hook搭配任意的ui組件庫,vdi還提供了更好的依賴注入嗷。如果搭配vdi的vueModule使用,就沒有上面說的問題了

到此這篇關(guān)于用vue3封裝一個(gè)符合思維且簡單實(shí)用的彈出層的文章就介紹到這了,更多相關(guān)vue3封裝彈出層內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • vue+vite+diff.js使用小結(jié)

    vue+vite+diff.js使用小結(jié)

    本文主要介紹了vue+vite+diff.js使用小結(jié),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-12-12
  • 詳解Vue項(xiàng)目的打包方式(生成dist文件)

    詳解Vue項(xiàng)目的打包方式(生成dist文件)

    本文主要介紹了詳解Vue項(xiàng)目的打包方式(生成dist文件),文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-01-01
  • vue監(jiān)聽頁面中的某個(gè)div的滾動事件并判斷滾動的位置

    vue監(jiān)聽頁面中的某個(gè)div的滾動事件并判斷滾動的位置

    本文主要介紹了vue監(jiān)聽頁面中的某個(gè)div的滾動事件并判斷滾動的位置,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-03-03
  • vue3保存屬性自動換行問題及解決

    vue3保存屬性自動換行問題及解決

    這篇文章主要介紹了vue3保存屬性自動換行問題及解決方案,具有很好的參考價(jià)值,希望對大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2024-03-03
  • vue實(shí)現(xiàn)表單驗(yàn)證小功能

    vue實(shí)現(xiàn)表單驗(yàn)證小功能

    這篇文章主要為大家詳細(xì)介紹了vue實(shí)現(xiàn)表單驗(yàn)證小功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-09-09
  • vue樣式穿透 ::v-deep的具體使用

    vue樣式穿透 ::v-deep的具體使用

    這篇文章主要介紹了vue樣式穿透 ::v-deep的具體使用,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-06-06
  • vue彈出框組件封裝實(shí)例代碼

    vue彈出框組件封裝實(shí)例代碼

    這篇文章主要介紹了vue彈出框組件封裝,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2019-10-10
  • 關(guān)于vue.extend的使用及說明

    關(guān)于vue.extend的使用及說明

    這篇文章主要介紹了關(guān)于vue.extend的使用及說明,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-03-03
  • Vue3.0的優(yōu)化總結(jié)

    Vue3.0的優(yōu)化總結(jié)

    在本篇文章里小編給大家整理的是一篇關(guān)于Vue3.0的優(yōu)化總結(jié)內(nèi)容,有需要的朋友們可以學(xué)習(xí)下。
    2020-10-10
  • vue如何通過點(diǎn)擊事件實(shí)現(xiàn)頁面跳轉(zhuǎn)詳解

    vue如何通過點(diǎn)擊事件實(shí)現(xiàn)頁面跳轉(zhuǎn)詳解

    頁面跳轉(zhuǎn),我們一般都通過路由跳轉(zhuǎn)實(shí)現(xiàn),通常情況下可直接使用router-link標(biāo)簽實(shí)現(xiàn)頁面跳轉(zhuǎn),下面這篇文章主要給大家介紹了關(guān)于vue如何通過點(diǎn)擊事件實(shí)現(xiàn)頁面跳轉(zhuǎn)的相關(guān)資料,需要的朋友可以參考下
    2022-07-07

最新評論