侧边栏壁纸
博主头像
M酷博主等级

祝君一帆风顺 ⛵️⛵️⛵️

  • 累计撰写 41 篇文章
  • 累计创建 37 个标签
  • 累计收到 283 条评论

目 录CONTENT

文章目录

Vue3 + Vite2 +TS 项目常见问题

M酷
2022-06-14 / 0 评论 / 2 点赞 / 193 阅读 / 8,872 字 / 正在检测是否收录...

1、ts 报错 Could not find a declaration file for module

ts 提示这个错误通常由以下几种情况:

  1. 引入的 npm 包不是用 typescript 编写的;
  2. 没有找到正确的类型定义文件;

针对第一种,我们可以尝试安装 @types/包名 来安装这个包对应的类型文件,如:
npm i @types/lodash -D

如果没有找到,我们也可以手动为它声明一下,此时可以直接到 Vite 项目自动生成的 env.d.ts 中添加声明,如果没有这个文件,可以在根目录下新建 shims-vue.d.ts,然后输入以下内容,注意最后要重新启动服务才生效。(关于类型文件编写,请参考)

Typescript 书写声明文件(可能是最全的)
TypeScript 声明文件全解析
declaration 声明文件

// declare 声明一个ambient module(即:没有内部实现的 module声明) 
declare module '*.vue' {
  import Vue from 'vue'
  export default Vue
}

declare module 'XX'
// xx即你包不能找到声明的包名,如 declare module 'lodash'

2、vue3+vite中 process.env 的配置&使用方法

vite 中的环境变量通过 import.meta.env 来暴露出来,但是不是所有文件中都可以获取到,如果我们想通过 process.env 的方式来读取,则需要像下面这样配置一下。

a. 在 vite.config.js 中,添加以下部分代码

import { defineConfig, loadEnv } from 'vite'

export default ({ mode }) =>
  defineConfig({
    define: {
      'process.env': loadEnv(mode, process.cwd())
    },
    ...
}

b. 在文件中使用变量值

// 创建axios实例
const service = axios.create({
  baseURL: process.env.BASE_API, // api 的 base_url
  timeout: 5000 // 请求超时时间
})

3、vue + ts 配置路径别名后 ts 报错

有 2 个位置需要配置一下,一个 vite.config.js,一个是 tsconfig.json(baseUrl 和 paths)

export default ({ mode }) =>
  defineConfig({
    base: './',
    resolve: {
      alias: {
        '@': path.resolve(__dirname, 'src')
      }
    }
}
{
  "baseUrl": "./",
  "compilerOptions": {
    //...
    "paths": {
      "@/*": [
        "./src/*"
      ]
    },
  },
  "include": [
    "src/**/*.ts",
    "src/**/*.tsx",
    "**/*.d.ts",
    "src/**/*.vue"
  ]
}

4、commitlint 无效,commit-msg 不执行

可能是配置不正确或者 commitlint 本身的缓存问题导致的,建议先删除 .husky 目录下的 commit-msg 文件,然后使用下面的命令重新生成 commit-msg 文件即可,注意内容格式不要错 。

npx husky add .husky/commit-msg "npx --no-install commitlint --edit "$1""

5、commitlint 校验不通过,本地修改全部丢失,如何找回?

由于 commit 有规范校验,当我们提交的格式不正确时候,它会把内容弹出去,不会 commit 上去,同时默认会把本地的修改全部重做。此时,大家不要慌,commitlint 其实会自动帮我们在 stash 里做一个备份,我们可以通过 git stash list 查看一下,发现有这样的一条或多条记录。

此时,我们就可以使用 git stash popgit stash apply 弹出草稿箱里的数据来恢复。类似的丢失,我们也可以先用 git reflog 先查看日志,然后配合 git reset --hard 版本号 进行恢复。

6、ElementPlus 按需引入后,单独调用 ElMessage、ElLoading 或其它组件时,出现样式丢失问题。

就是由于按需引入导致的,当前单独使用某个组件时(比如在 axios 中),Vite 并不知道你要用到这个组件,所以并没有去加载它对应的样式,此时我们只需要补上相关组件的样式即可,当然你全量引入也许。

方法一:在 main.ts 中单独引入那些组件的样式

// 引入Elmessage和Elloading的css样式文件
import 'element-plus/theme-chalk/el-loading.css'
import 'element-plus/theme-chalk/el-message.css'

方法二(推荐):通过 vite-plugin-style-importconsola 来实现自动引入

a. 首先安装一下,

yarn add vite-plugin-style-import consola -D

b. 在 vite.config.ts 中添加如下配置

// vite.config.ts
import {
  createStyleImportPlugin,
  ElementPlusResolve,
} from 'vite-plugin-style-import'

export default {
  plugins: [
    // ...
    createStyleImportPlugin({
      resolves: [ElementPlusResolve()],
      libs: [
        {
          libraryName: 'element-plus',
          esModule: true,
          resolveStyle: (name: string) => {
            return `element-plus/theme-chalk/${name}.css`
          },
        },
      ]
    }),
  ],
}

7、Non-relative paths are not allowed when ‘baseUrl’ is not set. Did you forget a leading ‘./’

出现此问题,需要你在 tsconfig.json 中配置 baseUrl 为 “.” 或 “./”

8、vite.config.ts 中注入的 scss/less 变量无效

我们通常会使用 preprocessorOptions 字段来注入 scss/less 变量和样式,以便在组件中直接使用,但有时,我们配置后发现并不生效,在 vue 组件中读取不到注入的变量,此时可以按如下步骤排查问题:

  1. 检查 vite.config.ts 中是否正确配置 additionalData 字段;
  2. vue 文件中的 style 标签是否配置了 lang="scss"lang="less"

有时,控制台还会提示 @forward rules must be written before any other 这个错误,意思是某些样式必须要在其它样式之前引入,这里通常是指我们自定义过的 ElementUI 样式,我们稍微修改下配置,像下面这样既可以完美解决,这样 main.ts 中就不需要再去引入 elementui 的样式了。参考:element-plus 更换主题色报错

css: {
      preprocessorOptions: {
        scss: {
          prependData: '@use "@/assets/style/element/index.scss" as *;',  // elementui,如果你想导入所有样式 @use "element-plus/theme-chalk/src/index.scss" as *;
          additionalData: `@import "@/assets/style/vars.scss";`  // 注入scss变量
        }
      }
    }

9、推荐使用 VSCode 和 Vue 官方拓展 Volar,它为 Vue 3 提供了全面的 IDE 支持

你需要在 VSCode 中禁用(工作区) Vetur,避免两者冲突。

10、Uncaught TypeError: Cannot read properties of undefined (reading ‘config’)

使用 app.config.globalProperties 取代 Vue.prototype

11、ElementPlus 组件默认展示的文字是英文

因为 Element-Plus 框架默认显示的是英文版,需要修改语言配置,有两种方法来设置。

a. 如果你是全量引入 ElementPlus,可以在 main.ts 中添加如下代码:

import { createApp } from "vue";
import App from "./App.vue";
import ElementPlus from "element-plus";
import "element-plus/dist/index.css";
import 'dayjs/locale/zh-cn';
import locale from "element-plus/lib/locale/lang/zh-cn";

createApp(App).use(ElementPlus, { locale }).mount("#app");

b. 如果你是按需引入 ElementPlus,main.ts 中可能无法直接配置,此时可以利用 ElementPlus 提供的内置组件 ConfigProvider 来实现。我们可以在 App.vue 文件中像如下这样配置:

<template>
  <el-config-provider :locale="locale">
    <Layout />
  </el-config-provider>
</template>

<script setup lang="ts">
  import Layout from '@/layout/index.vue'
  import { ElConfigProvider } from 'element-plus'
  import zhCN from 'element-plus/lib/locale/lang/zh-cn'
  const locale = zhCN
</script>

<style>
  #app {
    font-family: Avenir, Helvetica, Arial, sans-serif;
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
  }
</style>

12、vite 项目修改 node_modules 中的模块后,引入的文件依然是旧的

为了提高运行速度,vite 在首次运行时,对 node_modules 中的包进行了 esmodule 化,存储在 node_modules/.vite 目录下,这样下次就可以直接使用浏览器读取,提高加载速度。当我们修改了某一个 node_modules 后,vite 并不知道,也不会去更新 .vite 目录,所有我们只需要先删除 .vite 目录,然后重新运行项目即可。

13、setTimeout 和 setInterval 的类型定义

当我们再 ts 中使用 setTimeoutsetInterval 时,发现并没有 Timer 这个基本类型,于是我们直接使用 let timer:null | number = null 这种方式来定义,但是当我们给 timer 再次赋值的时候,发现还是会报错,提示 setTimeout 返回的不是 number 类型,此时只需要在 setTimeout 或 setInterval 前面加上 window 来调用即可。

let timer:null | number = null;
timer = window.setTimeout(() => {}, 1000)

14、TS 中如何定义 defineProps 和 defineEmits 的类型

interface Props {
  mode?: string
  type?: string
  data?: any
}
interface Emit {
  (e: 'approve' | 'cancel' | 'remove'): void
  (e: 'revise-record' | 'update-progress', id: number): void
  (e: 'save', form: Forms): void
}
  
// withDefaults 用来指定props的默认值,如果不需要可以直接写成
// const props = defineProps<Props>()
const props = withDefaults(defineProps<Props>(), {
  mode: 'add',
  type: 'form',
  data: {}
})
const emit = defineEmits<Emit>()

// 按上面的写法,当 Emit 中只有一项时,Eslint 可能会提示 prefer-function-type,意思是建议你使用函数类型声明
// 所以我们把 interface 修改为 type 即可解决
type Emit = (e: 'select' | 'remove', data: Person, index: number) => void
const emit = defineEmits<Emit>()
  
// 当然你也可以在 eslintrc.js 中禁用该规则   
// .eslintrc.json
{
  "rules": {
    "@typescript-eslint/prefer-function-type": "off"
  }
}

15、Vue3 setup 语法为组件添加 name 属性

Vue3 默认会根据文件名来推断组件的名称,如果组件对应的文件名为 index.vue,那么在 vue-dev-tools 中看到的组件就都是 Index,不太好区分,而且在使用 keep-aliveincludeexclude 功能时,必须显示的声明 name 才能正常执行逻辑。
在以往的 Vue 版本中,我们可以直接在 script 中通过 name 属性为组件指定名字,但是如果你使用 vue3setup 语法,是不支持直接定义 name 的,你需要通过 vite-plugin-vue-setup-extend 插件来实现。

1、安装

yarn add vite-plugin-vue-setup-extend -D

2、配置 vite.config.ts

import { defineConfig } from 'vite'
import VueSetupExtend from 'vite-plugin-vue-setup-extend'
export default defineConfig({
  plugins: [ VueSetupExtend() ]
})

3、使用

<script lang="ts" setup name="demo"></script>

16、watch 监听多个数据

// 监听城市--->单个数据
watch(() => state.country, () => {
    // 更改城市时重置之前填写的详细地址
        state.detailedAdress = "";
        console.log(state.countries);
        }
      );
    // 写两个watch太麻烦,现用watch监听省份和城市两个数据
    // 第一个参数() => [state.province, state.country] 监听的两个数据
    // 第二个参数回调函数,其中参数分别代表更改后与更改前的值,([newprovince,newcountry],[oldprovince,oldcountry]) ,第一个参数依次代表更改后的值,第二个参数依次代表更改前的值
      watch(() => [state.province, state.country], ([newprovince,newcountry],[oldprovince,oldcountry]) => {
        console.log(oldprovince,'省份---', newprovince);
        console.log(newcountry,'cs---', oldcountry);
        // 判断是不是省份发生的变化
        if(oldprovince !== newprovince) {
        const arr = state.allCity.filter((item) => item.province == state.province);
        state.countries = arr[0].cities;
        console.log(arr);
        state.country = "";
        }
        state.detailedAdress = "";
        console.log(state.countries);
      }
    );  

17、Vue3 + TS 中使用 svg 图标

直接参考使用 vite-plugin-svg-icons 来支持,具体请查看它的 文档

18、获取当前组件实例

const { appContext } = getCurrentInstance()!

19、使用最新版 vue-router 配置 404 页面时提示如下错误

Catch all routes (“*“) must now be defined using a param with a custom regexp
原因:Vue Router 不再使用 path-to-regexp,而是实现了自己的解析系统,该系统允许路由排名并启用动态路由。由于我们通常会在每个项目中添加一条单独的包罗万象的路线,因此支持的特殊语法没有太大的好处。参数的编码是跨路线编码,无一例外使事情更容易预测。

 [{
    path: '/404',
    name: '404',
    component: () => import('@/views/404.vue')
  },
  {
    path: '/:pathMatch(.*)',
    redirect: '/404'
  }]

20、Vue3 v-for 循环中如何赋值和获取 ref

由于数组中每一个元素 key 都是唯一的,可以通过 key 值给对应内容赋值

<div v-for=(item, index) in arrList>
	<div :ref="el => myRefs[index]=el"></div>
</div>

<script setup lang="ts">
	const myRefs = ref<Ref<string[]>>([])
	return {
		myRefs
	}
</script>

21、Element UI 中 ElMessageBox.prompt 中 inputValidator 的用法

当我们在使用 ElMessageBox.prompt 时,如果要对其中的 input 内容进行校验,需要用到 inputValidator 这个字段,配置自定义的验证规则,它是一个函数,返回 true 和 false,如果返回的是字符串,将作为展示的错误文案。代码如下:

ElMessageBox.prompt('量化单位:', '', {
      customClass: 'prompt-custom-unit',
      showClose: false,
      closeOnClickModal: false,
      closeOnPressEscape: false,
      dangerouslyUseHTMLString: true,
      // inputErrorMessage: '量化单位不能为空',
      inputValidator: (value: string) => {
        if (!value) return '量化单位不能为空'
        if (value.length > 10) return '量化单位最多10个字符'
        return true
      },
      beforeClose: (action, instance, done) => {
        if (action === 'confirm') {
          const value = instance.inputValue
          row.unit = value
        } else {
          row.unit = ''
        }
        done()
      }
    })

参考文章

Vite2 + Vue3 + TypeScript + Pinia 搭建一套企业级的开发脚手架【值得收藏】

2
广告 广告

评论区