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

用Vue?Demi同時(shí)支持Vue2和Vue3的方法

 更新時(shí)間:2022年12月16日 14:39:48   作者:街角小林  
這篇文章主要介紹了用Vue?Demi同時(shí)支持Vue2和Vue3的方法,實(shí)際開發(fā)中,同一個(gè)API在不同的版本中可能導(dǎo)入的來源不一樣,比如ref方法,本文結(jié)合示例代碼給大家介紹的非常詳細(xì),需要的朋友可以參考下

Vue Demi是什么

如果你想開發(fā)一個(gè)同時(shí)支持Vue2Vue3的庫可能想到以下兩種方式:

1.創(chuàng)建兩個(gè)分支,分別支持Vue2Vue3

2.只使用Vue2Vue3都支持的API

這兩種方式都有缺點(diǎn),第一種很麻煩,第二種無法使用Vue3新增的組合式 API,其實(shí)現(xiàn)在Vue2.7+版本已經(jīng)內(nèi)置支持組合式API,Vue2.6及之前的版本也可以使用@vue/composition-api插件來支持,所以完全可以只寫一套代碼同時(shí)支持Vue23。雖然如此,但是實(shí)際開發(fā)中,同一個(gè)API在不同的版本中可能導(dǎo)入的來源不一樣,比如ref方法,在Vue2.7+中直接從vue中導(dǎo)入,但是在Vue2.6-中只能從@vue/composition-api中導(dǎo)入,那么必然會(huì)涉及到版本判斷,Vue Demi就是用來解決這個(gè)問題,使用很簡(jiǎn)單,只要從Vue Demi中導(dǎo)出你需要的內(nèi)容即可:

import { ref, reactive, defineComponent } from 'vue-demi'

Vue-demi會(huì)根據(jù)你的項(xiàng)目判斷到底使用哪個(gè)版本的Vue,具體來說,它的策略如下:

  • <=2.6: 從Vue@vue/composition-api中導(dǎo)出
  • 2.7: 從Vue中導(dǎo)出(組合式API內(nèi)置于Vue 2.7中)
  • >=3.0: 從Vue中導(dǎo)出,并且還polyfill了兩個(gè)Vue 2版本的setdel API

接下來從源碼角度來看一下它具體是如何實(shí)現(xiàn)的。

基本原理

當(dāng)我們使用npm i vue-demi在我們的項(xiàng)目里安裝完以后,它會(huì)自動(dòng)執(zhí)行一個(gè)腳本:

{
    "scripts": {
        "postinstall": "node ./scripts/postinstall.js"
    }
}
// postinstall.js
const { switchVersion, loadModule } = require('./utils')

const Vue = loadModule('vue')

if (!Vue || typeof Vue.version !== 'string') {
  console.warn('[vue-demi] Vue is not found. Please run "npm install vue" to install.')
}
else if (Vue.version.startsWith('2.7.')) {
  switchVersion(2.7)
}
else if (Vue.version.startsWith('2.')) {
  switchVersion(2)
}
else if (Vue.version.startsWith('3.')) {
  switchVersion(3)
}
else {
  console.warn(`[vue-demi] Vue version v${Vue.version} is not suppported.`)
}

導(dǎo)入我們項(xiàng)目里安裝的vue,然后根據(jù)不同的版本分別調(diào)用switchVersion方法。

先看一下loadModule方法:

function loadModule(name) {
  try {
    return require(name)
  } catch (e) {
    return undefined
  }
}

很簡(jiǎn)單,就是包裝了一下require,防止報(bào)錯(cuò)阻塞代碼。

然后看一下switchVersion方法:

function switchVersion(version, vue) {
  copy('index.cjs', version, vue)
  copy('index.mjs', version, vue)
  copy('index.d.ts', version, vue)

  if (version === 2)
    updateVue2API()
}

執(zhí)行了copy方法,從函數(shù)名可以大概知道是復(fù)制文件,三個(gè)文件的類型也很清晰,分別是commonjs版本的文件、ESM版本的文件、TS類型定義文件。

另外還針對(duì)Vue2.6及一下版本執(zhí)行了updateVue2API方法。

updateVue2API方法我們后面再看,先看一下copy方法:

const dir = path.resolve(__dirname, '..', 'lib')

function copy(name, version, vue) {
  vue = vue || 'vue'
  const src = path.join(dir, `v${version}`, name)
  const dest = path.join(dir, name)
  let content = fs.readFileSync(src, 'utf-8')
  content = content.replace(/'vue'/g, `'${vue}'`)
  try {
    fs.unlinkSync(dest)
  } catch (error) { }
  fs.writeFileSync(dest, content, 'utf-8')
}

其實(shí)就是從不同版本的目錄里復(fù)制上述三個(gè)文件到外層目錄,其中還支持替換vue的名稱,這當(dāng)你給vue設(shè)置了別名時(shí)需要用到。

到這里,Vue Demi安裝完后自動(dòng)執(zhí)行的事情就做完了,其實(shí)就是根據(jù)用戶項(xiàng)目中安裝的Vue版本,分別從三個(gè)對(duì)應(yīng)的目錄中復(fù)制文件作為Vue Demi包的入口文件,Vue Demi支持三種模塊語法:

{
    "main": "lib/index.cjs",
    "jsdelivr": "lib/index.iife.js",
    "unpkg": "lib/index.iife.js",
    "module": "lib/index.mjs",
    "types": "lib/index.d.ts"
}

默認(rèn)入口為commonjs模塊cjs文件,支持ESM的可以使用mjs文件,同時(shí)還提供了可以直接在瀏覽器上使用的iife類型的文件。

接下來看一下分別針對(duì)三種版本的Vue具體都做了什么。

v2版本

Vue2.6版本只有一個(gè)默認(rèn)導(dǎo)出:

我們只看mjs文件,cjs有興趣的可以自行閱讀:

import Vue from 'vue'
import VueCompositionAPI from '@vue/composition-api/dist/vue-composition-api.mjs'

function install(_vue) {
  _vue = _vue || Vue
  if (_vue && !_vue['__composition_api_installed__'])
    _vue.use(VueCompositionAPI)
}

install(Vue)
// ...

導(dǎo)入VueVueCompositionAPI插件,并且自動(dòng)調(diào)用Vue.use方法安裝插件。

繼續(xù):

// ...
var isVue2 = true
var isVue3 = false
var Vue2 = Vue
var version = Vue.version

export {
	  isVue2,
    isVue3,
    Vue,
    Vue2,
    version,
    install,
}

/**VCA-EXPORTS**/
export * from '@vue/composition-api/dist/vue-composition-api.mjs'
/**VCA-EXPORTS**/

首先導(dǎo)出了兩個(gè)變量isVue2isVue3,方便我們的庫代碼判斷環(huán)境。

然后在導(dǎo)出Vue的同時(shí),還通過Vue2的名稱再導(dǎo)出了一遍,這是為啥呢,其實(shí)是因?yàn)?code>Vue2的API都是掛載在Vue對(duì)象上,比如我要進(jìn)行一些全局配置,那么只能這么操作:

import { Vue, isVue2 } from 'vue-demi'

if (isVue2) {
  Vue.config.xxx
}

這樣在Vue2的環(huán)境中沒有啥問題,但是當(dāng)我們的庫處于Vue3的環(huán)境中時(shí),其實(shí)是不需要導(dǎo)入Vue對(duì)象的,因?yàn)橛貌簧?,但是?gòu)建工具不知道,所以它會(huì)把Vue3的所有代碼都打包進(jìn)去,但是Vue3中很多我們沒有用到的內(nèi)容是不需要的,但是因?yàn)槲覀儗?dǎo)入了包含所有APIVue對(duì)象,所以無法進(jìn)行去除,所以針對(duì)Vue2版本單獨(dú)導(dǎo)出一個(gè)Vue2對(duì)象,我們就可以這么做:

import { Vue2 } from 'vue-demi'

if (Vue2) {
  Vue2.config.xxx
}

然后后續(xù)你會(huì)看到在Vue3的導(dǎo)出中Vue2undefined,這樣就可以解決這個(gè)問題了。

接著導(dǎo)出了Vue的版本和install方法,意味著你可以手動(dòng)安裝VueCompositionAPI插件。

然后是導(dǎo)出VueCompositionAPI插件提供的API,也就是組合式API,但是可以看到前后有兩行注釋,還記得前面提到的switchVersion方法里針對(duì)Vue2版本還執(zhí)行了updateVue2API方法,現(xiàn)在來看一看它做了什么事情:

function updateVue2API() {
  const ignoreList = ['version', 'default']
  // 檢查是否安裝了composition-api
  const VCA = loadModule('@vue/composition-api')
  if (!VCA) {
    console.warn('[vue-demi] Composition API plugin is not found. Please run "npm install @vue/composition-api" to install.')
    return
  }
  // 獲取除了version、default之外的其他所有導(dǎo)出
  const exports = Object.keys(VCA).filter(i => !ignoreList.includes(i))
  // 讀取ESM語法的入口文件
  const esmPath = path.join(dir, 'index.mjs')
  let content = fs.readFileSync(esmPath, 'utf-8')
  // 將export * 替換成 export { xxx }的形式
  content = content.replace(
    /\/\*\*VCA-EXPORTS\*\*\/[\s\S]+\/\*\*VCA-EXPORTS\*\*\//m,
`/**VCA-EXPORTS**/
export { ${exports.join(', ')} } from '@vue/composition-api/dist/vue-composition-api.mjs'
/**VCA-EXPORTS**/`
    )
  // 重新寫入文件
  fs.writeFileSync(esmPath, content, 'utf-8')
}

主要做的事情就是檢查是否安裝了@vue/composition-api,然后過濾出了@vue/composition-api除了versiondefault之外的所有導(dǎo)出內(nèi)容,最后將:

export * from '@vue/composition-api/dist/vue-composition-api.mjs'

的形式改寫成:

export { EffectScope, ... } from '@vue/composition-api/dist/vue-composition-api.mjs'

為什么要過濾掉versiondefault呢,version是因?yàn)橐呀?jīng)導(dǎo)出了Vueversion了,所以會(huì)沖突,本來也不需要,default即默認(rèn)導(dǎo)出,@vue/composition-api的默認(rèn)導(dǎo)出其實(shí)是一個(gè)包含它的install方法的對(duì)象,前面也看到了,可以默認(rèn)導(dǎo)入@vue/composition-api,然后通過Vue.use來安裝,這個(gè)其實(shí)也不需要從Vue Demi導(dǎo)出,不然像下面這樣就顯得很奇怪:

import VueCompositionAPI from 'vue-demi'

到這里,就導(dǎo)出所有內(nèi)容了,然后我們就可以從vue-demi中導(dǎo)入各種需要的內(nèi)容了,比如:

import { isVue2, Vue, ref, reactive, defineComponent } from 'vue-demi'

v2.7版本

接下來看一下是如何處理Vue2.7版本的導(dǎo)出的,和Vue2.6之前的版本相比,Vue2.7直接內(nèi)置了@vue/composition-api,所以除了默認(rèn)導(dǎo)出Vue對(duì)象外還導(dǎo)出了組合式API

import Vue from 'vue'

var isVue2 = true
var isVue3 = false
var Vue2 = Vue
var warn = Vue.util.warn

function install() {}

export { Vue, Vue2, isVue2, isVue3, install, warn }
// ...

v2相比,導(dǎo)出的內(nèi)容是差不多的,因?yàn)椴恍枰惭b@vue/composition-api,所以install是個(gè)空函數(shù),區(qū)別在于還導(dǎo)出了一個(gè)warn方法,這個(gè)文檔里沒有提到,但是可以從過往的issues中找到原因,大致就是Vue3導(dǎo)出了一個(gè)warn方法,而Vue2warn方法在Vue.util對(duì)象上,所以為了統(tǒng)一手動(dòng)導(dǎo)出,為什么V2版本不手動(dòng)導(dǎo)出一個(gè)呢,原因很簡(jiǎn)單,因?yàn)檫@個(gè)方法在@vue/composition-api的導(dǎo)出里有。

繼續(xù):

// ...
export * from 'vue'
// ...

導(dǎo)出上圖中Vue所有的導(dǎo)出,包括version、組合式API,但是要注意這種寫法不會(huì)導(dǎo)出默認(rèn)的Vue,所以如果你像下面這樣使用默認(rèn)導(dǎo)入是獲取不到Vue對(duì)象的:

import Vue from 'vue-demi'

繼續(xù):

// ...
// createApp polyfill
export function createApp(rootComponent, rootProps) {
  var vm
  var provide = {}
  var app = {
    config: Vue.config,
    use: Vue.use.bind(Vue),
    mixin: Vue.mixin.bind(Vue),
    component: Vue.component.bind(Vue),
    provide: function (key, value) {
      provide[key] = value
      return this
    },
    directive: function (name, dir) {
      if (dir) {
        Vue.directive(name, dir)
        return app
      } else {
        return Vue.directive(name)
      }
    },
    mount: function (el, hydrating) {
      if (!vm) {
        vm = new Vue(Object.assign({ propsData: rootProps }, rootComponent, { provide: Object.assign(provide, rootComponent.provide) }))
        vm.$mount(el, hydrating)
        return vm
      } else {
        return vm
      }
    },
    unmount: function () {
      if (vm) {
        vm.$destroy()
        vm = undefined
      }
    },
  }
  return app
}

Vue2new Vue創(chuàng)建Vue實(shí)例不一樣,Vue3是通過createApp方法,@vue/composition-api插件polyfill了這個(gè)方法,所以針對(duì)Vue2.7,Vue Demi手動(dòng)進(jìn)行了polyfill。

到這里,針對(duì)Vue2.7所做的事情就結(jié)束了。

v3版本

Vue3相比之前的版本,最大區(qū)別是不再提供一個(gè)單獨(dú)的Vue導(dǎo)出:

import * as Vue from 'vue'

var isVue2 = false
var isVue3 = true
var Vue2 = undefined

function install() {}

export {
  Vue,
  Vue2,
  isVue2,
  isVue3,
  install,
}
// ...

因?yàn)槟J(rèn)不導(dǎo)出Vue對(duì)象了,所以通過整體導(dǎo)入import * as Vue的方式把所有的導(dǎo)出都加載到Vue對(duì)象上,然后也可以看到導(dǎo)出的Vue2undefined,install同樣是個(gè)空函數(shù)。

繼續(xù):

// ...
export * from 'vue'
// ...

沒啥好說的,直接導(dǎo)出Vue的所有導(dǎo)出內(nèi)容。

繼續(xù):

// ...
export function set(target, key, val) {
  if (Array.isArray(target)) {
    target.length = Math.max(target.length, key)
    target.splice(key, 1, val)
    return val
  }
  target[key] = val
  return val
}

export function del(target, key) {
  if (Array.isArray(target)) {
    target.splice(key, 1)
    return
  }
  delete target[key]
}

最后polyfill了兩個(gè)方法,這兩個(gè)方法實(shí)際上是@vue/composition-api插件提供的,因?yàn)?code>@vue/composition-api提供的響應(yīng)性API實(shí)現(xiàn)上并沒有使用Proxy代理,仍舊是基于Vue2的響應(yīng)系統(tǒng)來實(shí)現(xiàn)的,所以Vue2中響應(yīng)系統(tǒng)的限制仍舊還是存在的,所以需要提供兩個(gè)類似Vue.setVue.delete方法用來給響應(yīng)性數(shù)據(jù)添加或刪除屬性。

到此這篇關(guān)于用Vue Demi同時(shí)支持Vue2和Vue3的方法的文章就介紹到這了,更多相關(guān)Vue Demi同時(shí)支持Vue2和Vue3內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • VUE : vue-cli中去掉路由中的井號(hào)#操作

    VUE : vue-cli中去掉路由中的井號(hào)#操作

    這篇文章主要介紹了VUE : vue-cli中去掉路由中的井號(hào)#操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧
    2020-09-09
  • 解析vue data不可以使用箭頭函數(shù)問題

    解析vue data不可以使用箭頭函數(shù)問題

    這篇文章主要介紹了vue data不可以使用箭頭函數(shù)問題,本文通過源碼解析給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2018-07-07
  • Vue+Django項(xiàng)目部署詳解

    Vue+Django項(xiàng)目部署詳解

    這篇文章主要介紹了Vue+Django項(xiàng)目部署詳解,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-05-05
  • vue項(xiàng)目中l(wèi)ess的一些使用小技巧

    vue項(xiàng)目中l(wèi)ess的一些使用小技巧

    前段時(shí)間一直在學(xué)習(xí)vue,開始記錄一下遇到的問題,下面這篇文章主要給大家介紹了關(guān)于vue項(xiàng)目中l(wèi)ess的一些使用小技巧,文中通過示例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2021-09-09
  • vue form 表單提交后刷新頁面的方法

    vue form 表單提交后刷新頁面的方法

    今天小編就為大家分享一篇vue form 表單提交后刷新頁面的方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧
    2018-09-09
  • 結(jié)合axios對(duì)項(xiàng)目中的api請(qǐng)求進(jìn)行封裝操作

    結(jié)合axios對(duì)項(xiàng)目中的api請(qǐng)求進(jìn)行封裝操作

    這篇文章主要介紹了結(jié)合axios對(duì)項(xiàng)目中的api請(qǐng)求進(jìn)行封裝操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧
    2020-09-09
  • vue-cli3配置與跨域處理方法

    vue-cli3配置與跨域處理方法

    這篇文章主要介紹了vue-cli3配置與跨域處理方法,非常不錯(cuò),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2019-08-08
  • openlayers6之地圖覆蓋物overlay詳解

    openlayers6之地圖覆蓋物overlay詳解

    overlay就是在地圖上以另外一種形式浮現(xiàn)在地圖上,常見的地圖覆蓋物為這三種類型,如:popup 彈窗、label標(biāo)注信息、text文本信息等,接下來跟隨小編看下openlayers6之地圖覆蓋物overlay詳解,一起看看吧
    2021-09-09
  • vue-router路由懶加載和權(quán)限控制詳解

    vue-router路由懶加載和權(quán)限控制詳解

    這篇文章主要介紹了vue-router路由懶加載和權(quán)限控制的相關(guān)資料
    2017-12-12
  • vue里面父組件修改子組件樣式的方法

    vue里面父組件修改子組件樣式的方法

    下面小編就為大家分享一篇vue里面父組件修改子組件樣式的方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧
    2018-02-02

最新評(píng)論