- 可能文章会有点长,我每个测试都带有截图,耐心看完,一定会有所收获的!
1. npm创建项目
创建
npm create vite news-html --template vue-ts
- 之后会让你选择,选择vue,ts即可。
- 好了之后会有提示的,进入项目主目录,然后npm安装一下依赖,安装成功npm run dev把项目跑起来即可
测试
到这个时候,基本的项目架子已经是好了,那肯定还没有完,我们再添加点东西,让它变得更加健壮、完美。
集成sass
- 说到sass,肯定有很多小伙伴头疼,因为安装node-sass过程中经常报错,我们现在直接用drat-sass,就不会有些这问题了,这也是sass现在主推的
就是想要安装
node-sass的小伙伴也不要慌,我之前文章好像有写。注意:报错基本都是出在node版本不对应上。再说一句:还是建议用drat-sass,方便快捷
安装
npm install --save-dev sass
测试
集成vue-router
安装
- npm install vue-router@4
安装成功,来看一下package.json
使用
- 在src下面建立一个router目录,里面存放有关路由的文件,同时建立两个目录写两个文件,方便后面测试路由是否挂载成功。(我这里页面统一放在view目录下)
router/index.ts
view/home/index.vue
- 注意:App.vue页面我们需要放置一个 路由占位符,路由会被渲染在此位置。
- 最后,我们在main.ts挂载一下。不幸的是 碰见问题了,克服困难。解决了就有成长。
导致这个问题的原因就是使用了
ts,没有配置 导致找不到对应的声明,我们在配置一下tsconfig.json(创建出来的ts项目根目录下有这个文件的)
{
"compilerOptions": {
"target": "ES2020",
"useDefineForClassFields": true,
"module": "ESNext",
"lib": [
"ES2020",
"DOM",
"DOM.Iterable"
],
"skipLibCheck": true,
"baseUrl": "./",
"paths": {
"@/*": [
"src/*"
]
},
/* Bundler mode */
"moduleResolution": "Node",
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true,
"jsx": "preserve",
/* Linting */
"strict": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noFallthroughCasesInSwitch": true,
},
"include": [
"src/**/*.ts",
"src/**/*.d.ts",
"src/**/*.tsx",
"src/**/*.vue"
],
"exclude": [
"node_modules"
],
"references": [
{
"path": "./tsconfig.node.json"
}
]
}
- 以上配置主要是
paths那一块配置解决这个问题,这样ts就可以找到识别到文件了 - 配置成功,不爆红线了,但是控制台又报错了。。确实搞人心态了,继续排查
- 又是找不到文件,我鼠标左键其实都可以点过去的,我们在vite.config.ts里面配置一下别名
成功,也不报错了。
测试
注意:有些小伙伴跟着我
vite.config.ts里面path肯定会找不到的,这是因为path是node里面的东西,我们需要安装@types/node,才可以识别到path
- npm install -D @types/node
集成Ant Design Vue组件库
- 我也是第一次用哈哈(之前都是用的element,想尝试一下这个框架,听说也很不错)
安装
- npm install ant-design-vue@4.x --save 先安装这个组件库
- npm install unplugin-vue-components -D 自动按需引入组件
vite.config.ts配置
- 加入我框住的代码
测试
集成axios
安装
- npm install axios
二次封装axios
- 创建utils目录,在utils目录下创建request.ts文件
- 其余的根据自己公司业务在这基础上添加逻辑代码即可。
import axios from 'axios'
import type {AxiosError, AxiosInstance, AxiosResponse, InternalAxiosRequestConfig} from "axios"
import {message as Message} from 'ant-design-vue';
// 自定义axios示例
const instance: AxiosInstance = axios.create({
baseURL: 'http://localhost:8080/news_server', // 接口前缀地址
timeout: 1000 * 10, // 接口超时时间 10秒
});
// 添加请求拦截器
instance.interceptors.request.use((config: InternalAxiosRequestConfig) => {
return config;
}, (error: AxiosError) => {
return Promise.reject(error);
});
// 添加响应拦截器
instance.interceptors.response.use((response: AxiosResponse) => {
const {code, data, message} = response.data;
if (code === 200) {
return data;
}
Message.error(message)
return Promise.reject(new Error(message))
}, (error: AxiosError) => {
let message = ""
const status = error.response?.status;
switch (status) {
case 401:
message = "token失效,请重新登录"
// 这里写退出登录逻辑
break
case 404:
message = "请求地址错误"
break
case 500:
message = "服务器繁忙"
break
default:
message = "网络链接故障"
}
Message.error(message)
return Promise.reject(error);
});
export default instance;
- 我们在创建一个api目录,管理我们的api,不同的api放到对应的目录下,再通过一个index.ts统一管理。
可以看到我这边也写了一个test 测试的方法调用接口获取数据,我们来看看封装的axios到底有没有成功呢
测试
引入unplugin-auto-import
- 每个文件都存在import {onMounted} from "vue" 等代码,想想也挺繁琐的,用这个插件,解放双手,自动引入。
安装
- npm install unplugin-auto-import -D
vite配置
- 配置完 重新运行会在根目录下生成auto-imports.d.ts文件,没有出来的 关掉编译器再打开就有了。
测试
- 我靠,竟然不行,原因是ts没有识别到这个文件,我们再tsConfig.json配置一下
完美
引入Pinia
安装
- npm install pinia
使用
- 在src目录下创建一个stores目录,再stores目录下创建一个index.ts文件
import { createPinia } from 'pinia'
const pinia = createPinia()
export default pinia
- 然后在main.ts里面引入挂载
- stores目录下创建moudules目录,并且在modules目录下创建一个user.ts文件
import {defineStore} from 'pinia'
interface IUserState {
firstName: string
lastName: string
}
const useUserStore = defineStore('user', {
state: (): IUserState => ({
firstName: 'Y',
lastName: 'JiaXin'
}),
getters: {
fullName(): string {
return this.firstName + ' ' + this.lastName
}
}
})
export default useUserStore
测试
- 可以看到输出了,简单的集成就结束了。
还记得我们上面引入了unplugin-auto-import吗
- vite.config.ts里面配置一下pinia的
- 快乐
集成vue i18n国际化
安装
- npm install vue-i18n
使用
- 在src目录下创建一个i18n目录。
-
语言文件
-
cn.ts 中文语言包
- en.ts 英文语言包
- index.ts 统一管理中文、英文语言包
- i18n目录下的index.ts文件
import {createI18n} from "vue-i18n"
import {enLang, cnLang} from "./language/index"
const messages = {
en: {
...enLang
},
cn: {
...cnLang
}
}
console.log("messages", messages)
const i18n = createI18n({
legacy: false, // 如果要支持compositionAPI,此项必须设置为false;
globalInjection: true, // 全局注册$t方法
locale: 'en',
messages: messages
})
export default i18n;
- 最终需要暴露出去,我们稍后就需要在main.ts当中引用它
- main.ts使用i18n
测试
我之前写了一个简单的登录页面,为了测试,我把代码贴出来
<template>
<div class="container">
<div class="container-box">
<div class="container-box-title">
<h1>{{ $t('login.title') }}</h1>
</div>
<div class="container-box-form">
<a-form
:model="formState"
@finish="handleFinish"
@finishFailed="handleFinishFailed"
>
<a-form-item>
<a-input v-model:value="formState.user" :placeholder="$t('login.username')">
<template #prefix>
<UserOutlined style="color: rgba(0, 0, 0, 0.25)"/>
</template>
</a-input>
</a-form-item>
<a-form-item>
<a-input v-model:value="formState.password" type="password" :placeholder="$t('login.password')">
<template #prefix>
<LockOutlined style="color: rgba(0, 0, 0, 0.25)"/>
</template>
</a-input>
</a-form-item>
<a-form-item>
<a-button
type="primary"
html-type="submit"
:disabled="formState.user === '' || formState.password === ''"
>
{{ $t('login.loginBtn')}}
</a-button>
</a-form-item>
</a-form>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import {UserOutlined, LockOutlined} from '@ant-design/icons-vue';
import type {UnwrapRef} from 'vue';
import type {FormProps} from 'ant-design-vue';
interface FormState {
user: string;
password: string;
}
const formState: UnwrapRef<FormState> = reactive({
user: '',
password: '',
});
const handleFinish: FormProps['onFinish'] = values => {
console.log(values, formState);
};
const handleFinishFailed: FormProps['onFinishFailed'] = errors => {
console.log(errors);
};
</script>
<style scoped lang="scss">
.container {
height: 100vh;
display: flex;
justify-content: center;
align-items: center;
background: linear-gradient(to right, #fbc2eb, #a8c1ee);
&-box {
width: 470px;
height: 450px;
padding: 0 30px;
border-radius: 10px;
background-color: #FFFF;
&-title {
margin-top: 80px;
}
&-title, &-form {
text-align: center;
}
}
}
</style>
- 由于我们在i18n里面配置了globalInjection: true, 全局挂载了直接使用。$t
- 你们也可以试试换成cn,显示的就是中文啦!当然你也可以在页面上写一个icon或者一个按钮,点击切换它,动态完成中英文语言的切换!
动态实现中英文切换
- 如图,我在右上角加入了一个icon,点击动态切换中英文。
思路
- i18n的locale配置不能写死,我这里使用的方案是从本地缓存取,如果没有默认是英文(第一次进入系统肯定是没有的,也相当于默认就是英文)
- 给右上角的icon绑定点击事件,判断本地缓存如果是中文咱们就赋值英文,如果是英文咱们就赋值中文,功能就可以实现了。
实现
路由文件拆分
当项目越来越大时,所有路由文件都写在一个文件几千行,也不利于查找修改。故拆分
- 将每个模块的路由文件按目录拆分
- 然后通过一个index.ts统一管理
路由拦截
import {createRouter, createWebHistory} from "vue-router";
import type {RouteLocationNormalized, NavigationGuardNext} from "vue-router"
import routes from "./modules/index"
const router = createRouter({
history: createWebHistory(),
routes
})
// 全局前置守卫
router.beforeEach((to: RouteLocationNormalized, from: RouteLocationNormalized, next: NavigationGuardNext): void => {
console.log("路由from", from)
const token = sessionStorage.getItem("news-html-token");
if (token) {
if (to.path === '/login') {
next('/home'); // 如果已登录,且目标页面是登录页,则重定向到 home 页
} else {
next(); // 如果已登录,正常跳转
}
} else {
if (to.path === '/login') {
next(); // 如果未登录,但目标页面是登录页,则正常跳转
} else {
next('/login'); // 如果未登录,且目标页面不是登录页,则重定向到登录页
}
}
})
// 全局后置钩子
router.afterEach((): void => {
})
export default router;