分享 15 个 Vue3 全家桶开发的避坑经验 下

简介: 分享 15 个 Vue3 全家桶开发的避坑经验 下

二、Vite

1. Vite 动态导入的使用问题

文档地址:cn.vitejs.dev/guide/featu…

使用 webpack 的同学应该都知道,在 webpack 中可以通过 require.context动态导入文件:

// https://webpack.js.org/guides/dependency-management/
require.context('./test', false, /\.test\.js$/);

在 Vite 中,我们可以使用这两个方法来动态导入文件:

  • import.meta.glob

该方法匹配到的文件默认是懒加载,通过动态导入实现,构建时会分离独立的 chunk,是异步导入,返回的是 Promise,需要做异步操作,使用方式如下:

const Components = import.meta.glob('../components/**/*.vue');
// 转译后:
const Components = {
  './components/a.vue': () => import('./components/a.vue'),
  './components/b.vue': () => import('./components/b.vue')
}
  • import.meta.globEager

该方法是直接导入所有模块,并且是同步导入,返回结果直接通过 for...in循环就可以操作,使用方式如下:

const Components = import.meta.globEager('../components/**/*.vue');
// 转译后:
import * as __glob__0_0 from './components/a.vue'
import * as __glob__0_1 from './components/b.vue'
const modules = {
  './components/a.vue': __glob__0_0,
  './components/b.vue': __glob__0_1
}

如果仅仅使用异步导入 Vue3 组件,也可以直接使用 Vue3 defineAsyncComponent API 来加载:

// https://v3.cn.vuejs.org/api/global-api.html#defineasynccomponent
import { defineAsyncComponent } from 'vue'
const AsyncComp = defineAsyncComponent(() =>
  import('./components/AsyncComponent.vue')
)
app.component('async-component', AsyncComp)

2. Vite 配置 alias 类型别名

文档地址:cn.vitejs.dev/config/#res…

当项目比较复杂的时候,经常需要配置 alias 路径别名来简化一些代码:

import Home from '@/views/Home.vue' 

在 Vite 中配置也很简单,只需要在 vite.config.tsresolve.alias中配置即可:

// vite.config.ts
export default defineConfig({
  base: './',
  resolve: {
    alias: {
      "@": path.join(__dirname, "./src")
    },
  }
  // 省略其他配置
})

如果使用的是 TypeScript 时,编辑器会提示路径不存在的警告⚠️,这时候可以在 tsconfig.json中添加 compilerOptions.paths的配置:

{
  "compilerOptions": {
    "paths": {
      "@/*": ["./src/*"]
     }
  }
}

3. Vite 配置全局 scss

文档地址:cn.vitejs.dev/config/#css…

当我们需要使用 scss 配置的主题变量(如 $primary)、mixin方法(如 @mixin lines)等时,如:

<script setup lang="ts">
</script>
<template>
  <div class="container"></div>
</template>
<style scoped lang="scss">
  .container{
    color: $primary;
    @include lines;
  }
</style>

我们可以将 scss 主题配置文件,配置在 vite.config.tscss.preprocessorOptions.scss.additionalData中:

// vite.config.ts
export default defineConfig({
  base: './',
  css: {
    preprocessorOptions: {
      // 添加公共样式
      scss: {
        additionalData: '@import "./src/style/style.scss";'
      }
    }
  },
  plugins: [vue()]
  // 省略其他配置
})

如果不想使用 scss 配置文件,也可以直接写成 scss 代码:

export default defineConfig({
  css: {
    preprocessorOptions: {
      scss: {
        additionalData: '$primary: #993300'
      }
    }
  }
})

三、VueRouter

1. script-setup 模式下获取路由参数

文档地址:router.vuejs.org/zh/guide/ad…

由于在 script-setup模式下,没有 this可以使用,就不能直接通过 this.$routerthis.$route来获取路由参数和跳转路由。

当我们需要获取路由参数时,就可以使用 vue-router提供的 useRoute方法来获取,使用如下:

// A.vue
<script setup lang="ts">
import { ref, onMounted } from 'vue';
import router from "@/router";
import { useRoute } from 'vue-router'
let detailId = ref<string>('');
onMounted(() => {
    const route = useRoute();
    detailId.value = route.params.id as string; // 获取参数
})
</script>

如果要做路由跳转,就可以使用 useRouter方法的返回值去跳转:

const router = useRouter();
router.push({
  name: 'search',
  query: {/**/},
})

四、Pinia

1. store 解构的变量修改后没有更新

文档地址:pinia.vuejs.org/core-concep…

当我们解构出 store 的变量后,再修改 store 上该变量的值,视图没有更新:

// A.vue
<script setup lang="ts">
import componentStore from "@/store/component";
const componentStoreObj = componentStore();
let { name } = componentStoreObj;
const changeName = () => {
  componentStoreObj.name = 'hello pingan8787';
}
</script>
<template>
  <span @click="changeName">{{name}}</span>
</template>

这时候点击按钮触发 changeName事件后,视图上的 name 并没有变化。这是因为 store 是个 reactive 对象,当进行解构后,会破坏它的响应性。所以我们不能直接进行解构。

这种情况就可以使用 Pinia 提供 storeToRefs工具方法,使用起来也很简单,只需要将需要解构的对象通过 storeToRefs方法包裹,其他逻辑不变:

// A.vue
<script setup lang="ts">
import componentStore from "@/store/component";
import { storeToRefs } from 'pinia';
const componentStoreObj = componentStore();
let { name } = storeToRefs(componentStoreObj); // 使用 storeToRefs 包裹
const changeName = () => {
  componentStoreObj.name = 'hello pingan8787';
}
</script>
<template>
  <span @click="changeName">{{name}}</span>
</template>

这样再修改其值,变更马上更新视图了。

2. Pinia 修改数据状态的方式

按照官网给的方案,目前有三种方式修改:

  1. 通过 store.属性名赋值修改单笔数据的状态;

这个方法就是前面一节使用的:

const changeName = () => {
  componentStoreObj.name = 'hello pingan8787';
}
  1. 通过 $patch方法修改多笔数据的状态;

文档地址:pinia.vuejs.org/api/interfa…

当我们需要同时修改多笔数据的状态时,如果还是按照上面方法,可能要这么写:

const changeName = () => {
  componentStoreObj.name = 'hello pingan8787'
  componentStoreObj.age = '18'
  componentStoreObj.addr = 'xiamen'
}

上面这么写也没什么问题,但是 Pinia 官网已经说明,使用 $patch的效率会更高,性能更好,所以在修改躲避数据时,更推荐使用 $patch,使用方式也很简单:

const changeName = () => {
  // 参数类型1:对象
  componentStoreObj.$patch({
    name: 'hello pingan8787',
    age: '18',
    addr: 'xiamen',
  })
  // 参数类型2:方法,该方法接收 store 中的 state 作为参数
  componentStoreObj.$patch(state => {
    state.name = 'hello pingan8787';
    state.age = '18';
    state.addr = 'xiamen';
  })
}
  1. 通过 action方法修改多笔数据的状态;

也可以在 store 中定义 actions 的一个方法来更新:

// store.ts
import { defineStore } from 'pinia';
export default defineStore({
    id: 'testStore',
    state: () => {
        return {
            name: 'pingan8787',
            age: '10',
            addr: 'fujian'
        }
    },
    actions: {
        updateState(){
            this.name = 'hello pingan8787';
            this.age = '18';
            this.addr = 'xiamen';
        }
    }
})

使用时:

const changeName = () => {
  componentStoreObj.updateState();
}

这三种方式都能更新 Pinia 中 store 的数据状态。

五、Element Plus

1. element-plus 打包时 @charset 警告

项目新安装的 element-plus 在开发阶段都是正常,没有提示任何警告,但是在打包过程中,控制台输出下面警告内容:

网络异常,图片无法展示
|

在官方 issues 中查阅很久:github.com/element-plu…

尝试在 vite.config.ts中配置 charset: false,结果也是无效:

// vite.config.ts
export default defineConfig({
  css: {
    preprocessorOptions: {
      scss: {
        charset: false // 无效
      }
    }
  }
})

最后在官方的 issues 中找到处理方法:

// vite.config.ts
// https://blog.csdn.net/u010059669/article/details/121808645
css: {
  postcss: {
    plugins: [
      // 移除打包element时的@charset警告
      {
        postcssPlugin: 'internal:charset-removal',
        AtRule: {
          charset: (atRule) => {
            if (atRule.name === 'charset') {
              atRule.remove();
            }
          }
        }
      }
    ],
  },
}

2. 中文语言包配置

文档地址:element-plus.gitee.io/zh-CN/guide…

默认 elemnt-plus 的组件是英文状态:

网络异常,图片无法展示
|

我们可以通过引入中文语言包,并添加到 ElementPlus 配置中来切换成中文:

// main.ts
// ... 省略其他
import ElementPlus from 'element-plus';
import 'element-plus/dist/index.css';
import locale from 'element-plus/lib/locale/lang/zh-cn'; // element-plus 中文语言包
app.use(ElementPlus, { locale }); // 配置中文语言包

这时候就能看到 ElementPlus 里面组件的文本变成中文了。

网络异常,图片无法展示
|

总结

以上是我最近从入门到实战 Vue3 全家桶的 3 个项目后总结避坑经验,其实很多都是文档中有介绍的,只是刚开始不熟悉。也希望大伙多看看文档咯~

Vue3 script-setup 模式确实越写越香。

本文内容如果有问题,欢迎大家一起评论讨论。

目录
相关文章
|
19天前
|
JavaScript 前端开发 索引
「Vue3系列」Vue3 条件语句/循环语句
在 Vue 3 中,你可以使用条件语句来动态地控制模板中的渲染内容。Vue 提供了多种方式来实现条件渲染,包括 `v-if`、`v-else-if`、`v-else` 和 `v-show` 指令。
33 0
|
20天前
Vue3框架中让table合计居中对齐
Vue3框架中让table合计居中对齐
|
20天前
Vue3 子/父组件相互调用
Vue3 子/父组件相互调用
35 0
|
20天前
|
JavaScript
vue3 使用element plus 打包时 报错
vue3 使用element plus 打包时 报错
23 0
|
16天前
|
JavaScript 前端开发 数据安全/隐私保护
Vue3——如何实现页面访问拦截
Vue3——如何实现页面访问拦截
|
20天前
Vue3 子传父 暴露数据 defineExpose
Vue3 子传父 暴露数据 defineExpose
Vue3 子传父 暴露数据 defineExpose
|
1天前
|
JSON 数据可视化 前端开发
vue3+threejs+koa可视化项目——模型文件上传(第四步)
vue3+threejs+koa可视化项目——模型文件上传(第四步)
15 7
|
1天前
|
JSON 数据可视化 数据库
vue3+threejs+koa可视化项目——实现登录注册(第三步)
vue3+threejs+koa可视化项目——实现登录注册(第三步)
18 5
|
1天前
|
JavaScript 数据可视化 算法
vue3+threejs可视化项目——搭建vue3+ts+antd路由布局(第一步)
vue3+threejs可视化项目——搭建vue3+ts+antd路由布局(第一步)
16 6
|
10天前
|
JavaScript 算法 前端开发
vue3和vue2的区别都有哪些
【4月更文挑战第15天】Vue3与Vue2在响应式系统(Proxy vs. Object.defineProperty)、组件模块化(Composition API vs. Options API)、数据变化检测(Reactive API vs. $watch)、虚拟DOM算法(基于迭代 vs. 基于递归)及Tree-Shaking支持上存在显著差异。Vue3的改进带来了更好的性能和灵活性,适合追求新技术的项目。Vue2则因其成熟稳定,适合维护大型项目。选择版本需根据项目需求、团队情况和技术追求来决定。
13 0