2021必知必会的vite+vue3项目最佳实践

发布时间:2024-06-01 19:01

2021学什么

2021第一更是尤大的Vite2,全新插件架构,丝滑的开发体验,和Vue3的完美结合。 2021年第一弹,村长将以Vite2+Vue3为主题开启大家的前端学习之旅。

\"2021必知必会的vite+vue3项目最佳实践_第1张图片\"

“我自己是一名从事了6年web前端开发的老程序员(我的微信:webxxq),今年年初我花了一个月整理了一份最适合2021年自学的web前端全套培训教程(视频+源码+笔记+项目实战),从最基础的HTML+CSS+JS到移动端HTML5以及各种框架和新技术都有整理,打包给每一位前端小伙伴,这里是前端学习者聚集地,欢迎初学和进阶中的小伙伴(所有前端教程关注我的微信公众号:web前端学习圈,关注后回复“web”即可领取)。

本文目标

vue3+vite2项目中常见任务实践:

  • 基建:配置、lint、测试、样式组织、服务封装、数据mock、UI库整合、路由、状态管理等
  • 常见业务编写和代码组织
  • 打包发布

创建Vite2项目

闲言碎语不必说,下面我们表一表好汉vite2

使用npm:

$ npm init @vitejs/app
复制代码

按提示指定项目名称和模板,或直接指定

$ npm init @vitejs/app my-vue-app --template vue
复制代码

Vite2主要变化

  • 配置选项变化:vue特有选项、创建选项、css选项、jsx选项等、别名行为变化:不再要求/开头或结尾
  • Vue支持:通过 @vitejs/plugin-vue插件支持
  • React支持
  • HMR API变化
  • 清单格式变化
  • 插件API重新设计

Vue支持

Vue的整合也通过插件实现,和其他框架一视同仁:

\"2021必知必会的vite+vue3项目最佳实践_第2张图片\"

SFC定义默认使用setup script,语法比较激进,但更简洁,好评!

\"2021必知必会的vite+vue3项目最佳实践_第3张图片\"

别名定义

不再需要像vite1一样在别名前后加上/,这和webpack项目配置可以保持一致便于移植,好评!

import path from \'path\'

export default {
  alias: {
    \"@\": path.resolve(__dirname, \"src\"),
    \"comps\": path.resolve(__dirname, \"src/components\"),
  },
}
复制代码

App.vue里面用一下试试


复制代码

插件API重新设计

Vite2主要变化在插件体系,这样更标准化、易扩展。Vite2插件API扩展自Rollup插件体系,因此能兼容现存的Rollup插件,编写的Vite插件也可以同时运行于开发和创建,好评!

插件编写我会另开专题讨论,欢迎大家关注我。

Vue3 Jsx支持

vue3jsx支持需要引入插件:@vitejs/plugin-vue-jsx

$ npm i @vitejs/plugin-vue-jsx -D
复制代码

注册插件,vite.config.js

import vueJsx from \"@vitejs/plugin-vue-jsx\";

export default {
  plugins: [vue(), vueJsx()],
}
复制代码

用法也有要求,改造一下App.vue



复制代码

Mock插件应用

之前给大家介绍的vite-plugin-mock已经重构支持了Vite2。

安装插件

npm i mockjs -S
复制代码

npm i vite-plugin-mock cross-env -D
复制代码

配置,vite.config.js

import { viteMockServe } from \'vite-plugin-mock\'

export default {
  plugins: [ viteMockServe({ supportTs: false }) ]
}
复制代码

设置环境变量,package.json

{
  \"scripts\": {
    \"dev\": \"cross-env NODE_ENV=development vite\",
    \"build\": \"vite build\"
  },
} 

工程化

基础配置、样式处理、lint、测试、打包发布等参见我上一篇文章:vite工程化实践

项目基础架构

路由

安装vue-router 4.x

npm i vue-router@next -S
复制代码

\"2021必知必会的vite+vue3项目最佳实践_第4张图片\"

路由配置,router/index.js

import { createRouter, createWebHashHistory } from \'vue-router\';

const router = createRouter({
  history: createWebHashHistory(),
  routes: [
    { path: \'/\', component: () => import(\'views/home.vue\') }
  ]
});

export default router
复制代码

引入,main.js

import router from \"@/router\";
createApp(App).use(router).mount(\"#app\");
复制代码

别忘了创建home.vue并修改App.vue

路由用法略有变化,村长的视频教程

状态管理

安装vuex 4.x

npm i vuex@next -S
复制代码

\"2021必知必会的vite+vue3项目最佳实践_第5张图片\"

Store配置,store/index.js

import {createStore} from \'vuex\';

export default createStore({
  state: {
    couter: 0
  }
});
复制代码

引入,main.js

import store from \"@/store\";
createApp(App).use(store).mount(\"#app\");
复制代码

用法和以前基本一样,村长的视频教程

样式组织

安装sass

npm i sass -D
复制代码

styles目录保存各种样式

\"2021必知必会的vite+vue3项目最佳实践_第6张图片\"

index.scss作为出口组织这些样式,同时编写一些全局样式

\"2021必知必会的vite+vue3项目最佳实践_第7张图片\"

最后在main.js导入

import \"styles/index.scss\";
复制代码

注意在vite.config.js添加styles别名

UI库

就用我们花果山团队自家的element3。

中文文档

安装

npm i element3 -S
复制代码

完整引入,main.js

import element3 from \"element3\";
import \"element3/lib/theme-chalk/index.css\";

createApp(App).use(element3)
复制代码

按需引入,main.js

import \"element3/lib/theme-chalk/button.css\";
import { ElButton } from \"element3\"
createApp(App).use(ElButton)
复制代码

抽取成插件会更好,plugins/element3.js

// 完整引入
import element3 from \"element3\";
import \"element3/lib/theme-chalk/index.css\";

// 按需引入
// import { ElButton } from \"element3\";
// import \"element3/lib/theme-chalk/button.css\";

export default function (app) {
  // 完整引入
  app.use(element3)

  // 按需引入
  // app.use(ElButton);
}

测试

my button
复制代码

基础布局

我们应用需要一个基本布局页,类似下图,将来每个页面以布局页为父页面即可:

\"2021必知必会的vite+vue3项目最佳实践_第8张图片\"

布局页面,layout/index.vue






复制代码

别忘了创建AppMain.vueNavbar.vue

路由配置,router/index.js

{
  path: \"/\",
	component: Layout,
  children: [
    {
      path: \"\",
      component: () => import(\'views/home.vue\'),
      name: \"Home\",
      meta: { title: \"首页\", icon: \"el-icon-s-home\" },
    },
  ],
},
复制代码

动态导航

侧边导航

根据路由表动态生成侧边导航菜单。

\"2021必知必会的vite+vue3项目最佳实践_第9张图片\"

首先创建侧边栏组件,递归输出routes中的配置为多级菜单,layout/Sidebar/index.vue





复制代码

注意:sass文件导出变量解析需要用到css module,因此variables文件要加上module中缀。

添加相关样式:

  • styles/variables.module.scss
  • styles/sidebar.scss
  • styles/index.scss中引入

创建SidebarItem.vue组件,解析当前路由是导航链接还是父菜单:

\"2021必知必会的vite+vue3项目最佳实践_第10张图片\"

面包屑

通过路由匹配数组可以动态生成面包屑。

面包屑组件,layouts/components/Breadcrumb.vue






复制代码

别忘了添加依赖:path-to-regexp

注意:vue-router4已经不再使用path-to-regexp解析动态path,因此这里后续还需要改进。

数据封装

统一封装数据请求服务,有利于解决一下问题:

  • 统一配置请求
  • 请求、响应统一处理

准备工作:

  • 安装axios:

    npm i axios -S
    复制代码
    
  • 添加配置文件:.env.development

    VITE_BASE_API=/api
    复制代码
    

请求封装,utils/request.js

import axios from \"axios\";
import { Message, Msgbox } from \"element3\";

// 创建axios实例
const service = axios.create({
  // 在请求地址前面加上baseURL
  baseURL: import.meta.env.VITE_BASE_API,
  // 当发送跨域请求时携带cookie
  // withCredentials: true,
  timeout: 5000,
});

// 请求拦截
service.interceptors.request.use(
  (config) => {
    // 模拟指定请求令牌
    config.headers[\"X-Token\"] = \"my token\";
    return config;
  },
  (error) => {
    // 请求错误的统一处理
    console.log(error); // for debug
    return Promise.reject(error);
  }
);

// 响应拦截器
service.interceptors.response.use(
  /**
   * 通过判断状态码统一处理响应,根据情况修改
   * 同时也可以通过HTTP状态码判断请求结果
   */
  (response) => {
    const res = response.data;

    // 如果状态码不是20000则认为有错误
    if (res.code !== 20000) {
      Message.error({
        message: res.message || \"Error\",
        duration: 5 * 1000,
      });

      // 50008: 非法令牌; 50012: 其他客户端已登入; 50014: 令牌过期;
      if (res.code === 50008 || res.code === 50012 || res.code === 50014) {
        // 重新登录
        Msgbox.confirm(\"您已登出, 请重新登录\", \"确认\", {
          confirmButtonText: \"重新登录\",
          cancelButtonText: \"取消\",
          type: \"warning\",
        }).then(() => {
          store.dispatch(\"user/resetToken\").then(() => {
            location.reload();
          });
        });
      }
      return Promise.reject(new Error(res.message || \"Error\"));
    } else {
      return res;
    }
  },
  (error) => {
    console.log(\"err\" + error); // for debug
    Message({
      message: error.message,
      type: \"error\",
      duration: 5 * 1000,
    });
    return Promise.reject(error);
  }
);

export default service;

复制代码

常见业务处理

结构化数据展示

使用el-table展示结构化数据,配合el-pagination做数据分页。

\"2021必知必会的vite+vue3项目最佳实践_第11张图片\"

文件组织结构如下:list.vue展示列表,edit.vuecreate.vue编辑或创建,内部复用detail.vue处理,model中负责数据业务处理。

\"2021必知必会的vite+vue3项目最佳实践_第12张图片\"

list.vue中的数据展示


  
  
  

复制代码

listloading数据的获取逻辑,可以使用compsition-api提取到userModel.js

export function useList() {
  // 列表数据
  const state = reactive({
    loading: true, // 加载状态
    list: [], // 列表数据
  });

  // 获取列表
  function getList() {
    state.loading = true;
    return request({
      url: \"/getUsers\",
      method: \"get\",
    }).then(({ data, total }) => {
      // 设置列表数据
      state.list = data;
    }).finally(() => {
      state.loading = false;
    });
  }
  
  // 首次获取数据
  getList();

  return { state, getList };
}
复制代码

list.vue中使用

import { useList } from \"./model/userModel\";
复制代码

const { state, getList } = useList();
复制代码

分页处理,list.vue


复制代码

数据也在userModel中处理

const state = reactive({
  total: 0,   // 总条数
  listQuery: {// 分页查询参数
    page: 1,  // 当前页码
    limit: 5, // 每页条数
  },
});
复制代码

request({
  url: \"/getUsers\",
  method: \"get\",
  params: state.listQuery, // 在查询中加入分页参数
})

表单处理

用户数据新增、编辑使用el-form处理

可用一个组件detail.vue来处理,区别仅在于初始化时是否获取信息回填到表单。


  
    
  
  
    
  
  
    提交
  

复制代码

数据处理同样可以提取到userModel中处理。

export function useItem(isEdit, id) {
  const model = ref(Object.assign({}, defaultData));

  // 初始化时,根据isEdit判定是否需要获取详情
  onMounted(() => {
    if (isEdit && id) {
      // 获取详情
      request({
        url: \"/getUser\",
        method: \"get\",
        params: { id },
      }).then(({ data }) => {
        model.value = data;
      });
    }
  });
  return { model };
}
复制代码

配套视频演示

本文配套演示视频,喜欢看视频的小伙伴看这里: 「备战2021」Vite2 + Vue3项目最佳实践

配套源码

本文相关源码点这里

ItVuer - 免责声明 - 关于我们 - 联系我们

本网站信息来源于互联网,如有侵权请联系:561261067@qq.com

桂ICP备16001015号