最近vite更新频繁,现版本最高vite2,确实更高更快更强,可惜,run build报错,尝试了一下vue3框架的各种搭建模式,现总结以下适合移动端的vue3+ts+vant搭建方式,避免后续走弯路
创建vue3+ts项目
基础node环境搭建这里不做详述
vue脚手架搭建(这里不选择用vite,因为不稳定,等待尤大后续更新出稳定版本)
npm install -g @vue/cli
创建vue3+ts项目
vue create vue3-project
创建项目时注意勾选自己需要的各种选项
引入ui样式框架,这里选择vant
安装vant
# Vue 3 项目,安装 Vant 3:
npm i vant@next -S
vant 官网:在 Vite 中如何按需引入组件? 在 Vite 中无须考虑按需引入的问题。Vite 在构建代码时,会自动通过 Tree Shaking 移除未使用的 ESM 模块。而 Vant 3.0 内部所有模块都是基于 ESM 编写的,天然具备按需引入的能力。 现阶段遗留的问题是,未使用的组件样式无法被 Tree Shaking 识别并移除,后续我们会考虑通过 Vite 插件的方式进行支持
main.ts使用
import { createApp } from 'vue'
import App from './App.vue'
import Vant from 'vant'
import 'vant/lib/index.css';
createApp(App).use(Vant).mount('#app')
项目运行
npm run dev
测试vant是否引入成功(查看组件样式是否正确显示即可)
创建TestDemo.vue组件并引用
使用van-cell-group组件
<van-cell-group>
<van-cell title="单元格" value="内容"></van-cell>
<van-cell title="单元格" value="内容"></van-cell>
</van-cell-group>
注释掉App.vue中的基础样式
项目编译
run build
测试项目打包结果
使用nodejs的http-server模块直接在dist文件中启用建议服务检测 进入dist根目录
http-server
简易封装axios
src文件加下新建services文件夹 新建两个子文件url.ts和request.ts
url.ts
export default{
baseUrl:'http://www.test.com',
login:'/login/normal'
}
request.ts
import axios, { AxiosInstance, AxiosResponse } from "axios";
import url from "@/services/url";
axios.defaults.timeout = 60000; // 设置全局请求超时时间
axios.defaults.baseURL = url.baseUrl // 设置全局请求基地址
export default class Request {
private spinningAxios = axios.create(); // 建立请求时会产生全局Loading的axios实例
private noSpinningAxios = axios.create(); // 建立请求时不会产生全局Loading的axios实例
constructor() {
this.addInterceptors(this.spinningAxios, true);
this.addInterceptors(this.noSpinningAxios, false);
}
private addInterceptors(requestMain: AxiosInstance, loading: boolean): void {
requestMain.interceptors.request.use(options => {
// 对全局请求的options进行更改,例如增加动态头部信息等
if (loading) {
// 自定义全局Loading的产生方式,在项目开发中建议在全局写一个工具类 例如 xxxx.showLoading()
}
return options;
}, error => {
// 错误捕捉 此时的错误为最外层status的错误
return Request.outError(error, loading)
})
requestMain.interceptors.response.use(response => {
// 处理全局请求的返回response,例如对返回值进行判断
return Request.disposeResponse(response, loading)
}, error => {
// 错误捕捉 此时的错误为最外层status的错误
return Request.outError(error, loading)
})
}
private static outError(error: any, loading: boolean): Promise<string> {
if (loading) {
// 自定义全局Loading的关闭方式,在项目开发中建议在全局写一个工具类 例如 xxxx.hideLoading()
}
const { response = {} } = error;
return Promise.reject(response.statusText || (error && error.toString()) || "未知错误");
}
private static disposeResponse(response: AxiosResponse, loading: boolean): AxiosResponse | Promise<any> {
if (loading) {
// 自定义全局Loading的关闭方式,在项目开发中建议在全局写一个工具类 例如 xxxx.hideLoading()
}
// 对接口返回的数据进行判断,例如接口中 code 的值 200为成功,500为失败,401为未登录时进行各个操作,此处可以使用枚举
const { data } = response;
switch (data.code) {
// case insideStatus.success: // 200
// return response;
// case insideStatus.error: // 500
// return Promise.reject(data.msg);
// case insideStatus.noLogin: // 401
// this.utils.toLogin();
// return Promise.reject(data.msg);
// default:
// return Promise.reject(data.msg);
default: return response; //示例数据,请自行剔除
}
}
public async post<T, S>(url: string, data: T): Promise<S | string> {
return this.spinningAxios.post(url, data, {
// 添加例如 headers 之类的属性
}).then(res => Promise.resolve(res.data)).catch(err => Promise.reject(err.toString()))
}
public async get<T, S>(url: string, data: T): Promise<S | string> {
return this.spinningAxios.get(url, {
params: data,
// 添加例如 headers 之类的属性
}).then(res => Promise.resolve(res.data)).catch(err => Promise.reject(err.toString()))
}
public async postNoLoading<T, S>(url: string, data: T): Promise<S | string> {
return this.noSpinningAxios.post(url, data, {
// 添加例如 headers 之类的属性
}).then(res => Promise.resolve(res.data)).catch(err => Promise.reject(err.toString()))
}
public async getNoLoading<T, S>(url: string, data: T): Promise<S | string> {
return this.noSpinningAxios.get(url, {
params: data,
// 添加例如 headers 之类的属性
}).then(res => Promise.resolve(res.data)).catch(err => Promise.reject(err.toString()))
}
}
request使用
src文件夹下新建api文件夹 新建text.ts文件
import Request from '@/services/request';
export default class Methods {
private request = new Request();
public async login<T, S>(data: T): Promise<S | string> {
return this.request.post('12312321', data)
}
}
页面中使用
import Methods from '@/api/test'
setup: () => {
onMounted(() => {
const http = new Methods()
http
.login({
userPhone: '123456789',
userPassword: '123456789',
})
.then((res) => {
//成功回调
console.log(res)
})
.catch((err) => {
//失败回调
console.log(err)
})
})
},
vuex的使用
vue3新建项目时代码中自带store文件
这里模块化处理 store文件夹下新建module文件夹 module下新建test.ts
const test = {
state: {
total: 10
},
mutations: {
totleFun(state: any, value: number): void {
state.total = value
}
},
actions: {
totleFunAdd(context: any, value: number) {
context.commit('totleFun', value + 1)
},
totleFunDel(context: any, value: number) {
context.commit('totleFun', value - 1)
}
}
}
export default test
相应的index.js中引用
import { createStore } from 'vuex'
import test from './module/test'
export default createStore({
state: {
},
mutations: {
},
actions: {
},
modules: {
test
}
})
页面中访问
//引入
import {useStore } from 'vuex'
//使用
useStore().state.test.total