vue3+vite+TypeScript+vant项目搭建
序言
今天又接了个移动端项目,在搭建项目的过程中仍然磕磕绊绊。想想移动端项目这也算是第三个了,参考了这么多大佬的博客,仍然是这个水平,顿感羞愧。痛定思痛,决定把搭建过程详细记录下来,以便后续参考,交流学习。
链接
以下是我参考的文章链接,大佬们的文章像是黑夜里的明灯,指引着我从小小白走到小白,万分感谢。
说了这么多,让我们进入正题!
搭建一个vue+TypeScript项目
打开工作目录
1.打开终端,输入命令
npm init vite@latest
2.回车执行命令,你会得到下边的界面,随你喜好给项目取个名字
3.选择vue框架
4. 选择TypeScript
5.等它执行完毕,打开创建的项目文件夹,看到的目录结构是这样滴
6.别心急哦,再次打开终端,先npm i安装依赖,然后npm run dev运行项目,看到这样的界面就算是成功搭建了一个vue3+ts+vite项目了。
引入sass
vite有内置的sass配置信息,所以直接安装sass即可!(要像大佬一样精准冷酷的说话!!!),终端输入代码npm install --save-dev sass,全局搜索可以看到有以下依赖。
接下来就可以愉快的用sass写样式了
引入vant
按以下命令复制执行即可
# Vue 3 项目,安装最新版 Vant
npm i vant
# Vue 2 项目,安装 Vant 2
npm i vant@latest-v2
移动端适配
适配总是移动端项目绕不开的话题,这里使用的是rem适配方案。在这里介绍两个插件。
postcss-pxtorem插件
用来将px转换成rem适配(意思就是你只需要填写对应的px值,就可以在页面上自动适配,不需要自己手动转rem。但笔者项目实测,好像只有.vue文件写在style里的px会被转化成rem,行内式和外链式样式不会被转化,大家也可以试一下。)。
npm install postcss-pxtorem
不需要创建什么postcss.config.ts文件,感谢大佬的文章让我避坑。vite中是自带了这种写法,所以只需要直接在vite.config.ts中填写相关配置就可以了。
amfe-flexible插件
npm i -S amfe-flexible
下载完两个插件后一定要记得在main.ts文件中import amfe-flexible
import App from './App.vue'
//不要忘记import
import "amfe-flexible";
const app = createApp(App)
app.use(router).mount('#app')
以下是vite.config.ts文件中的配置代码
//vite.base.config.js
import { defineConfig } from 'vite';
import vue from '@vitejs/plugin-vue';
import Components from 'unplugin-vue-components/vite';
//vant组件自动注册
import { VantResolver } from 'unplugin-vue-components/resolvers';
import postcssImport from "postcss-pxtorem"
export default defineConfig({
base: './', // 设置打包路径
//vant组件自动注册
plugins: [
vue(),
Components({
resolvers: [VantResolver()],
})
],
resolve: {
alias: [
{
find: '@',
replacement: `/src`,
},
{
find: '@api',
replacement: `/src/api`,
}
]
},
server: {
host: '0.0.0.0',
port: 4000, // 设置服务启动端口号
open: true, // 设置服务启动时是否自动打开浏览器
cors: true, // 允许跨域
// 设置后台请求代理,根据我们项目实际情况配置
proxy: {
'/api': {
target: '',
changeOrigin: true,
secure: false,
rewrite: (path) => path.replace('/api/', '/')
}
}
},
//适配
css: {
postcss: {
plugins: [
postcssImport({
// 这里的rootValue就是你的设计稿大小
rootValue: 37.5,
propList: ['*'],
})
]
}
}
})
做完以上,你的移动端页面就可以适配绝大部分机型了。
vant组件自动注册
在使用组件的时候,如果用到一个引入一个,这是非常不方便的。vant提供了一种非常便捷的自动注册方法,在基于 vite、webpack 或 vue-cli 的项目中使用 Vant 时,可以使用 unplugin-vue-components 插件,它可以自动引入组件,并按需引入组件的样式。官网有详细的介绍,这里我也简单记录一下。
# 通过 npm 安装
npm i unplugin-vue-components -D
# 通过 yarn 安装
yarn add unplugin-vue-components -D
# 通过 pnpm 安装
pnpm add unplugin-vue-components -D
插件安装结束后,在vite.config.ts编写相应的配置代码,具体见上方适配代码,有一起贴出来。
安装router4
这个时候我们可以愉快的编写页面了,路由配置是必不可少的。
npm install vue-router
创建一个router文件夹,在router文件夹下新建一个index.ts文件。创建路由代码如下:
import {
createRouter,
createWebHashHistory,
RouteRecordRaw,
} from 'vue-router';
const routes: Array<RouteRecordRaw> = [
//工资详情界面
{
path: '/salary/detail', component: () => import('@/views/home/salary/SalaryDetail.vue'),
},
];
const router = createRouter({
history: createWebHashHistory(),
routes,
});
//全局前置路由守卫
// router.beforeEach((to, from, next) => {
// if (to.path == '/login') {
// next()
// } else {
// if (window.sessionStorage.getItem('sid') || to.query.sid) {
// next()
// } else {
// next('/login')
// }
// }
// })
export default router;
同样别忘了在main.ts文件中import router对象
import { createApp } from 'vue'
import router from './router';
import "amfe-flexible";
import App from './App.vue'
const app = createApp(App)
app.use(router).mount('#app')
安装axios
愉快的写完静态界面,这个时候我们要和后端的同学对接口了,这个时候要安装axios
npm install axios
pnpm install axios
在这里写下我的封装方式,仅供参考。
我习惯于将axios二次封装后,声明成一个全局方法,所以先创建一个api.d.ts的声明文件。
interface Api {
post(url: string, data?: any, config?: any): Promise<any>;
get(url: string, config?: any): Promise<any>;
put(url: string, data?: any, config?: any): Promise<any>;
delete(url: string, config?: any): Promise<any>;
patch(url: string, data?: any, config?: any): Promise<any>;
postForm(url: string, data?: any, config?: any): Promise<any>;
putForm(url: string, data?: any, config?: any): Promise<any>;
patchForm(url: string, data?: any, config?: any): Promise<any>;
}
declare const App: {
api: Api
}
这里声明一个全局的App对象,然后创建axios文件夹,文件夹结构如下图
//RequestInterceptor.ts
import { AxiosRequestConfig, AxiosError } from 'axios';
const request = (config: AxiosRequestConfig<any>) => {
// 在发送之前的配置
return config
}
const requestError = (error: AxiosError) => {
// 对请求错误的处理
return error
}
export {
request,
requestError
}
//ResponseInterceptor.ts
import { AxiosResponse, AxiosError } from 'axios';
const response = (response: AxiosResponse<any, any>) => {
// 对请求结果的处理
if (response.status === 200) {
return response.data
}
}
const responseError = async (error: AxiosError) => {
//对响应错误的处理
const code = error.response?.status;
switch (code) {
case 401:
// console.log('未授权');
break;
case 403:
// console.log('您没有访问权限');
break;
case 404:
break;
case 500:
break;
case 502:
break;
case 503:
break
}
return error
}
export {
response,
responseError
}
//index.ts
import axios from 'axios';
import { request, requestError } from './Interceptor/RequestInterceptor';
import { response, responseError } from './Interceptor/ResponseInterceptor';
axios.defaults.withCredentials = true
const _axios = axios.create({
baseURL: '/api/',
headers: {
'Content-Type': 'application/json;charset=UTF-8;',
},
timeout: 100000
})
//请求拦截器
_axios.interceptors.request.use(request, requestError);
//响应拦截器
_axios.interceptors.response.use(response, responseError);
export default () => {
if (!App.api) {
Object.defineProperty(App, 'api', {
value: {
post(url: string, data?: any, config?: any) {
return _axios.post(url, data, config);
},
get(url: string, config?: any) {
return _axios.get(url, config);
},
put(url: string, data?: any, config?: any) {
return _axios.put(url, data, config);
},
delete(url: string, config?: any) {
return _axios.delete(url, config);
},
patch(url: string, data?: any, config?: any) {
return _axios.patch(url, data, config);
},
postForm(url: string, data?: any, config?: any) {
return _axios.postForm(url, data, config);
},
putForm(url: string, data?: any, config?: any) {
return _axios.putForm(url, data, config);
},
patchForm(url: string, data?: any, config?: any) {
return _axios.patchForm(url, data, config);
},
},
writable: false,
enumerable: true
})
}
}
同样别忘了import
import { createApp } from 'vue'
import router from './router';
import App from './App.vue';
import "amfe-flexible";
import axios from '@/axios'
const app = createApp(App)
app.use(router,axios).mount('#app')
创建一个test.ts文件,能够.出来全局Axios方法就算是封装成功了,
tip:补充一下,全局方法的封装逻辑,是如果找不到App对象中的api方法,则通Object.defineProperty方法定义App的api属性,将请求方法封装到App对象,发散一下,这可以实现很多不同类公共方法的封装。所以需要声明一个App对象,否则会报错。声明也很简单,在index.html文件里var一个App对象就好了,如下:
配置映射路径
目录层级深了,引用不方便。这个时候就需要配置路径映射了。配置路径映射也很简单,我们只需要在vite.config.ts文件中添加配置就好。代码如下:
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
export default defineConfig({
plugins: [vue()],
resolve: {
//路径映射
alias: [
{
find: '@',
replacement: `/src`,
},
{
find: '@api',
replacement: `/src/api`,
}
]
},
})
推测如果是js,到这一步应该就可以了,但要通过Ts编译的话,还需要在tsconfig.json中添加配置,否则会报红。配置如下:
{
/*其他配置省略*/
"compilerOptions": {
//路径映射配置
"paths": {
"@/*": [
"./src/*"
]
}
}
}
这样写可以避免长串的../../../,使得路径导入变得简洁而优雅。使用方法如下:
结束
再次感谢各位大佬对我的帮助!!!