首页 > 其他分享 >备战2021:vite2项目最佳实践

备战2021:vite2项目最佳实践

时间:2022-10-06 15:31:39浏览次数:53  
标签:插件 vue const router 备战 2021 import vite2 path

备战2021:vite2项目最佳实践_ide


备战2021:Vite2项目最佳实践

作者同款机械键盘

vite2来了

​Vite1​​​还没用上,​​Vite2​​​已经更新了,全新插件架构,丝滑的开发体验,和​​Vue3​​的完美结合。2021年第一弹,村长打算以Vite2+Vue3为主题开启大家的前端学习之旅。

2021先学学vite准没错

备战2021:vite2项目最佳实践_ios_02

本文目标

  • ​vite2​​变化分析
  • 项目中常见任务​​vite2+vue3​​实践

创建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:vite2项目最佳实践_ios_03

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

备战2021:vite2项目最佳实践_css_04

别名定义

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

import path from 'path'

export default {
alias: {
"@": path.resolve(__dirname, "src"),
"comps": path.resolve(__dirname, "src/components"),
},
}

​App.vue​​里面用一下试试

<script setup>
import HelloWorld from 'comps/HelloWorld.vue'
</script>

插件API重新设计

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

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

Vue3 Jsx支持

​vue3​​​中​​jsx​​​支持需要引入插件:​​@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​

<!-- 1.标记为jsx -->
<script setup lang="jsx">
import { defineComponent } from "vue";
import HelloWorld from "comps/HelloWorld.vue";
import logo from "./assets/logo.png"

// 2.用defineComponent定义组件且要导出
export default defineComponent({
render: () => (
<>
<img alt="Vue logo" src={logo} />
<HelloWorld msg="Hello Vue 3 + Vite" />
</>
),
});
</script>
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"
},
}

项目基础架构

路由

安装​​vue-router 4.x​

npm i vue-router@next -S

备战2021:vite2项目最佳实践_ide_05

路由配置,​​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:vite2项目最佳实践_css_06

Store配置,​​store/index.js​

import {createStore} from 'vuex';

export const store = createStore({
state: {
couter: 0
}
});

引入,​​main.js​

import store from "@/store";
createApp(App).use(store).mount("#app");

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

样式组织

安装sass

npm i sass -D

​styles​​目录保存各种样式

备战2021:vite2项目最佳实践_ios_07截屏2020-12-24 上午11.51.30

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

备战2021:vite2项目最佳实践_ide_08image-20201224115414266

最后在​​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);
}

测试

<el-button>my button</el-button>

基础布局

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

备战2021:vite2项目最佳实践_ide_09image-20201223143247535

布局页面,​​layout/index.vue​

<template>
<div class="app-wrapper">
<!-- 侧边栏 -->
<div class="sidebar-container"></div>
<!-- 内容容器 -->
<div class="main-container">
<!-- 顶部导航栏 -->
<navbar />
<!-- 内容区 -->
<app-main />
</div>
</div>
</template>

<script setup>
import AppMain from "./components/AppMain.vue";
import Navbar from "./components/Navbar.vue";
</script>

<style lang="scss" scoped>
@import "../styles/mixin.scss";

.app-wrapper {
@include clearfix;
position: relative;
height: 100%;
width: 100%;
}
</style>

别忘了创建​​AppMain.vue​​​和​​Navbar.vue​

路由配置,​​router/index.js​

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

动态导航

侧边导航

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

备战2021:vite2项目最佳实践_ios_10image-20201225180300250

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

<template>
<el-scrollbar wrap-class="scrollbar-wrapper">
<el-menu
:default-active="activeMenu"
:background-color="variables.menuBg"
:text-color="variables.menuText"
:unique-opened="false"
:active-text-color="variables.menuActiveText"
mode="vertical"
>
<sidebar-item
v-for="route in routes"
:key="route.path"
:item="route"
:base-path="route.path"
/>
</el-menu>
</el-scrollbar>
</template>

<script setup>
import SidebarItem from "./SidebarItem.vue";
import { computed } from "vue";
import { useRoute } from "vue-router";
import { routes } from "@/router";
import variables from "styles/variables.module.scss";

const activeMenu = computed(() => {
const route = useRoute();
const { meta, path } = route;
if (meta.activeMenu) {
return meta.activeMenu;
}
return path;
});
</script>

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

添加相关样式:

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

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

备战2021:vite2项目最佳实践_css_11image-20201229123955087

面包屑

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

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

<template>
<el-breadcrumb class="app-breadcrumb" separator="/">
<el-breadcrumb-item v-for="(item, index) in levelList" :key="item.path">
<span
v-if="item.redirect === 'noRedirect' || index == levelList.length - 1"
class="no-redirect"
>{{ item.meta.title }}</span>
<a v-else @click.prevent="handleLink(item)">{{ item.meta.title }}</a>
</el-breadcrumb-item>
</el-breadcrumb>
</template>

<script setup>
import { compile } from "path-to-regexp";
import { reactive, ref, watch } from "vue";
import { useRoute, useRouter } from "vue-router";

const levelList = ref(null);
const router = useRouter();
const route = useRoute();

const getBreadcrumb = () => {
let matched = route.matched.filter((item) => item.meta && item.meta.title);

const first = matched[0];
if (first.path !== "/") {
matched = [{ path: "/home", meta: { title: "首页" } }].concat(matched);
}

levelList.value = matched.filter(
(item) => item.meta && item.meta.title && item.meta.breadcrumb !== false
);
}

const pathCompile = (path) => {
var toPath = compile(path);
return toPath(route.params);
}

const handleLink = (item) => {
const { redirect, path } = item;
if (redirect) {
router.push(redirect);
return;
}
router.push(pathCompile(path));
}

getBreadcrumb();
watch(route, getBreadcrumb)

</script>

<style lang="scss" scoped>
.app-breadcrumb.el-breadcrumb {
display: inline-block;
font-size: 14px;
line-height: 50px;
margin-left: 8px;

.no-redirect {
color: #97a8be;
cursor: text;
}
}
</style>

别忘了添加依赖:​​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:vite2项目最佳实践_ios_12image-20210201110626262

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

备战2021:vite2项目最佳实践_ide_13image-20210201110542893

​list.vue​​中的数据展示

<el-table v-loading="loading" :data="list">
<el-table-column label="ID" prop="id"></el-table-column>
<el-table-column label="账户名" prop="name"></el-table-column>
<el-table-column label="年龄" prop="age"></el-table-column>
</el-table>

​list​​​和​​loading​​​数据的获取逻辑,可以使用​​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​

<pagination
:total="total"
v-model:page="listQuery.page"
v-model:limit="listQuery.limit"
@pagination="getList"
></pagination>

数据也在​​userModel​​中处理

const state = reactive({
total: 0, // 总条数
listQuery: {// 分页查询参数
page: 1, // 当前页码
limit: 5, // 每页条数
},
});
request({
url: "/getUsers",
method: "get",
params: state.listQuery, // 在查询中加入分页参数
})
表单处理

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

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

<el-form ref="form" :model="model" :rules="rules">
<el-form-item prop="name" label="用户名">
<el-input v-model="model.name"></el-input>
</el-form-item>
<el-form-item prop="age" label="用户年龄">
<el-input v-model.number="model.age"></el-input>
</el-form-item>
<el-form-item>
<el-button @click="submitForm" type="primary">提交</el-button>
</el-form-item>
</el-form>

数据处理同样可以提取到​​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项目最佳实践

制作不易,求一个​​3连​​​、​​关注​​不过分吧!?

配套源码讲义

欢迎关注公众号「村长学前端」自取

后续创作计划

vite2最重要的更新莫过于插件系统,后续我打算搞一搞,包括不限于如下内容:

  • vite2工作机制分析
  • vite2插件机制分析
  • vite2插件编写实战 大家点个赞,收藏一下,以便后续学习。

支持村长

关于vite2项目实践就说到这里,这篇内容折腾了很久,踩了不少坑,掉了几根头发,小伙伴们点个赞

标签:插件,vue,const,router,备战,2021,import,vite2,path
From: https://blog.51cto.com/u_15680963/5733735

相关文章

  • 备战2021:Vite2插件开发指南
    Vite插件是什么使用Vite插件可以扩展Vite能力,比如解析用户自定义的文件输入,在打包代码前转译代码,或者查找第三方模块。image-20210216214524914Vite插件的形式​​Vite​​......
  • MSC Adams 2021软件安装包和安装教程
    MSCAdams2021软件简介:MSCAdams2021是一款著名的机械系统动态仿真分析软件,使用交互式图形环境和零件库、约束库、力库,创建完全参数化的机械系统几何模型,可以帮助工程师在......
  • A Unified Generative Framework for Aspect-Based Sentiment Analysis 基于方面的情
    摘要基于方面的情感分析(ABSA)旨在识别方面术语、相应的情感极性和观点术语。ABSA中有七个子任务。大多数研究只关注这些子任务的子集,这导致了各种复杂的ABSA模型,但很难在统......
  • Microsoft Office LTSC 2021 for Macv16.67 beta版mac/win
    近日,微软公司发布了office 2021Standard(预览版),以在组织中运行macOS的设备上进行安装和测试。本站第一时间为您带来office2021forMac商业预览版,Mac版office2021包括W......
  • 「ROIR 2021 Day 1」题解
    loj有原题。别问为什么没T4,问就是不会,等以后来补。T1-两台机器设两台机子分别为\(a,b\),分\(4\)种情况:只用\(a\),只用\(b\),先\(a\)后\(b\),先\(b\)后\(a\),判断......
  • 报告分享|2021中国实体零售数字化专题报告
    全文链接:http://tecdat.cn/?p=28716原文出处:拓端数据部落公众号 作者:MingjiTang统计学中传统的数据类型有截面数据和时间序列数据。这两者都只能在某一纵向或横向上......
  • Premiere Pro 2021 for Mac(pr 2021 直装版)v15.4.1中文版 mac/win
    PremierePro2021forMac是Adobe公司旗下的一款功能强大的视频编辑软件,具有智能化视频剪辑工具,可以为您提供采集、剪辑、调色、美化音频、字幕添加、输出、DVD刻录的一整......
  • 【补档】CSP2021-J 游记
    (洛谷博客版本)前传:CSP2020-J游记上一次拿了2=,这次争取冲1=!主要时间花在复赛内容上面了,初赛没怎么搞。初赛看到前15题一阵狂喜:这次稳了。单选好像只错了两三题的......
  • 2022-2023-1 20211326《信息安全专业导论》第六周学习总结
    作业信息(1)XOR加密https://www.mosoteach.cn/web/index.php?c=interaction_homework&m=s_write&clazz_course_id=C070E3BB-B075-4571-98F8-B939119D851A&id=D647648F-56AB......
  • CVE-2021- 22205漏洞复现
    一、漏洞概述2021年4⽉15⽇,GitLab官方发布安全补丁更新修复了GitLab命令执行漏洞(CVE-2021-22205)。由于GitLab中的ExifTool没有对传⼊的图像文件的扩展名进行正确处理,攻击......