目录
6:在 Vue 2 项目中使用(需要 Composition API)
这是什么?
vue-demi 是一个 Vue 库,旨在帮助开发者编写同时支持 Vue 2 和 Vue 3 的库。它的名字来源于“demigod”(半神)。(果然神)它通过提供统一的 API 接口,让你能够编写兼容两个 Vue 主要版本的代码。
主要用处:
版本检测:自动检测当前项目中使用的 Vue 版本
统一 API:提供一致的 API 调用方式
平滑迁移:帮助库作者和开发者更容易地支持多版本 Vue
怎么使用?
安装和设置
1. 安装 Vue Demi
npm install vue-demi
# 或
yarn add vue-demi
2. 添加 Vue 版本别名
在 package.json 中添加:
{
"scripts": {
"postinstall": "vue-demi-fix"
}
}
或者手动设置别名:
{
"dependencies": {
"vue-demi": "latest"
},
"alias": {
"vue-demi": "vue-demi/lib/v2/index.js" // Vue 2 项目
// 或
"vue-demi": "vue-demi/lib/v3/index.js" // Vue 3 项目
}
}
基本使用方法
1. 导入 API
import { ref, reactive, computed, defineComponent } from 'vue-demi'
2. 版本检测
import { isVue2, isVue3, Vue2 } from 'vue-demi'
if (isVue2) {
console.log('运行在 Vue 2 环境中')
// 可以使用 Vue2 访问 Vue 2 的全局 API
} else if (isVue3) {
console.log('运行在 Vue 3 环境中')
}
使用说明
1:基础组合式函数
// useCounter.js
import { ref, computed } from 'vue-demi'
export function useCounter(initialValue = 0) {
const count = ref(initialValue)
const increment = () => count.value++
const decrement = () => count.value--
const reset = () => count.value = initialValue
const double = computed(() => count.value * 2)
const isEven = computed(() => count.value % 2 === 0)
return {
count,
increment,
decrement,
reset,
double,
isEven
}
}
2:兼容性组件
// MyComponent.vue
<template>
<div>
<h3>{{ title }}</h3>
<p>计数: {{ count }}</p>
<button @click="increment">增加</button>
<button @click="decrement">减少</button>
</div>
</template>
<script>
import { defineComponent, ref } from 'vue-demi'
export default defineComponent({
name: 'MyComponent',
props: {
title: {
type: String,
default: '计数器'
}
},
setup(props) {
const count = ref(0)
const increment = () => count.value++
const decrement = () => count.value--
return {
count,
increment,
decrement
}
}
})
</script>
3:条件性代码(处理版本差异)
// utils.js
// 导入 Vue Demi 提供的版本检测和实例获取功能
import { isVue2, isVue3, getCurrentInstance } from 'vue-demi'
/**
* 获取当前 Vue 应用的全局属性
* 这个函数解决了 Vue 2 和 Vue 3 中全局属性访问方式的不同
* @returns {Object} 返回全局属性对象,如果获取失败返回空对象
*/
export function getGlobalProperties() {
// 检查当前环境是否为 Vue 2
if (isVue2) {
// Vue 2 方式:通过实例的 proxy 属性访问全局属性
const vm = getCurrentInstance() // 获取当前组件实例
// 在 Vue 2 中,全局属性通常挂载在 Vue.prototype 上,通过实例的 proxy 访问
return vm ? vm.proxy : {} // 如果有实例则返回 proxy,否则返回空对象
}
// 检查当前环境是否为 Vue 3
else if (isVue3) {
// Vue 3 方式:通过应用配置的 globalProperties 访问全局属性
const instance = getCurrentInstance() // 获取当前组件实例
// 在 Vue 3 中,全局属性存储在 appContext.config.globalProperties 中
return instance ? instance.appContext.config.globalProperties : {}
}
}
/**
* 统一的事件触发函数,兼容 Vue 2 和 Vue 3 的事件系统
* Vue 2 使用 this.$emit(),Vue 3 使用 this.emit() 或 setup 中的 emit()
* @param {Object} instance - Vue 组件实例
* @param {string} eventName - 要触发的事件名称
* @param {...any} args - 传递给事件的参数
*/
export function emitEvent(instance, eventName, ...args) {
// Vue 2 的事件触发方式
if (isVue2) {
// Vue 2 使用 $emit 方法触发自定义事件
// instance 是组件实例,$emit 是 Vue 2 的内置方法
instance.$emit(eventName, ...args)
}
// Vue 3 的事件触发方式
else if (isVue3) {
// Vue 3 使用 emit 方法触发自定义事件(选项式 API)
// 在组合式 API 中,emit 是通过 setup 函数的参数或 defineEmits 获取的
instance.emit(eventName, ...args)
}
// 注意:在 Vue 3 的组合式 API 中,通常使用从 setup 中解构的 emit 函数
// 但这个函数处理的是组件实例本身的方法调用
}
4:插件开发
// plugin.js
import { isVue2, isVue3 } from 'vue-demi'
export const MyPlugin = {
install(app, options) {
// 添加全局方法或属性
if (isVue2) {
// Vue 2 安装方式
app.prototype.$myMethod = function() {
console.log('这是 Vue 2 的全局方法')
}
} else if (isVue3) {
// Vue 3 安装方式
app.config.globalProperties.$myMethod = function() {
console.log('这是 Vue 3 的全局方法')
}
}
// 添加全局指令
app.directive('focus', {
mounted(el) {
el.focus()
},
// Vue 2 兼容
inserted: isVue2 ? function(el) {
el.focus()
} : undefined
})
}
}
5:组合式 API 封装
// useApi.js
import { ref, reactive, watch } from 'vue-demi'
export function useApi(url, options = {}) {
const data = ref(null)
const loading = ref(false)
const error = ref(null)
const state = reactive({
data: null,
loading: false,
error: null
})
async function fetchData() {
loading.value = true
state.loading = true
error.value = null
state.error = null
try {
const response = await fetch(url, options)
const result = await response.json()
data.value = result
state.data = result
} catch (err) {
error.value = err
state.error = err
} finally {
loading.value = false
state.loading = false
}
}
// 自动监听 URL 变化
watch(() => url, fetchData, { immediate: true })
return {
// 两种返回方式都提供,增加兼容性
data,
loading,
error,
fetchData,
// 响应式对象方式
state
}
}
6:在 Vue 2 项目中使用(需要 Composition API)
// main.js (Vue 2 项目)
import Vue from 'vue'
import VueCompositionAPI from '@vue/composition-api'
import App from './App.vue'
Vue.use(VueCompositionAPI)
new Vue({
render: h => h(App)
}).$mount('#app')
// 组件中使用
import { useCounter } from './useCounter'
export default {
setup() {
const { count, increment } = useCounter()
return {
count,
increment
}
}
}
注意事项
Vue 2 项目需要安装 Composition API:
npm install @vue/composition-apiTypeScript 支持:Vue Demi 提供了完整的 TypeScript 类型定义
是优化还是桥梁?
准确地说,Vue Demi 更像是一个"桥梁"和"兼容层",而不是传统意义上的性能优化工具。
Vue Demi 作为桥梁的作用
(其实上面已经讲到了)
1. 版本兼容桥梁
// 没有 Vue Demi - 需要条件编译
if (Vue.version.startsWith('2')) {
// Vue 2 代码
Vue.prototype.$myMethod = function() {}
} else {
// Vue 3 代码
app.config.globalProperties.$myMethod = function() {}
}
// 使用 Vue Demi - 统一接口
import { isVue2, isVue3 } from 'vue-demi'
// 或者使用统一的 API
2. API 统一桥梁
// 传统方式需要区分导入源
// Vue 2 项目
import { ref } from '@vue/composition-api'
// Vue 3 项目
import { ref } from 'vue'
// 使用 Vue Demi - 统一导入
import { ref } from 'vue-demi' // 自动适配当前环境
为什么说它是桥梁而不是优化?
降低迁移成本:让库作者可以逐步迁移,而不是重写
连接生态:保持 Vue 2 和 Vue 3 生态系统的连续性
减少破坏性变更:提供平滑的升级路径
实际案例对比:
没有 Vue Demi 的情况:
// 库作者需要维护两个版本
// package.json
{
"main": "dist/index.js",
"module": "dist/index.esm.js",
"vue2": "dist/vue2.js",
"vue3": "dist/vue3.js"
}
// 构建两个不同的包,用户需要手动选择
使用 Vue Demi 的情况:
// 只需要维护一个代码库
// package.json
{
"main": "dist/index.js",
"module": "dist/index.esm.js"
}
// 用户安装后自动适配当前 Vue 版本
Vue Demi 的实际价值
1. 对库开发者的价值
// 以前:需要维护两个分支
// vue2-branch/src/index.js
import Vue from 'vue'
export function install(Vue) {
Vue.prototype.$myPlugin = function() {}
}
// vue3-branch/src/index.js
import { createApp } from 'vue'
export function install(app) {
app.config.globalProperties.$myPlugin = function() {}
}
// 现在:使用 Vue Demi 统一代码
import { isVue2, isVue3 } from 'vue-demi'
export function install(appOrVue) {
if (isVue2) {
appOrVue.prototype.$myPlugin = function() {}
} else {
appOrVue.config.globalProperties.$myPlugin = function() {}
}
}
2. 对企业项目的价值
大型项目迁移场景
传统方式:一次性重写,高风险
使用 Vue Demi:渐进式迁移
步骤1:部分组件使用 Vue Demi 编写,兼容两个版本
步骤2:逐步将 Vue 2 组件迁移到兼容版本
步骤3:最终升级到 Vue 3,代码无需大量修改
Vue Demi 与性能优化的关系
间接的优化效果:
1. 减少代码重复 - 优化维护成本
之前:两份代码库
之后:一份代码库 + 自动适配
2. 减少上下文切换 - 优化开发体验
之前:在 Vue 2 和 Vue 3 思维模式间切换
之后:统一的开发模式
3. 加速迁移过程 - 优化时间成本
迁移时间从数月缩短到数周
但不是运行时性能优化:
Vue Demi 本身不会:
- 减少打包体积(可能略有增加)
- 提升运行时性能
- 优化渲染性能
它主要解决的是开发效率和兼容性问题
1149

被折叠的 条评论
为什么被折叠?



