真实的国产乱ⅩXXX66竹夫人,五月香六月婷婷激情综合,亚洲日本VA一区二区三区,亚洲精品一区二区三区麻豆

成都創(chuàng)新互聯(lián)網(wǎng)站制作重慶分公司

Vue3+hook如何實(shí)現(xiàn)彈窗組件

本文小編為大家詳細(xì)介紹“Vue3+hook如何實(shí)現(xiàn)彈窗組件”,內(nèi)容詳細(xì),步驟清晰,細(xì)節(jié)處理妥當(dāng),希望這篇“Vue3+hook如何實(shí)現(xiàn)彈窗組件”文章能幫助大家解決疑惑,下面跟著小編的思路慢慢深入,一起來(lái)學(xué)習(xí)新知識(shí)吧。

成都創(chuàng)新互聯(lián)公司的客戶(hù)來(lái)自各行各業(yè),為了共同目標(biāo),我們?cè)诠ぷ魃厦芮信浜?,從?chuàng)業(yè)型小企業(yè)到企事業(yè)單位,感謝他們對(duì)我們的要求,感謝他們從不同領(lǐng)域給我們帶來(lái)的挑戰(zhàn),讓我們激情的團(tuán)隊(duì)有機(jī)會(huì)用頭腦與智慧不斷的給客戶(hù)帶來(lái)驚喜。專(zhuān)業(yè)領(lǐng)域包括網(wǎng)站設(shè)計(jì)、成都做網(wǎng)站、電商網(wǎng)站開(kāi)發(fā)、微信營(yíng)銷(xiāo)、系統(tǒng)平臺(tái)開(kāi)發(fā)。

要封裝什么

如果是普通彈窗使用的話,直接使用el-dialog組件已經(jīng)足夠了

但我還是一個(gè)比較愛(ài)折騰的人,我們先看看官方dialog文檔有什么可以添加的功能

...

大概看了一下,我打算封裝一下功能

  • 提供全屏操作按鈕(右上角)

  • 默認(rèn)提供“確認(rèn)”,“關(guān)閉”按鈕

  • 內(nèi)部添加Loading效果

封裝Dialog

確定了要封裝的功能之后,先來(lái)一個(gè)簡(jiǎn)單的dialog組件。

把雙向綁定處理一下,這樣外部就可以直接通過(guò)v-model直接控制彈窗了。



interface PropsType {
  modelValue?: boolean;
}

const props = withDefaults(defineProps(), {
  modelValue: false,
});

const emits = defineEmits<{
  (e: "update:modelValue"): void;
}>();

header

這里使用到圖標(biāo)庫(kù)@element-plus/icons-vue

如沒(méi)有安裝,請(qǐng)執(zhí)行npm install @element-plus/icons-vue

使用el-dialog提供的header插槽,將全屏圖表和關(guān)閉圖標(biāo)放置到右上角中。給el-dialog傳遞show-close屬性關(guān)閉默認(rèn)圖標(biāo)。


  


import { FullScreen, Close } from "@element-plus/icons-vue";


// 處理樣式
:deep(.el-dialog__header) {
  border-bottom: 1px solid #eee;
  display: flex;
  padding: 12px 16px;
  align-items: center;
  justify-content: space-between;
  margin: 0;
}
.dialog-title {
  line-height: 24px;
  font-size: 18px;
  color: #303133;
}
.btns {
  display: flex;
  align-items: center;
  i {
    margin-right: 8px;

    font-size: 16px;
    cursor: pointer;
  }
  i:last-child {
    margin-right: 0;
  }
}

彈窗的標(biāo)題文字內(nèi)容通過(guò)props進(jìn)行傳遞,默認(rèn)為空(''


interface PropsType {
  // 忽略之前的代碼
  title?: string;
}

const props = withDefaults(defineProps(), {
  title: "",
});

我們看看現(xiàn)在頭部的效果(這里沒(méi)傳入標(biāo)題,默認(rèn)為''

Vue3+hook如何實(shí)現(xiàn)彈窗組件

現(xiàn)在這個(gè)按鈕只有樣式效果,還沒(méi)有寫(xiě)上對(duì)應(yīng)的功能 ~

給他們先綁定上對(duì)應(yīng)的事件和指令


    


import { FullScreen, Close } from "@element-plus/icons-vue";

interface PropsType {
  title?: string;
  modelValue?: boolean;
  hiddenFullBtn?: boolean;
}

const props = withDefaults(defineProps(), {
  title: "",
  modelValue: false,
  hiddenFullBtn: false,
});

const emits = defineEmits<{
  (e: "update:modelValue"): void;
  (e: "close"): void;
}>();

// 當(dāng)前是否處于全屏狀態(tài)
const isFullscreen = ref(false);
// 是否顯示全屏效果圖標(biāo)
const isFullScreenBtn = computed(() => {
  if (props.hiddenFullBtn) return false;
  if (attrs?.fullscreen) return false;
  return true;
});

// 開(kāi)啟、關(guān)閉全屏效果
const handleFullscreen = () => {
  if (attrs?.fullscreen) return;
  isFullscreen.value = !isFullscreen.value;
};

// 關(guān)閉彈窗時(shí)向外部發(fā)送close事件
const handleClose = () => {
  emits("close");
};

NICE 頭部功能也就完成了

Footer

接下來(lái),再處理下底部?jī)?nèi)容,默認(rèn)提供兩個(gè)按鈕,分別是“確定”和“關(guān)閉”,這個(gè)名稱(chēng)也是可以通過(guò)props屬性修改的。

兩個(gè)按鈕綁定點(diǎn)擊事件,向外發(fā)送不同的事件。


    
  
import { useSlots } from "vue"; // 獲取插槽 const slots = useSlots(); interface PropsType {     title?: string;     width?: string | number;     isDraggable?: boolean;     modelValue?: boolean;     hiddenFullBtn?: boolean;     confirmText?: string;     cancelText?: string; } const props = withDefaults(defineProps(), {     title: "",     isDraggable: false,     modelValue: false,     hiddenFullBtn: false,     confirmText: "確認(rèn)",     cancelText: "關(guān)閉", }); const handleClose = () => {     emits("close"); }; const handleConfirm = () => {     emits("confirm"); };

Vue3+hook如何實(shí)現(xiàn)彈窗組件

又搞定了一部分了,就剩下Content了 ~

Content

彈窗內(nèi)容通過(guò)默認(rèn)插槽的方式傳入進(jìn)來(lái),在外層的div元素上添加v-loading標(biāo)簽,實(shí)現(xiàn)加載態(tài)。

如果你想整個(gè)彈窗實(shí)現(xiàn)loading效果,請(qǐng)把v-loading移到最外層元素即可。 注意不能是el-dialog元素上,否則無(wú)法實(shí)現(xiàn) 可能是el-dialog使用了teleport組件,導(dǎo)致v-loading無(wú)法正常工作。 等有空研究一下 ~



interface PropsType {
  loading?: boolean;
}

const props = withDefaults(defineProps(), {
  loading: false,
});

試試看中間的loading效果

剩下一些細(xì)節(jié)處理

el-dialog組件提供了很多個(gè)props屬性供用戶(hù)選擇,但我們現(xiàn)在封裝的dialog組件只使用到了一小部分props屬性。當(dāng)用戶(hù)想要使用其他的props屬性時(shí)該怎么辦?

例如使用width屬性時(shí),難道要在我們封裝的組件中接收props.width再傳遞給組件嗎?

不不不,還有另外一種方法,還記得剛剛在做全屏操作的時(shí)候使用到的useAttrs輔助函數(shù)嗎

它可以獲取當(dāng)前組件傳遞進(jìn)來(lái)的屬性。有了這個(gè)方法之后,再配合并即可將外部傳遞進(jìn)來(lái)的函數(shù)再傳遞到el-dialog組件上面啦


    

為了避免內(nèi)部傳遞的props被覆蓋掉,v-bind="attrs"需要放在最前面

在使用時(shí),可能會(huì)給before-close屬性傳遞一個(gè)函數(shù),但到了后面被內(nèi)部的handleClose方法給覆蓋掉了。

解決方案是在handleClose函數(shù)中,獲取attrs.['before-close']屬性,如果類(lèi)型是函數(shù)函數(shù),先執(zhí)行它。

const handleClose = () => {
  if (
    Reflect.has(attrs, "before-close") &&
    typeof attrs["before-close"] === "function"
  ) {
    attrs["before-close"]();
  }
  emits("close");
};

有關(guān)于el-dialog組件的封裝就到這里了

封裝hooks

利用Vue composition Api再封裝一下在使用el-dialog組件狀態(tài)的管理hook

useDialog

簡(jiǎn)單處理顯示和加載態(tài)開(kāi)關(guān)的hook

import { ref } from "vue";

export default function useDialog() {
  const visible = ref(false);
  const loading = ref(false);
  const openDialog = () => (visible.value = true);
  const closeDialog = () => (visible.value = false);
  const openLoading = () => (loading.value = true);
  const closeLoading = () => (loading.value = false);
  return {
    visible,
    loading,
    openDialog,
    closeDialog,
    openLoading,
    closeLoading,
  };
}

useDialog Demo

Vue3+hook如何實(shí)現(xiàn)彈窗組件



import useDialog from "./components/useDialog";
import DialogCmp from "./components/Dialog.vue";

const {
  visible: visible1,
  openDialog: openDialog1,
  closeDialog: closeDialog1,
} = useDialog();

useDialogState 和 useDialogWithForm

useDialogState

針對(duì)開(kāi)發(fā)管理后臺(tái)彈窗狀態(tài)封裝的一個(gè)hook,搭配下面的useDialogWithForm使用。

export enum MODE {
  ADD,  EDIT,
}
import { ref } from "vue";
import { MODE } from "./types";
export default function useDialogState() {
  const mode = ref(MODE.ADD);
  const visible = ref(false);
  const updateMode = (target: MODE) => {
    mode.value = target;
  };
  return { mode, visible, updateMode };
}

useDialogWithForm

針對(duì)表單彈窗組件封裝的hooks,接收一個(gè)formRef實(shí)例,負(fù)責(zé)控制彈窗內(nèi)標(biāo)題及清空表單中的校驗(yàn)結(jié)果,減少多余的代碼 ~

import { FormInstance } from "element-plus";
import { Ref, ref } from "vue";
import { MODE } from "./types";
import useDialogState from "./useDialogState";

export default function useDialogFn(
  formInstance: Ref
) {
  const { visible, mode, updateMode } = useDialogState();

  const closeDialog = () => {
    formInstance.value.resetFields();
    visible.value = false;
  };
  const openDialog = (target: MODE) => {
    updateMode(target);
    visible.value = true;
  };
  return { visible, mode, openDialog, closeDialog };
}

useDialogWithForm Demo

Vue3+hook如何實(shí)現(xiàn)彈窗組件



import { ElMessage, FormInstance } from "element-plus";
import { Ref, ref } from "vue";
import Dialog from "./Dialog.vue";
import { MODE } from "./types";
import useDialogWithForm from "./useDialogWithForm";

const rules = {
  name: {
    type: "string",
    required: true,
    pattern: /^[a-z]+$/,
    trigger: "change",
    message: "只能是英文名稱(chēng)哦",
    transform(value: string) {
      return value.trim();
    },
  },
  age: {
    type: "string",
    required: true,
    pattern: /^[0-9]+$/,
    trigger: "change",
    message: "年齡只能是數(shù)字哦",
    transform(value: string) {
      return value.trim();
    },
  },
  mobile: {
    type: "string",
    required: true,
    pattern:
      /^(?:(?:\+|00)86)?1(?:(?:3[\d])|(?:4[5-79])|(?:5[0-35-9])|(?:6[5-7])|(?:7[0-8])|(?:8[\d])|(?:9[189]))\d{8}$/,
    trigger: "change",
    message: "請(qǐng)輸入正確的手機(jī)號(hào)碼",
    transform(value: string) {
      return value.trim();
    },
  },
};

interface FromDataType {
  name: string;
  age: string;
  mobile: string;
}

const formDataRef = ref(null);

let formData = ref({
  name: "",
  age: "",
  mobile: "",
});

const { visible, closeDialog, openDialog, mode } = useDialogWithForm(
  formDataRef as Ref
);
const confirm = () => {
  if (!formDataRef.value) return;
  formDataRef.value.validate((valid) => {
    if (valid) {
      console.log("confirm");
      ElMessage({
        message: "提交成功",
        type: "success",
      });
      closeDialog();
    }
  });
};

const customClose = () => {
  ElMessage({
    message: "取消提交",
    type: "info",
  });
  closeDialog();
};
defineExpose({
  closeDialog,
  openDialog,
});

讀到這里,這篇“Vue3+hook如何實(shí)現(xiàn)彈窗組件”文章已經(jīng)介紹完畢,想要掌握這篇文章的知識(shí)點(diǎn)還需要大家自己動(dòng)手實(shí)踐使用過(guò)才能領(lǐng)會(huì),如果想了解更多相關(guān)內(nèi)容的文章,歡迎關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道。


新聞標(biāo)題:Vue3+hook如何實(shí)現(xiàn)彈窗組件
當(dāng)前URL:http://weahome.cn/article/gicddp.html

其他資訊

在線咨詢(xún)

微信咨詢(xún)

電話咨詢(xún)

028-86922220(工作日)

18980820575(7×24)

提交需求

返回頂部