前言:vue3+ts+vite大家已经都开始用了,最近也在学习,基本上是零基础开始ts的学习,很多语法知识是边写边查,没有系统的学习ts。此处展示从零开始,搭建的一个框架,方便拿来即用!
1. 初始化一个vite项目
npm create vite@latest
复制
其中框架选择vue,语言选择typeScript
2. 启动项目
npm install npm run dev
复制
项目启动成功以后如下所示:
3. 修改目录
为了方便日常工作中的框架使用,在此处对刚初始化好的框架进行改造,在原有框架的基础上,添加store,router,layout,utils,views等文件夹,其中的作用将在后面进行说明。如图所示:
4. 配置router
首先安装vue-router的依赖
npm install vue-router
复制
在router文件夹下创建index.ts文件,配置如下:
import { createRouter, createWebHashHistory, RouteRecordRaw } from 'vue-router'; const routes: Array<RouteRecordRaw> = [ // 项目打开后进入的默认地址 { path: '/', redirect: '/login' }, { path: '/login', component: () => import('../views/login/login.vue') }, { path: '/home', component: () => import('../views/home/home.vue') } ] const router = createRouter({ history: createWebHashHistory(), // 本项目采用了哈希模式 routes }) export default router
复制
路由文件配置以后,需要在main.ts文件中进行引用,如下所示:
import { createApp } from 'vue' import './style.css' import App from './App.vue' const app = createApp(App) // 路由设置 import router from './router/index' app.use(router) app.mount('#app')
复制
修改app.vue文件,根据实际情况进行修改,本项目中不需要初始化的helloWord组件,所以修改如下所示:
<script setup lang="ts"> </script> <template> <div> <router-view></router-view> </div> </template> <style scoped> </style>
复制
在views文件夹中创建login.vue文件,并重新启动项目,如图所示,跳转到登陆页面后表示路由配置成功:
vue文件中使用路由的方法如下:
import { useRouter, useRoute} from 'vue-router' const router = useRouter() const route = useRoute() // 路由跳转 router.push('/xxx')
复制
**补充:**路由hash模式与history模式的区别
- hash模式
示例:http://localhost:5173/#/login
原理:利用window监听的onhashchange事件,不会包含在http请求中,对后端完全没有影响。 - history模式
示例:http://localhost:5173/login
原理:地址发生改变后,会按照改变后的地址向服务端发送请求,需要后端配合处理,做地址映射。
5.配置vuex(pinia)
pinia 是一个拥有组合式API的状态管理库。
pinia官网: https://pinia.vuejs.org/zh/introduction.html
首先安装pinia的依赖
npm install pinia
复制
在store文件夹中创建index.ts,具体内容如下:
import type {App} from 'vue' import { createPinia } from "pinia"; const store = createPinia() export function setupStore(app:App<Element>) { app.use(store) } export {store}
复制
然后在store文件夹中创建modules文件夹,并创建user.ts 文件,用来保存用户的基本信息。
import { defineStore } from 'pinia' import { store } from '../index' interface userInfoType { username: string, age: number, gender: string } export const useUserStore = defineStore('user', () => { // 此处使用的是组合式API的方式,更多情况可查看官网 let userInfo: userInfoType = { username: '小明', age: 18, gender: '男' } return { userInfo } }, ) // 最后到处定义的useUserStore export function useUserStoreHook() { return useUserStore(store) }
复制
store的基本信息配置好以后,需要在main.ts问价中挂载到app组件上,如下:
import { setupStore } from './store' // 挂载store setupStore(app);
复制
存储在vuex中的数据使用方式如下:
// login.vue 文件 <script setup lang="ts"> import { useUserStore } from '../../store/modules/user' const userStore = useUserStore() let userInfo = userStore.userInfo </script> <template> <div class="login-wrap"> <p>登录页面</p> {{ userInfo.username }}的年龄是{{ userInfo.age }} </div> </template> <style scoped> .login-wrap { width: 100%; height: 100vh; background-size: 100% 100%; position: relative; box-sizing: border-box; } </style>
复制
效果如下:
6. element-plus 的基本使用
首先安装依赖
npm install element-plus
复制
官网: https://element-plus.org/zh-CN/guide/design.html
本项目中使用的是方法是在main.ts文件中完整导入!main.ts文件如下:
// element-plus import ElementPlus from 'element-plus' import 'element-plus/dist/index.css' // 导入所有的icon图标 import * as ElementPlusIconsVue from '@element-plus/icons-vue' app.use(ElementPlus) for (const [key, component] of Object.entries(ElementPlusIconsVue)) { app.component(key, component) }
复制
在vue文件中基本使用方法:
import { ElMessage } from 'element-plus' ElMessage('你好')
复制
7. axios封装
对于前后分离的项目来说,绑定后端提供的接口进行数据增删改查是业务中较为重要的部分,此处对axios的使用进行封装,方便向服务断发送请求。
依旧是安装axios的依赖:
npm install axios
复制
axios的接口封装文件如下:
import axios from 'axios'; import type { AxiosInstance, AxiosRequestConfig, AxiosResponse, AxiosError } from 'axios' import {getCookie,setCookie} from '../../utils/cookie' const service: AxiosInstance = axios.create({ baseURL: import.meta.env.VITE_APP_API_BASEURL, timeout: 15000, headers: { 'Content-Type': 'application/json' }, }); interface requestConfig extends AxiosRequestConfig { headers?: any } // axios实例拦截请求 service.interceptors.request.use( (config: requestConfig) => { const token = getCookie('token'); if (token) { config.headers.token = token } return config; }, (error: AxiosError) => { return Promise.reject(error); }, ); // axios实例拦截响应 service.interceptors.response.use( (response: AxiosResponse) => { if (response.status === 200) { return response; } return response; }, // 请求失败 (error: any) => { const { response } = error; if (response) { // 请求已发出,但是不在2xx的范围 return Promise.reject(response.data); } }, ); /*** * post 方法封装 */ export function postMethod<T>(url:string,params?:any):Promise<T> { return new Promise((resolve, reject) => { service.post(url,params).then((res:any) => { if(res.data.code === 200 && res.headers['token']) { setCookie('token',res.headers['token'],21600) } resolve(res.data) }).catch((err) => { reject(err) }) }) } /*** * get 方法封装 */ export function getMethod<T>(url:string,params?:any):Promise<T> { return new Promise((resolve, reject) => { service.get(url,params).then((res:any) => { if(res.data.code === 200 && res.headers['token']) { setCookie('token',res.headers['token'],21600) } resolve(res.data) }).catch((err) => { reject(err) }) }) } /** * 文件上传 方法封装 * 上传文件传参方式注意为form-data格式 */ export function uploadFile<T>(url:string,uploadForm:any):Promise<T>{ const fd = new FormData() fd.append('fileName', uploadForm.projectId) fd.append('file', uploadForm.file) return new Promise((resolve, reject) => { service.post(url,fd,{ headers: { 'Content-Type': 'multipart/form-data' } }).then((res:any) => { if(res.data.code === 200 && res.headers['token']) { setCookie('token',res.headers['token'],21600) } resolve(res.data) }).catch((err) => { reject(err) }) }) }
复制
8. cookie封装
用户登录的时候,提交表单信息,需要对接口返回的token进行存储,此处使用了cookie进行存储,可以利用js-cookie库进行cookie存储,也可自己封装方法,此处是封装cookie的方法进行cookie的存储,获取,以及清除,如下所示:
// cookie.ts /** * cookie 浏览器缓存 */ const domain = '' // 时间单位为秒 export function setCookie(c_name: string, value: any, expire?: any) { var date: any = new Date() date.setSeconds(date.getSeconds() + expire) document.cookie = c_name + '=' + escape(value) + '; expires=' + date.toGMTString() + '; domain=' + domain + ';path=/' } export function getCookie(c_name: string) { let c_start: number let c_end: number if (document.cookie.length > 0) { c_start = document.cookie.indexOf(c_name + '=') if (c_start != -1) { c_start = c_start + c_name.length + 1 c_end = document.cookie.indexOf(';', c_start) if (c_end == -1) c_end = document.cookie.length return unescape(document.cookie.substring(c_start, c_end)) } } return '' } export function delCookie(c_name:string) { setCookie(c_name, '', -1) }
复制
9. localStorage 使用
在获取localStorage存储信息时,发现存在一个问题,在vue文件中的setup的语法糖中,直接使用JSON的序列化方法会标红,可以正常使用,但是存在类型问题。将其进行封装后,发现这个问题不在出现,在vue文件中使用时,直接引入即可。如下所示:
// localStorage.ts /** * window.localStorage 浏览器永久缓存 */ export const localStorage = { // 设置永久缓存 set(key: string, val: any) { window.localStorage.setItem(key, JSON.stringify(val)); }, // 获取永久缓存 get(key: string) { const json: any = window.localStorage.getItem(key); return JSON.parse(json); }, // 移除永久缓存 remove(key: string) { window.localStorage.removeItem(key); }, // 移除全部永久缓存 clear() { window.localStorage.clear(); } };
复制
10. 框架地址
gitee地址: https://gitee.com/free_project/vue3_ts_frame.git
目前只有一个空架子,针对表单的使用等还未进行展示;因为对ts不熟,好多类型都设置了any。若有问题还请指出!