手把手,完整的从0搭建vite-vue3-ts项目框架:配置less+svg+pinia+vant+axios
项目同步git:https://gitee.com/lixin_ajax/vue3-vite-ts-pinia-vant-less.git
为避免赘述,过于基础的点会直接省略或贴图,比如创建文件夹/文件的路径/路由一类
配置相应功能,也尽量只贴相关代码,并不代表整个文件内容
我会尽量把每一步都记录下来,让跟随文档操作的朋友也能还原项目
项目不尽完美,但是主体功能应该都可以有所参考
一.本地初始环境
二.使用vite脚手架,创建vue3+ts
yarn create vite
输入项目名,回车确认
选择Vue和TypeScript
文件目录如下,项目创建成功!
三.启动项目:根据提示进入项目运行项目,或自行使用编码器输入指令进行启动
yarn // 安装依赖
yarn dev // 运行项目
浏览器打开地址,运行成功!
四.必备依赖
This package contains type definitions for Node.js (http://nodejs.org/)
yarn add @types/node -S -D
五.配置路径别名@
1.位置:直接改写vite.config.ts -- 顺便就添加alias
// vite.config.ts import vue from "@vitejs/plugin-vue";
import { resolve } from "path"; function pathResolve(dir: string) {
return resolve(process.cwd(), ".", dir);
} // https://vitejs.dev/config/
export default () => {
return {
resolve: {
alias: [
{
find: "@",
replacement: pathResolve("src"),
},
{
find: "views",
replacement: pathResolve("src/views"),
},
],
},
plugins: [vue()],
};
};
2.位置:tsconfig.json -- 修改baseUrl及paths
// tsconfig.json
六.配置vue-router
yarn add vue-router -S
推荐一个很好的插件nprogress【进度条】
yarn add @types/nprogress nprogress -D
main.ts引入router
// main.ts import { createApp } from 'vue'
import './style.css' import App from './App.vue'
import router from "./router"; const app = createApp(App as any);
app.use(router) app.mount('#app')
src下创建router文件夹,项目往往很大需要模块化,这里路由下分出一个test模块
/router/index.ts
/router/index.ts import { createRouter, createWebHashHistory, RouteRecordRaw } from "vue-router";
import NProgress from "nprogress";
import "nprogress/nprogress.css"; const modules: any = import.meta.glob("./modules/**/*.ts", { eager: true }); const routes: Array<RouteRecordRaw> = [];
for (const key in modules) {
routes.push(...modules[key].default);
} const router = createRouter({
history: createWebHashHistory(), // history 模式则使用 createWebHistory()
routes,
}); router.beforeEach(async (_to, _from, next) => {
NProgress.start();
next();
}); router.afterEach((_to) => {
NProgress.done();
}); export default router;
/router/typings.d.ts 路由meta格式受控
/router/typing.d.ts import "vue-router"; declare module "vue-router" {
interface RouteMeta {
// options
title?: string;
// every route must declare
show?: boolean; //
}
}
然后就是test下随便创建一个路由,对应的,views下创建相应的vue文件,App.vue给上router-view
test/index.ts
app.vue
test/index.vue
查看页面
页面正确显示,路由部署成功!
七.配置css预处理:less
yarn add less less-loader -D
为了配置全局的less样式文件,同时引入fs模块
yarn add fs -D
进入项目根目录的配置文件
位置:vite.config.ts -- css
// vite.config.ts import vue from "@vitejs/plugin-vue";
import { resolve } from "path";
import fs from 'fs' function pathResolve(dir: string) {
return resolve(process.cwd(), ".", dir);
} // https://vitejs.dev/config/
export default () => {
const lessResources: Array<String> = []
fs.readdirSync('src/assets/styles').map((dirname) => {
if (fs.statSync(`src/assets/styles/${dirname}`).isFile()) {
lessResources.push(`@import "src/assets/styles/${dirname}";`)
}
})
return {
......,// css
css: {
preprocessorOptions: {
less: {
charset: false,
additionalData: lessResources.join(''),
modifyVars: {
'primary-color': '#0080FF',
'link-color': '#0080FF',
'border-radius-base': '4px',
},
javascriptEnabled: true,
},
},
},
};
};
这里配置的公共less文件路径为src/assets/styles,创建styles文件夹和index.less文件
进入index.less声明全局样式,测试less配置是否成功
进入test/index.vue使用声明
查看页面
盒子背景颜色改变,less及全局less配置成功!
八.配置svg
yarn add vite-plugin-svg-icons -D
yarn add fast-glob -D
vite.config.ts引入插件
// vite.config.ts import vue from "@vitejs/plugin-vue";
import { createSvgIconsPlugin } from "vite-plugin-svg-icons";
import path from "path"; // https://vitejs.dev/config/
export default () => {
return {
......,
plugins: [
vue(),
createSvgIconsPlugin({
// 指定需要缓存的图标文件夹
iconDirs: [path.resolve(process.cwd(), "src/assets/icons")],
// 指定symbolId格式
symbolId: "icon-[dir]-[name]",
}),
],
};
};
根据config配置创建存放svg的目录文件,并创建SvgIcon组件
SvgIcon组件
// SvgIcon/index.vue <template>
<svg aria-hidden="true" class="svg-icon">
<use :xlink:href="symbolId" :fill="color" />
</svg>
</template> <script lang="ts" setup>
import { computed } from "vue"; const props = defineProps({
prefix: {
type: String,
default: "icon",
},
name: {
type: String,
required: true,
},
color: {
type: String,
default: "#333",
},
});
const symbolId = computed(() => `#${props.prefix}-${props.name}`);
</script>
<style lang="less" scoped>
.svg-icon {
width: 1em;
height: 1em;
fill: v-bind(color);
vertical-align: middle;
color: v-bind(color);
}
</style>
在main.ts中注册SvgIcon为全局组件
// main.ts import { createApp } from 'vue'
import './style.css'
import "virtual:svg-icons-register";
import SvgIcon from "@/components/SvgIcon/index.vue"; import App from './App.vue'
import router from "./router"; const app = createApp(App as any);
app.use(router) app.mount('#app')
app.component("SvgIcon", SvgIcon);
在test/index.vue中引入组件
// test/index.vue <svg-icon name="test-vue" />
查看页面,测试是否成功
页面显示svg图标,svg组件配置成功!
九.配置pinia
pinia: 类似vuex的仓库
pinia-use-persist: 持久加密缓存pinia数据
yarn add pinia pinia-use-persist -S
main.ts中引入pinia
// main.ts import { createApp } from 'vue'
import { createPinia } from 'pinia'
import { usePersist } from 'pinia-use-persist' import App from './App.vue' const app = createApp(App as any);
const pinia = createPinia()
pinia.use(usePersist)
app.use(pinia)
src下创建store目录存放相关文件
/store/modules下存放项目不同模块需要通过pinia通信的数据,假装项目有一个test模块,存放了一个数据number
// store/modules/test/index.ts import { defineStore } from "pinia"; interface stateType {
number: number;
} const useTestStore = defineStore("user", {
state: (): stateType => ({
number: 0,
}), getters: {}, actions: {
setNumber(number: number): void {
this.number = number;
},
}, persist: {
enabled: true,
encryptionKey: "contractAdmin",
},
}); export { useTestStore };
store/index.ts引入各模块
// store/index.ts import { createPinia } from "pinia";
import { useTestStore } from "./modules/test"; const pinia = createPinia(); export { useTestStore };
export default pinia;
回到test/index.vue,测试pinia配置是否成功
// test/index.vue <template>
<!-- 测试pinia -->
<button @click="number += 1">{{ number }}</button>
</div>
</template> <script setup lang="ts">
import { computed } from 'vue'
import { useTestStore } from '@/store' const store = useTestStore()
const number = computed<number>({
get() {
return store.number
},
set(value) {
store.setNumber(value)
},
})
</script>
点击按钮,查看页面是否变化
页面数据没有初始化,pinia配置成功!
十.配置vant ui
vant ui:https://vant-contrib.gitee.io/vant/v4/#/zh-CN/home
yarn add vant
这里再推荐一个插件,unplugin-vue-components【自动引入】,引入ui可以省去很多麻烦
yarn add unplugin-vue-components -D
vite.config.ts中引入vant ui
// vite.config.ts import vue from '@vitejs/plugin-vue';
import Components from 'unplugin-vue-components/vite';
import { VantResolver } from 'unplugin-vue-components/resolvers'; export default {
plugins: [
vue(),
Components({
resolvers: [VantResolver()],
}),
],
};
回到test/index.vue测试vant ui引入是否成功
// test/index.vue <!-- 测试vant ui -->
<div>
<van-button type="primary">vant button</van-button>
</div>
刷新页面查看
按钮有样式,vant ui引入成功!
但是官方描述:Vant 中有个别组件是以函数的形式提供的,包括 Toast,Dialog,Notify 和 ImagePreview 组件。在使用函数组件时,unplugin-vue-components 无法自动引入对应的样式,因此需要手动引入样式。
所以,这几个组件需要使用的话需要在main.ts中引入样式
// main.ts // Toast
import 'vant/es/toast/style';
// Dialog
import 'vant/es/dialog/style';
// Notify
import 'vant/es/notify/style';
// ImagePreview
import 'vant/es/image-preview/style';
回到test/index.vue测试,示例toast
// test/index.vue import { Toast } from 'vant' Toast('使用vant')
查看页面
toast有样式,vant ui引入成功!
但是,使用vant ui多是移动端,所以还要做移动端做以下适配
参考: https://vant-contrib.gitee.io/vant/v4/#/zh-CN/advanced-usage
1.适配安全距离
根据vant ui提供,在根文件index.html修改
// index.html <!-- 在 head 标签中添加 meta 标签,并设置 viewport-fit=cover 值 -->
<meta name="viewport"
content="width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, viewport-fit=cover" /> <!-- 开启顶部安全区适配 -->
<van-nav-bar safe-area-inset-top /> <!-- 开启底部安全区适配 -->
<van-number-keyboard safe-area-inset-bottom />
2.Viewport 布局
postcss-px-to-viewport-8-plugin:postcss-px-to-viewport-8-plugin 是一款 PostCSS 插件,用于将 px 单位转化为 vw/vh 单位。
yarn add postcss-px-to-viewport-8-plugin -D
vite.config.ts中更改配置
// vite.config.ts import pxtovw from 'postcss-px-to-viewport-8-plugin'
const loder_pxtovw = pxtovw({
//这里是设计稿宽度 自己修改
viewportWidth: 375,
viewportUnit: 'vw'
})
export default defineConfig({
......,
css: {
postcss: {
plugins: [loder_pxtovw]
}
}
})
创建一个types/index.d.ts,用于处理包括postcss-px-to-viewport-8-plugin一类的没有声明文件的依赖
// src/types/index.d.ts declare module "postcss-px-to-viewport-8-plugin"
刷新页面,F12查看样式
px已被转换,vant ui 及 移动端配置成功!
十一.配置axios
yarn add axios
// tsconfig.json {
"compilerOptions": {
......,
"types": ["vite/client", "vite-plugin-svg-icons/client"]
},
"include": [
"src/**/*.ts",
"src/**/*.d.ts",
"src/**/*.tsx",
"src/**/*.vue",
"*.ts",
],
"exclude": ["node_modules", "dist"],
"references": [{ "path": "./tsconfig.node.json" }]
}
src下创建axios请求文件
创建axios
// utils/http/axios/index.ts import axios, {
AxiosInstance,
AxiosRequestConfig,
AxiosResponse,
AxiosError,
} from "axios";
import { IResponse } from "./type"; // 如果请求超过 `timeout` 的时间,请求将被中断
axios.defaults.timeout = 5000; const axiosInstance: AxiosInstance = axios.create({
baseURL: import.meta.env.VITE_APP_API_BASEURL + "",
}); // axios实例拦截请求
axiosInstance.interceptors.request.use(
(config: AxiosRequestConfig) => {
// 配置headers
config.headers = {
...config.headers,
};
return config;
},
(error: any) => {
return Promise.reject(error);
}
); // axios实例拦截响应
axiosInstance.interceptors.response.use(
// 请求成功
(response: AxiosResponse) => {
return response;
},
// 请求失败
(error: AxiosError) => {
const { response } = error;
console.error(response, "response error");
if (response) {
return Promise.reject(response.data);
}
}
); const request = <T = any>(config: AxiosRequestConfig): Promise<T> => {
const conf = config;
return new Promise((resolve) => {
axiosInstance
.request<any, AxiosResponse<IResponse>>(conf)
.then((res: AxiosResponse<IResponse>) => {
const {
data: { result },
} = res;
resolve(result as T);
});
});
}; export function get<T = any>(config: AxiosRequestConfig): Promise<T> {
return request({ ...config, method: "GET" });
} export function post<T = any>(config: AxiosRequestConfig): Promise<T> {
return request({ ...config, method: "POST" });
} export default request;
export type { AxiosInstance, AxiosResponse };
// utils/http/axios/type.ts export interface RequestOptions {
// Whether to process the request result
isTransformResponse?: boolean;
} // 返回res.data的interface
export interface IResponse<T = any> {
code: number | string;
result: T;
data: T;
message: string;
status: string | number;
}
根目录创建.env.development配置开发请求地址
// .env.development # 开发环境 VITE_APP_API_BASEURL = 你的请求地址 NODE_ENV = development
vite.config.ts配置server
// vite.config.ts server: {
hmr: { overlay: false }, // 禁用或配置 HMR 连接 设置 server.hmr.overlay 为 false 可以禁用服务器错误遮罩层
// 服务配置
port: 3030, // 类型: number 指定服务器端口;
open: false, // 类型: boolean | string在服务器启动时自动在浏览器中打开应用程序;
cors: false, // 类型: boolean | CorsOptions 为开发服务器配置 CORS。默认启用并允许任何源
host: "0.0.0.0", // IP配置,支持从IP启动
["/api"]: {
target: process.env.VITE_APP_API_BASEURL,
changeOrigin: true,
rewrite: (path: string) => path.replace(new RegExp("^/api"), ""),
},
},
创建api存放目录
创建一个api
// api/test/index.ts import { post } from "@/utils/http/axios";
import { IResponse } from "@/utils/http/axios/type"; export interface LoginData {
username?: string;
password?: string;
} enum URL {
login = "/api/user_center/testLogin",
} /**
* @description: 用户登录
* @params {LoginData} params
* @return {Promise}
*/ const login = async (data: LoginData) =>
post<IResponse>({ url: URL.login, data }); export { login };
回到test/index.vue调用api测试axios
// test/index.vue <script setup lang="ts">
import { login } from '@/api/test' login({})
</script>
回到页面,查看network
接口请求成功,axios配置成功!
最后,配置一下打包
// vite.config.ts import { UserConfig, ConfigEnv, loadEnv } from "vite"; // https://vitejs.dev/config/
export default ({ command, mode }: ConfigEnv): UserConfig => {
const env = loadEnv(mode, __dirname);
return {
base: env.NODE_ENV === "development" ? "/" : "./",
build: {
outDir: "dist",
assetsDir: "assets", //指定静态资源存放路径
sourcemap: false, //是否构建source map 文件
},
};
};
结语:
项目到此主体功能就已经配置完毕了,细节之处大家多多查看官网和众多网页的分享
项目还有很多不完善甚至错误的地方,踩坑还会继续,后续有时间还会继续优化,实际使用中还有很多地方需要改进
项目同步git:https://gitee.com/lixin_ajax/vue3-vite-ts-pinia-vant-less.git
手把手,完整的从0搭建vite-vue3-ts项目框架:配置less+svg+pinia+vant+axios的更多相关文章
- vite创建vue3+ts项目流程
vite+vue3+typescript搭建项目过程 vite和vue3.0都出来一段时间了,尝试一下搭vite+vue3+ts的项目 相关资料网址 vue3.0官网:https://v3.vue ...
- vue3.0+vite+ts项目搭建--vite.config.ts配置(三)
vite.config.ts配置 配置路径处理模块 安装ts的类型声明文件 yarn add @types/node -D 通过配置alias来定义路径的别名 resolve: { alias: { ...
- 从零开始搭建Electron+Vue+Webpack项目框架,一套代码,同时构建客户端、web端(一)
摘要:随着前端技术的飞速发展,越来越多的技术领域开始被前端工程师踏足.从NodeJs问世至今,各种前端工具脚手架.服务端框架层出不穷,“全栈工程师”对于前端开发者来说,再也不只是说说而已.在NodeJ ...
- 【原创】从零开始搭建Electron+Vue+Webpack项目框架,一套代码,同时构建客户端、web端(二)
摘要:上篇文章说到了如何新建工程,并启动一个最简单的Electron应用.“跑起来”了Electron,那就接着把Vue“跑起来”吧.有一点需要说明的是,webpack是贯穿这个系列始终的,我也是本着 ...
- 【原创】从零开始搭建Electron+Vue+Webpack项目框架(六)Electron打包,同时构建客户端和web端
导航: (一)Electron跑起来(二)从零搭建Vue全家桶+webpack项目框架(三)Electron+Vue+Webpack,联合调试整个项目(四)Electron配置润色(五)预加载及自动更 ...
- 【原创】从零开始搭建Electron+Vue+Webpack项目框架(五)预加载和Electron自动更新
导航: (一)Electron跑起来(二)从零搭建Vue全家桶+webpack项目框架(三)Electron+Vue+Webpack,联合调试整个项目(四)Electron配置润色(五)预加载及自动更 ...
- 从0搭建vue后台管理项目到颈椎病康复指南(一)
网上搜索了很久Vue项目搭建指南,并没有找到写的比较符合心意的,所以打算自己撸一个指南,集合众家之所长(不善于排版,有点逼死强迫症,如果觉得写的有问题,可以留言斧正,觉得写的太差的,可以留言哪里差, ...
- vue-cli+webpack搭建简单的vue项目框架
0.先去官网下载安装nodeJS 1.在cmd中输入命令 node -version 若出现node版本号 则安装成功 2.通过命令:cd 文件夹名 进入某具体文件夹后进行如下命令操作: ...
- struts 2.3.28+spring 4.2.5.RELEASE+hibernate 5.1.0.Final整合maven构建项目基本配置
第一次写博客,主要也是记录给自己看的,可能很多比较熟的地方就没注释 用maven构建,ssh框架都是选用的最新的release版(感觉还是不要用beta),环境jdk1.8 tomcat8.0 mys ...
- Flutter学习三之搭建一个简单的项目框架
上一篇文章介绍了Dart的语法的基本使用,从这篇文章开始,开发一个基于玩Android网站的app.使用的他们开放的api来获取网站数据. 根据网站的结构,我们app最外层框架需要添加一个底部导航栏, ...
随机推荐
- 使用【阿里云】服务器、【Xshell】搭建自己的【网站】—— { }
重置实例密码 打开Xshell连接主机 Apache 服务 安装 yum install httpd* -y 操作 启动 systemctl start httpd.service 查看状态 syst ...
- 弱隔离级别 & 事务并发问题
介绍弱隔离级别 为什么要有弱隔离级别 如果两个事务操作的是不同的数据, 即不存在数据依赖关系, 则它们可以安全地并行执行.但是当出现某个事务修改数据而另一个事务同时要读取该数据, 或者两个事务同时修改 ...
- 使用Steamwork.Net 接入Steam一点心得
1. 前言 这是我在开发过程中使用的一点总结,目前使用的东西包含基础登录功能,存档功能,成就系统,以及DLC安装功能.Steamwork不仅仅有这些功能还有游戏内交易,排行榜,数据传输等功能,这些功 ...
- sklearn中MLPClassifier源码解析
神经网络 .fit() 首先传入类私用方法._fit() 确定hidden_layer_size是可迭代的 调用_validate_hyperparameters验证超参数是否合法 验证输入的x和y是 ...
- java项目中VO、DTO以及Entity,各自是在什么情况下应用的
按照标准来说: entity里的每一个字段,与数据库相对应 vo里的每一个字段,是和你前台页面相对应 dto,这是用来转换从entity到dto,或者从dto到entity的中间的东西 举个例子: h ...
- Elasticsearch: Ngrams, edge ngrams, and shingles
Ngrams和edge ngrams是在Elasticsearch中标记文本的两种更独特的方式. Ngrams是一种将一个标记分成一个单词的每个部分的多个子字符的方法. ngram和edge ngra ...
- MySQL集群搭建(5)-MHA高可用架构
1 概述 1.1 MHA 简介 MHA - Master High Availability 是由 Perl 实现的一款高可用程序,出现故障时,MHA 以最小的停机时间(通常10-30秒)执行 mas ...
- java设计模式之七大原则
java设计模式 以下内容为本人的学习笔记,如需要转载,请声明原文链接 https://www.cnblogs.com/lyh1024/p/16724932.html 设计模式 1.设计模式的目的 ...
- 谣言检测——(PSA)《Probing Spurious Correlations in Popular Event-Based Rumor Detection Benchmarks》
论文信息 论文标题:Probing Spurious Correlations in Popular Event-Based Rumor Detection Benchmarks论文作者:Jiayin ...
- PAT (Basic Level) Practice 1007 素数对猜想 分数 20
让我们定义dn为:dn=pn+1−pn,其中pi是第i个素数.显然有d1=1,且对于n>1有dn是偶数."素数对猜想"认为"存在无穷多对相邻且差为2的 ...