在vue2的项目中丝滑的使用vue3(以若依为例)

1,210 阅读2分钟

背景

在很多情况下,我们的项目没有办法直接升级到vue3但是我们又想体验vue3的一些用法,这种情况下,我们就需要对项目进行改造,这是我们在使用若依框架的时候的一个升级方案,希望能给大家带来一些灵感。

支持vue3的响应式api

通过 vue-demi@vue/composition-api来实现vue3的api的使用。 最简单的使用方法。 在首页的 index.vue中进行测试。

<template>
  <div>
    {{ counter }}

    <el-button @click="add">增加</el-button>
  </div>
</template>

<script>
  import { ref } from "vue-demi"
  export default {
    setup(){
      const counter = ref(1);
      const add = () => {
        counter.value ++
      }
    }
  }
</script>

支持setup的语法模式

这里需要使用到的是github.com/unplugin/un…

安装插件

npm i  -D unplugin-vue2-script-setup

使用插件

vue.config.js中导入插件

const ScriptSetup = require('unplugin-vue2-script-setup/webpack').default

module.exports = {
  // ... 忽略前面的配置
  plugins:[
    // ... 忽略前面的配置
    ScriptSetup({})
  ]
  // ... 忽略后面的配置
}

实现volar的提示

若要实现volar的提示,需要安装一下 @vue/runtime-dom

npm i -D @vue/runtime-dom

为了避免错误,所以需要配置一下tsconfig.json 因为若依中不存在这个配置文件,需要我们重新创建一个新的配置文件。

{
  "compilerOptions": {
    "target": "ES2020",
    "useDefineForClassFields": true,
    "module": "ESNext",
    "lib": ["ES2020", "DOM", "DOM.Iterable"],
    "skipLibCheck": true,

    /* Bundler mode */
    "moduleResolution": "bundler",
    "allowImportingTsExtensions": true,
    "resolveJsonModule": true,
    "isolatedModules": true,
    "noEmit": true,
    "jsx": "preserve",
    "jsxImportSource": "vue",
    "types": [
      "unplugin-vue2-script-setup/types"
    ],

    /* Linting */
    "allowJs":true,
    "strict": true,
    "noUnusedLocals": true,
    "noUnusedParameters": true,
    "noFallthroughCasesInSwitch": true,
    // paths
    "baseUrl": ".",
    "paths": {
      "@/*": ["src/*"]
    }
  },
  "vueCompilerOptions": {
    "target": 2
  },
  "include": [
    "src/**/*.ts",
    "src/**/*.js",
    "src/**/*.vue"
  ]
}

对工程功能进行测试,将原来的写法改成setup的写法

<template>
  <div>
    {{ counter }}

    <el-button @click="add">增加</el-button>
  </div>
</template>

<script setup>
  import { ref } from "vue-demi"
  const counter = ref(1);
  const add = () => {
    counter.value ++
  }
</script>

测试是否可以正常运行。

实现自动导入

这里使用到的插件是unplugin-auto-import 需要先安装一下这个插件

npm i -D unplugin-auto-import

安装完成后在 vue.config.js中进行配置

module.exports = {
  /* ... */
  plugins: [
    require('unplugin-auto-import/webpack').default({ /* options */ 
        imports:["vue-demi"],
        dirs:["src/composable"],
    }),
  ],
}

然后再对demo进行改造删除导入再进行测试

<template>
  <div>
    {{ counter }}

    <el-button @click="add">增加</el-button>
  </div>
</template>

<script setup>
  const counter = ref(1);
  const add = () => {
    counter.value ++
  }
</script>

若依中在setup中使用字典

创建一个composable的文件夹,用于存放组合式api的代码,创建一个dict.js的文件 将一下代码拷贝到 dict.js文件中。

import { getCurrentInstance, ref, nextTick} from "vue-demi"
import Dict from "@/utils/dict/Dict.js"

export const useDict = (dicts,$options = {}) =>{
    const dict = ref()
    const instance = getCurrentInstance()
    const options = instance?.proxy?._dictOptions ?? {};


    if(dicts.length > 0){
        dict.value = new Dict();
        dict.value.owner = instance

        options.onCreated && options.onCreated(dict.value)
        dict.value.init({
            ...options,
            types:dicts
        }).then(() => {
          options.onReady && options.onReady(dict.value)
          nextTick(() => {
            instance.emit('dictReady', dict.value)
            if ($options.methods && $options.methods.onDictReady instanceof Function) {
              $options.methods.onDictReady?.(dict.value)
            }
          })
        })
    }

    return {
        dict
    }
}

接下来需要在 src/utils/dict/index.js中,加入如下的一行代码


export default function(Vue, options) {
  mergeOptions(options)

+  // 数据挂载到原型上
+  Vue.prototype._dictOptions = options;
}

这样我们就完成了dict字典的支持改造。 我们进行相应的测试:

<template>
  <div>
    {{ a }}
    <el-button @click="handleClick">按钮
     
    </el-button>

    <el-select v-model="data" placeholder="请选择任务分组">
      <el-option
        v-for="dict in dict.type.sys_job_group"
        :key="dict.value"
        :label="dict.label"
        :value="dict.value"
      ></el-option>
    </el-select>
    {{ data }}
  </div>
</template>


<script setup>
import { useDict } from "@/composable/dict"
const { dict } = useDict(['sys_job_group', 'sys_job_status'])
const a = ref(1)

const data = ref()

const handleClick = () => {
  a.value ++
}

</script>