1、ts 报错 Could not find a declaration file for module
ts 提示这个错误通常由以下几种情况:
- 引入的 npm 包不是用 typescript 编写的;
- 没有找到正确的类型定义文件;
针对第一种,我们可以尝试安装 @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 pop
或 git 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-import
和 consola
来实现自动引入
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 组件中读取不到注入的变量,此时可以按如下步骤排查问题:
- 检查
vite.config.ts
中是否正确配置additionalData
字段; - 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 中使用 setTimeout
和 setInterval
时,发现并没有 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-alive
的 include
和 exclude
功能时,必须显示的声明 name
才能正常执行逻辑。
在以往的 Vue 版本中,我们可以直接在 script
中通过 name
属性为组件指定名字,但是如果你使用 vue3
的 setup
语法,是不支持直接定义 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()
}
})
评论区