用Vue Demi 構建同時兼容Vue2與Vue3組件庫

前言:

Vue Demi 是一個很棒的包,具有很多潛力和實用性。我強烈建議在創建下一個 Vue 庫時使用它。

根據創建者 Anthony Fu 的說法,Vue Demi 是一個開發實用程序,它允許用戶為 Vue 2 和 Vue 3 編寫通用的 Vue 庫,而無需擔心用戶安裝的版本。

以前,要創建支持兩個目標版本的 Vue 庫,我們會使用不同的分支來分離對每個版本的支持。對於現有庫來說,這是一個很好的方法,因為它們的代碼庫通常更穩定。

缺點是,你需要維護兩個代碼庫,這讓你的工作量翻倍。對於想要支持Vue的兩個目標版本的新Vue庫來說,我不推薦這種方法。實施兩次功能請求和錯誤修復根本就不理想。

這就是 Vue Demi 的用武之地。Vue Demi 通過為兩個目標版本提供通用支持來解決這個問題,這意味著您隻需構建一次即可獲得兩個目標版本的所有優點,從而獲得兩全其美的優勢。

在本文中,我們將瞭解 Vue Demi 是做什麼的,它是如何工作的,以及如何開始構建一個通用的 Vue 組件庫。

一、Vue Demi 中的額外 API

除瞭 Vue 已經提供的 API 之外,Vue Demi 還引入瞭一些額外的 API 來幫助區分用戶的環境和執行特定於版本的邏輯。讓我們仔細看看它們!

請註意:Vue Demi 還包括 Vue 中已經存在的標準 API,例如 ref、onMounted 和 onUnmounted 等。

1.isVue2 and isVue3

在 Vue Demi 中,isvue2 和 isvue3 API 允許用戶在創建 Vue 庫時應用特定於版本的邏輯。

例如:

import { isVue2, isVue3 } from 'vue-demi' 
if (isVue2) { 
  // Vue 2 only 
} else { 
  // Vue 3 only 
}

vue2

Vue Demi 提供瞭 vue2 API,它允許用戶訪問 Vue 2 的全局 API,如下所示:

import { Vue2 } from 'vue-demi' 
// in Vue 3 `Vue2` will return undefined 
if (Vue2) { 
  Vue2.config.devtools = true 
}
install()

在 Vue 2 中,Composition API 作為插件提供,在使用它之前需要安裝在 Vue 實例上:

import Vue from 'vue' 
import VueCompositionAPI from '@vue/composition-api' 

Vue.use(VueCompositionAPI)

Vue Demi 會嘗試自動安裝它,但是對於您想要確保插件安裝正確的情況,提供瞭 install() API 來幫助您。

它作為 Vue.use(VueCompositionAPI) 的安全版本公開:

import { install } from 'vue-demi' 

install()

二、Vue Demi 入門

要開始使用 Vue Demi,您需要將其安裝到您的應用程序中。在本文中,我們將創建一個集成 Paystack 支付網關的 Vue 組件庫。

你可以像這樣安裝 Vue Demi:

// Npm 
npm i vue-demi 

// Yarn 
yarn add vue-demi

您還需要添加 vue @vue/composition-api 作為庫的對等依賴項,以指定它應該支持的版本。

現在我們可以將 Vue Demi 導入我們的應用程序:

<script lang="ts"> 
import {defineComponent, PropType, h, isVue2} from "vue-demi" 

export default defineComponent({
  // ... 
}) 
</script>

此處所示,我們可以使用已經存在的標準 Vue API,例如 defineComponent、PropType 和 h。

現在我們已經導入瞭Vue Demi,讓我們來添加我們的props。這些是用戶在使用組件庫時需要(或不需要,取決於你的口味)傳入的屬性。

<script lang="ts">
import {defineComponent, PropType, h, isVue2} from "vue-demi"
// Basically this tells the metadata prop what kind of data is should accept
interface MetaData {
  [key: string]: any
}

export default defineComponent({
  props: {
    paystackKey: {
      type: String as PropType<string>,
      required: true,
    },
    email: {
      type: String as PropType<string>,
      required: true,
    },
    firstname: {
      type: String as PropType<string>,
      required: true,
    },
    lastname: {
      type: String as PropType<string>,
      required: true,
    },
    amount: {
      type: Number as PropType<number>,
      required: true,
    },
    reference: {
      type: String as PropType<string>,
      required: true,
    },
    channels: {
      type: Array as PropType<string[]>,
      default: () => ["card", "bank"],
    },
    callback: {
      type: Function as PropType<(response: any) => void>,
      required: true,
    },
    close: {
      type: Function as PropType<() => void>,
      required: true,
    },
    metadata: {
      type: Object as PropType<MetaData>,
      default: () => {},
    },
    currency: {
      type: String as PropType<string>,
      default: "",
    },
    plan: {
      type: String as PropType<string>,
      default: "",
    },
    quantity: {
      type: String as PropType<string>,
      default: "",
    },
    subaccount: {
      type: String as PropType<string>,
      default: "",
    },
    splitCode: {
      type: String as PropType<string>,
      default: "",
    },
    transactionCharge: {
      type: Number as PropType<number>,
      default: 0,
    },
    bearer: {
      type: String as PropType<string>,
      default: "",
    },
  }
</script>

上面看到的屬性是使用 Paystack Popup JS 所必需的。

Popup JS 提供瞭一種將 Paystack 集成到我們的網站並開始接收付款的簡單方法:

data() {
    return {
      scriptLoaded: false,
    }
  },
  created() {
    this.loadScript()
  },
  methods: {
    async loadScript(): Promise<void> {
      const scriptPromise = new Promise<boolean>((resolve) => {
        const script: any = document.createElement("script")
        script.defer = true
        script.src = "https://js.paystack.co/v1/inline.js"
        // Add script to document head
        document.getElementsByTagName("head")[0].appendChild(script)
        if (script.readyState) {
          // IE support
          script.onreadystatechange = () => {
            if (script.readyState === "complete") {
              script.onreadystatechange = null
              resolve(true)
            }
          }
        } else {
          // Others
          script.onload = () => {
            resolve(true)
          }
        }
      })
      this.scriptLoaded = await scriptPromise
    },
    payWithPaystack(): void {
      if (this.scriptLoaded) {
        const paystackOptions = {
          key: this.paystackKey,
          email: this.email,
          firstname: this.firstname,
          lastname: this.lastname,
          channels: this.channels,
          amount: this.amount,
          ref: this.reference,
          callback: (response: any) => {
            this.callback(response)
          },
          onClose: () => {
            this.close()
          },
          metadata: this.metadata,
          currency: this.currency,
          plan: this.plan,
          quantity: this.quantity,
          subaccount: this.subaccount,
          split_code: this.splitCode,
          transaction_charge: this.transactionCharge,
          bearer: this.bearer,
        }
        const windowEl: any = window
        const handler = windowEl.PaystackPop.setup(paystackOptions)
        handler.openIframe()
      }
    },
  },

scriptLoaded 狀態幫助我們知道是否添加瞭Paystack Popup JS 腳本,並且 loadScript 方法加載 Paystack Popup JS 腳本並將其添加到我們的文檔頭部。

payWithPaystack 方法用於在調用時使用 Paystack Popup JS 初始化交易:

render() {
    if (isVue2) {
      return h(
        "button",
        {
          staticClass: ["paystack-button"],
          style: [{display: "block"}],
          attrs: {type: "button"},
          on: {click: this.payWithPaystack},
        },
        this.$slots.default ? this.$slots.default : "PROCEED TO PAYMENT"
      )
    }
    return h(
      "button",
      {
        class: ["paystack-button"],
        style: [{display: "block"}],
        type: "button",
        onClick: this.payWithPaystack,
      },
      this.$slots.default ? this.$slots.default() : "PROCEED TO PAYMENT"
    )
}

render 函數幫助我們創建沒有 標簽的組件,並返回一個虛擬 DOM 節點。

如果你註意到,我們在條件語句中使用瞭Vue Demi的一個API,isVue2,來有條件地渲染我們的按鈕。如果沒有這一點,如果我們想在Vue 2應用程序中使用我們的組件庫,我們可能會因為Vue 2不支持Vue 3的一些API而遇到錯誤。

現在,當我們構建我們的庫時,它可以在 Vue 2 和 Vue 3 中訪問。

到此這篇關於用Vue Demi 構建同時兼容Vue2與Vue3組件庫的文章就介紹到這瞭,更多相關 使用Vue Demi 構建內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!

推薦閱讀: