npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

vue-use-modal-context

v0.6.2

Published

Vue modal helpers for simplify modal usage

Downloads

15

Readme

vue-use-modal-context

這是一個讓使用 modal 更簡便的工具。使用 Vue 3 provide / inject。請先了解後再使用。

提供開關 modal 以及傳遞資料更簡單的寫法,我想應該可以減輕一些設定 modal 時的工作。

支援 Vue 3+。

不包含 modal 本身。如果你在挑選 modal 的套件,你可以考慮 vue-final-modal

Install

npm install vue-use-modal-context

你可以使用 plugin 全域註冊元件 <ModalContext>, <ModalProvider>。 (請傳入 component: true

import { ModalContextPlugin } from "vue-use-modal-context"

const app = createApp(App)

app.use(ModalContextPlugin, { component: true })

app.mount('#app')

或是直接引入也可以。

import { ModalContext, ModalProvider } from "vue-use-modal-context"

設定 global component type

Tutorial

首先看一下一個普通的使用 modal 的範例。

這是我經常遇到的情況:為了設定一個 modal,我需要設定 show, openModal, modalData .....。如果有 10 個 modal,就必須設定 10 次。

<script setup>
import { ref } from 'vue'

const show = ref(false)
const modalData = ref({
  userId: 0
})

const openModal = (userId) => {
  show.value = true
  modalData.userId = userId
}

const onModalClose = () => {
  modalData.userId = 0
}
</script>
<template>
  <div>
    <button @click="openModal(81383)">Show user</button>
    <UserModal v-model="show" :user-id="modalData.userId" @close="onModalClose()">
      <!-- Modal content -->
    </UserModal>
  </div>

</template>

現在試著使用 vue-use-modal-context 中提供的工具 useModalContext 以及 ModalProvider 簡化這個範例。首先呼叫 useModalContext(),你可以得到 openModal

<!-- Step 1: call useModalContext -->
<script setup>
import { useModalContext, ModalProvider } from "vue-use-modal-context"

const { openModal } = useModalContext()
</script>
<template>
  <div>
    
  </div>
</template>

接著你需要加入 ModalProvider,將一個 modal 註冊到 modalContext 中。我們註冊了一個 modal,名稱是 UserModal

<!-- Step 2: use ModalProvider to register modal -->
<script setup>
import { useModalContext, ModalProvider } from "vue-use-modal-context"

const { openModal } = useModalContext()
</script>
<template>
  <div>
    <ModalProvider name="UserModal">

    </ModalProvider>
  </div>
</template>

接著可以從 ModalProvider 的 scoped slot 中取得 modal 的狀態,有 show 以及 data,我們將這兩個資料連接到 Modal 上。 並且設定初始的資料 init-data

<!-- Step 3: connect ModalProvider to UserModal -->
<script setup>
import { useModalContext, ModalProvider } from "vue-use-modal-context"

const { openModal } = useModalContext()
</script>
<template>
  <div>
    <ModalProvider v-slot="{ modal }" name="UserModal" :init-data="{ userId: 0 }">
      <UserModal v-model="modal.show" :user-id="modal.data.userId"  />
    </ModalProvider>
  </div>
</template>

最後只要加上開啟 modal 的 button,在上面綁定 openModal 即可。

<!-- Step 4: openModal anywhere -->
<script setup>
import { useModalContext, ModalProvider } from "vue-use-modal-context"

const { openModal } = useModalContext()
</script>
<template>
  <div>
    <button @click="openModal('UserModal', { userId: 81383 })">Show user</button>
    <ModalProvider v-slot="{ modal }" name="UserModal" :init-data="{ userId: 0 }">
      <UserModal v-model="modal.show" :user-id="modal.data.userId"  />
    </ModalProvider>
  </div>
</template>

如果你想要新增一個 modal,那只要註冊新的 modalProvider 就好。

<!-- Step ex: use more modal -->
<script setup>
import { useModalContext, ModalProvider } from "vue-use-modal-context"

const { openModal } = useModalContext()
</script>
<template>
  <div>
    <button @click="openModal('UserModal', { userId: 81383 })">Show user</button>
    <button @click="openModal('OrderModal', { orderId: 233456 })">Show order</button>
    <button @click="openModal('PaymentModal', { paymentId: 33445 })">Show payment</button>

    <ModalProvider v-slot="{ modal }" name="UserModal" :init-data="{ userId: 0 }">
      <UserModal v-model="modal.show" :user-id="modal.data.userId"  />
    </ModalProvider>
    
    <ModalProvider v-slot="{ modal }" name="OrderModal" :init-data="{ orderId: 0 }">
      <UserModal v-model="modal.show" :user-id="modal.data.orderId"  />
    </ModalProvider>
    
    <ModalProvider v-slot="{ modal }" name="PaymentModal" :init-data="{ paymentId: 0 }">
      <UserModal v-model="modal.show" :user-id="modal.data.paymentId"  />
    </ModalProvider>
  </div>
</template>

useModalContext 也有元件的版本,如果你偏好使用元件也可以嘗試看看。

<!-- Step ex: ModalContext component -->
<script setup>
import { ModalContext, ModalProvider } from "vue-use-modal-context"

</script>
<template>
  <ModalContext v-slot="{ openModal, closeModal }">
    <div>
      <button @click="openModal('UserModal', { userId: 81383 })">Show user</button>
      <button @click="openModal('OrderModal', { orderId: 233456 })">Show order</button>
      <button @click="openModal('PaymentModal', { paymentId: 33445 })">Show payment</button>

      <ModalProvider v-slot="{ modal }" name="UserModal" :init-data="{ userId: 0 }">
        <UserModal v-model="modal.show" :user-id="modal.data.userId"  />
      </ModalProvider>
      
      <ModalProvider v-slot="{ modal }" name="OrderModal" :init-data="{ orderId: 0 }">
        <UserModal v-model="modal.show" :user-id="modal.data.orderId"  />
      </ModalProvider>
      
      <ModalProvider v-slot="{ modal }" name="PaymentModal" :init-data="{ paymentId: 0 }">
        <UserModal v-model="modal.show" :user-id="modal.data.paymentId"  />
      </ModalProvider>
    </div>
  </ModalContext>
</template>

Tutorial - global context

可能會需要一個可以跨元件,並且跨 context 的 global modal context。

這時候你可以使用 useGlobalModalContext

使用 global modal 需要註冊 plugin,請參考文件

setup global modal

你可以在任何一個地方設定 <ModalProvider>。記得,將他設定為 global。通常會放在 App.vue

<!-- App.vue -->
<template>
  <ModalProvider name="LoginModal" global>
    <!-- Do anything just like non-global modal -->
  </ModalProvider>
</template>

設定好之後,就可以在任何地方使用 useGlobalModalContext 開啟他

<!-- Child.vue -->
<script setup>
import { useGlobalModalContext } from "vue-use-modal-context"

const { openGlobalModal, patchGlobalModal, closeGlobalModal, } = useGlobalModalContext()

onMounted(() => {
  openGlobalModal("LoginModal")
})
</script>

documentation

useModalContext and <ModalContext>

useModalContext 是個 composition function。會對子元件用 provide 的方式傳遞 modal context 的資料。此外他會回傳 3 個函式。

  • openModal(name: string, data?: Record<string, any>) => void: 開啟指定 name 的 modal,並傳遞 data。傳遞 data 時會完全覆寫現有的 data。data 不是必傳的,有傳遞的話必須是個 Object,如果沒有傳,則 modal data 會是 initData。

  • closeModal(name: string) => void: 關閉指定 name 的 modal。

  • patchModal(name: string, data: Record<string, any> | (data) => Record<string, any>) => void:

    • 更新指定 modal 的 data。
    • 不是 overwrite,而是會以類似 Object.assign 的方式更新。
    • 建議 openModal 之後才做 patchModal
    • 0.3.0 版開始, data 可以是 update function。這個函式會接收現在的 modalData,並且會將回傳的物件合併到 modalData 上
// From 0.3.0
// patch modal by function data
patchModal("UserModal" ,(currentData) => {
  return currentData.userId === 123 ? { 
    order: [
      ...currentData.order,
      newOrder
    ]
  } : {}
})

<ModalContext>

<ModalContext>useModalContext 的元件版本,是個 renderless component。這三個函式也可以在 <ModalContext> 元件的 scoped slot 中取得。

<ModalContext v-slot="{ openModal, closeModal, patchModal}">
  <!--your content ....-->
</ModalContext>

你也可以透過 ref 在 setup 中存取 ModalContext 的方法。

<script setup>
import { ref, onMounted } from 'vue'

const ModalContextRef = ref()
onMounted(() => {
  if (ModalContextRef.value){
    ModalContextRef.value.openModal('UserModal', { userId: 3310 })
    // or closeModal, patchModal ....
  }
})
</script>
<template>
  <ModalContext v-slot="{ openModal, closeModal, patchModal}" ref="ModalContextRef">
    <!--your content ....-->
  </ModalContext>
</template>

useModalProvider and <ModalProvider>

<ModalProvider>useModalProvider 的元件版本,是個 renderless component。他會在自己所在 ModalContext 中註冊 modal。

他必須被放在 ModalContext 之中,換句話說,他的父元件或是更上層的元件必須要有 useModalContext 或是 ModalContext

<ModalProvider> 提供一些參數:

  • name: 必要參數。設定 modal 的名稱。這會對應 openModal 的第一參數。
  • init-data: 非必要參數。會決定 modal.data 的初始狀態。如果沒有傳,則預設 {}
  • global: boolean。是否屬於 globalModalContext ,default是false。(見 globalModalContext)
  • reset-after-close: boolean。是否在 close 之後 reset data 回 init-data。預設是 false

<ModalProvider> 提供的 scoped slot

  • modal: 有 modal 的狀態跟一些函式可以用。 是一個 reactive 物件,所以不要對這個物件做解構賦值

    • modal.show: boolean, modal 是開 or 關。
    • modal.data: 預設是 {},如果有傳 init-data 的話,則預設是 init-data。當呼叫 openModal 時,如果 openModal 有傳遞 data,則 modal.data 會變成該 data。呼叫 patchModal 時也可以修改 modal.data
  • closeAnd(fn: () => any): 關閉 modal ,並執行 fn。如果需要設定 event handler 時,這可以幫得上忙。

以下使用 closeAnd 的一個時機:

<ModalProvider v-slot="{ modal, closeAnd }" name="UserEditModal" :init-data="{ userId: 0 }">
  <Modal v-model="modal.show">
    <UserForm :user-id="modal.data.userId" @update-sucess="closeAnd(fetchUserList)" />
  </Modal>
</ModalProvider>

useModalProvider 是個 composition function。<ModalProvder> 內部就是使用 useModalProvider

參數:(name: string, initData: Record<string, any> = {}, resetAfterClose: boolean = false, global: boolean = false)

  • name: 必要參數。設定 modal 的名稱。這會對應 openModal 的第一參數。
  • init-data: 非必要參數。會決定 modal.data 的初始狀態。如果沒有傳,則預設 {}
  • resetAfterClose: 非必要參數。是否在 close 後重設 data 回 initData。預設是 false。
  • global: boolean。是否屬於 globalModalContext ,default 是 false。(見 globalModalContext)

回傳:

  • modal: 與 <ModalProvider> scoped slot 中的 modal

useGlobalModalContext

useGlobalModalContext 可以取得 global modal context 的操作函式:

useGlobalModalContext 將會回傳:

  • openGlobalModal: 與 openModal 相同,但只能開啟 global modal。
  • closeGlobalModal: 與 closeModal 相同,但只能關閉 global modal。
  • patchGlobalModal: 與 patchModal 相同,但只能 patch global modal。

Types

內部的 type 基本上都有曝露出來。以下說明比較常用的 type 設置

Global components type

當你是使用全域註冊元件時(比如使用 plugin 時),如果你是使用 vscode + volar,你可以透過以下方式設置 global components type

// src/components.d.ts
import { ModalContext, ModalProvider } from 'vue-use-modal-context'

declare module 'vue' {
  export interface GlobalComponents {
    ModalContext: typeof ModalContext
    ModalProvider: typeof ModalProvider
  }
}