web前端框架配置:vite+vue3+ts
vite+ts+vue3创建项目(不定时更新)
新建项目
使用vite创建项目
选择的是vue+ts
第一次运行项目
使用vs code进入项目:
文件->打开文件夹->选择刚才新建项目的文件夹
新建一个终端,在终端里输入:
npm install
然后执行运行的语句:
npm run dev
项目即可运行。此时的web状态为:
当页面显示该状态,则表示已成功创建项目。
引入element-plus
下载element-plus
npm install element-plus --save
相关配置
格式化配置
1: 推荐使用vscode
2: vscode 安装插件 vetur | Prettier - Code formatter
3: 详细配置查看settings.json(放置.vscode里)
4:按下ctrl+s 即可对单文件(.vue, .js)完成格式化
{
"vsicons.presets.nestjs": true,
"files.exclude": {
"node_modules": true,
"dist": false
},
"editor": {
"formatOnSave": true
},
// .js 格式化设置
"prettier": {
"semi": false,
"singleQuote": true,
"printWidth": 100
},
// .vue 格式化设置 "octref.vetur"
"[vue]": {
"editor.defaultFormatter": "octref.vetur"
},
"vetur.validation.template": false,
"vetur.experimental.templateInterpolationService": false,
"vetur.format.defaultFormatterOptions": {
"prettier": {
"semi": false,
"singleQuote": true,
"printWidth": 100
}
}
}
国际化配置
由于element-plus配套组件默认显示是英文的,由此需要进行国际化配置。
通过 ConfigProvider 的方式来使用,详细的使用方法请查阅 ConfigProvider 的文档
<template>
<el-config-provider :locale="locale">
<App />
</el-config-provider>
</template>
<script>
import { ElConfigProvider } from 'element-plus'
import zhCn from 'element-plus/es/locale/lang/zh-cn'
defineComponent({
components: {
[ElConfigProvider.name]: ElConfigProvider,
},
data() {
return {
locale: zhCn,
}
},
})
</script>
很明显国际化不能做到页面层,要页面嵌套组件的方式
<el-config-provider :locale="locale">
<Yourprovide />
</el-config-provider>
import { ElConfigProvider } from 'element-plus';
components: {
[ElConfigProvider.name]: ElConfigProvider,
Timeprovide,
},
然后引入语言包,以中文为例,最后设置语言变量即可
import zhCn from 'element-plus/lib/locale/lang/zh-cn';
locale: zhCn,
已上为网络上的讲解,我本地此时的app.vue为:
<template>
<el-config-provider :locale="locale">
<div id="app">
</div>
</el-config-provider>
</template>
<script lang="ts">
import { defineComponent } from 'vue'
import { ElConfigProvider } from 'element-plus'
import zhCn from 'element-plus/es/locale/lang/zh-cn'
export default defineComponent({
name: 'App',
components: {
[ElConfigProvider.name]: ElConfigProvider //添加组件
},
setup(props: any, ctx) {
return {
locale: zhCn
}
},
})
</script>
<style scoped>
</style>
当时,出现过一些问题,“element-plus”飘红了,原因:typescript 只能理解 .ts 文件,无法理解 .vue文件
对此,需要做一些修改:
在src路径下新建一个后缀为 .d.ts 的文件.
本项目新建了一个文件“shims-vue.d.ts”
内容是:
declare module '*.vue' {
import { DefineComponent } from 'vue'
// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/ban-types
const component: DefineComponent<{}, {}, any>
export default component
}
此时,可能还会有飘红,提示信息为“Cannot find module ‘vue’. Did you mean to set the ‘moduleResolution’ option to ‘node’, or to add aliases to the ‘paths’ option?”,此时查看自己的tsconfig.json文件中,确保’module’设置为’ESNext’,并确保’moduleResolution’设置为’node’。
router设置
安装vue-router
npm install vue-router@4
rouer里的index.js(基本框架):
import { createRouter, createWebHashHistory, RouteRecordRaw } from 'vue-router'
// let pages = import.meta.glob('../view/**/**.vue')
const routes: Array<RouteRecordRaw> = [
{
path: '/',
name: 'demo',
component: () => import('../components/HelloWorld.vue'),
// component: pages['../components/HelloWorld.vue']
},
{
path: '/foo',
name: 'foo',
component: () => import('../views/home/foo.vue'),
},
{
path: '/bar',
name: 'bar',
component: () => import('../views/home/bar.vue'),
}
]
const router = createRouter({
history: createWebHashHistory(),
routes
})
export { router }
测试页面foo.vue/bar.vue
<template>
<div>this is foo page</div>
</template>
<script setup>
</script>
<style>
</style>
app.vue页面进行如下修改
<template>
<el-config-provider :locale="locale">
<div id="app">
<router-view></router-view>
</div>
</el-config-provider>
</template>
<script lang="ts">
import { defineComponent } from 'vue'
import { reactive, ref, toRefs, computed, watch, inject } from 'vue'
import { ElConfigProvider } from 'element-plus'
import zhCn from 'element-plus/es/locale/lang/zh-cn'
import { useRouter } from 'vue-router'
export default defineComponent({
name: 'App',
components: {
[ElConfigProvider.name]: ElConfigProvider, //添加组件
},
setup(props: any, ctx) {
return {
locale: zhCn,
}
},
})
</script>
<style scoped>
</style>
store设置
安装vuex
npm i vuex@next -S
在src里新建一个store文件夹,入口目录为index.ts,文件里内容为:
// import { InjectionKey } from 'vue'
import { createStore, Store } from 'vuex'
// import { vx as user } from './user'
export type IState = any
// export const key: InjectionKey<Store<IState>> = Symbol()
export const vx = {
state: {},
mutations: {
demoMutation(state: any) {}
},
actions: {
async demoAction({ commit, state, rootState }: any, app: any) {
console.log(3)
}
},
getters: {
demoGetter(state: any) {
return async () => {
return null
}
}
},
modules: { }
}
export const store = createStore<IState>(vx)
该store内的index.ts作为主文件,通过模块化的形式导入其他store:import引入,modules导入。
然后在main.js里引入
import { createApp } from 'vue'
import { router } from './router'
import { store } from './store'
import './glob'
import './style.css'
import App from './App.vue'
const app = createApp(App)
app.use(router)
app.use(store)
app.mount('#app')
在其他页面的适用:
<template>
<div>this is foo page{{ store.state.test1 }}</div>
</template>
<script setup>
import { useStore } from 'vuex'
const store = useStore()
</script>
<style>
</style>
此时test1是在store主文件里定义过的。
axios
安装axios:
npm install axios
二次封装axios:
目的:
主要是要用到请求拦截器和响应拦截器;
请求拦截器:可以在发请求之前可以处理一些业务
响应拦截器:当服务器数据返回以后,可以处理一些事情
二次封装的思路可参考(核心思路)
https://blog.csdn.net/qq_45881272/article/details/126121928
在src里新建一个文件夹api,其中包含两部分:分别是二次封装的axios、接口接口。
本项目的二次封装代码如下:直接导入可能有些地方报错,注意去global里去申明$api。在api里建一个user的模块,处理登录功能。
import Axios, { AxiosInstance } from 'axios'
import { ElMessage } from 'element-plus'
const FORCE_RELOGIN: boolean = import.meta.env.VITE_TEST_FORCE_RELOGIN == 'true'
let authorization: string = localStorage.getItem('authorization') || ''
interface IAx extends AxiosInstance {
$getWithBody: any
}
const instance: AxiosInstance = Axios.create({
timeout: 35000,
withCredentials: true,
/* eslint-disable */
// @ts-ignore
'headers.post.Content-Type': 'application/json;charset=UTF-8',
'headers.put.Content-Type': 'application/json;charset=UTF-8',
'headers.patch.Content-Type': 'application/json;charset=UTF-8'
})
instance.defaults.baseURL = ''
instance.interceptors.request.use(
(req: any): any => {
req.headers.Authorization = authorization + (FORCE_RELOGIN ? '@@@@' : '')
return req
},
(err: any): any => {
throw err
}
)
instance.interceptors.response.use(
async (res: any) => {
if (
res.data.status == 401 ||
res.data.status == 403 ||
res.data.code == 401 ||
res.data.code == 403
) {
onAuthorizationInvalid(res)
} else {
await onLoginSuccess(res)
}
if (res.data && res.data.code != 0) {
ElMessage({
message: res.data.message,
type: 'error',
duration: 3 * 1000
})
}
return res.data
},
async (err: any) => {
let message = `${err.response ? err.response : ''}-${err.message ? err.message : ''}`
ElMessage({
message,
type: 'error',
duration: 3 * 1000
})
console.log(err)
return Promise.reject(err)
}
)
function onAuthorizationInvalid(res: any) {
authorization = ''
localStorage.removeItem('authorization')
$router.push({
path: '/login'
})
$store.dispatch('user/relogin')
}
async function onLoginSuccess(res: any) {
switch (res.config.url) {
case $api.user.post.session:
authorization = res.headers.authorization
localStorage.setItem('authorization', authorization)
$router.push({
path: '/home'
})
await $store.dispatch('user/getInfo')
await $store.dispatch('nav/init', true)
break
}
}
let contex = {
...instance,
$getWithBody(url: string, data: any) {
let xhr = new XMLHttpRequest()
xhr.withCredentials = true
xhr.addEventListener('readystatechange', function () {
console.log(this)
if (this.readyState === 4) {
console.log(this.responseText)
}
})
xhr.open('GET', url, true)
xhr.withCredentials = true
xhr.setRequestHeader('Content-Type', 'application/json;charset=UTF-8')
// xhr.setRequestHeader('Accept', '*/*')
// xhr.setRequestHeader('Cache-Control', 'no-cache')
xhr.setRequestHeader('Authorization', authorization)
// xhr.setRequestHeader('cache-control', 'no-cache')
xhr.send(JSON.stringify(data))
xhr.onload = function () {
console.log('onload')
}
}
}
export { contex }
解决跨域问题:
我们用代理解决,在vue.config.js配置如下代码:
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
// https://vitejs.dev/config/
export default defineConfig({
plugins: [vue()],
server: {
host: '127.0.0.1',
port: 5173,
open: false,
https: false,
hmr: true,
proxy: {
'/ucloud': {
// target: 'http://127.0.0.1:9991',
// target: 'http://10.6.***.128:****',
target: 'http://****.****.com',
changeOrigin: true,
rewrite: (path) => path.replace(/^\/ucloud/, '')
}
}
},
})
我做了个测试,在foo.vue文件里
<template>
<div>this is foo page{{ store.state.test1 }}</div>
</template>
<script setup>
import { onMounted } from '@vue/runtime-core'
import { useStore } from 'vuex'
const store = useStore()
onMounted(() => {
// console.log($api.user.post.session)
let res = $ax.get($api.user.get.session)
console.log(res)
})
</script>
<style>
</style>
调用的接口数据如下:
// const domain = import.meta.env.VITE_DOMAIN_UCLOUD
const domain = '/ucloud'//http://ucloud.unisoc.com/
export default {
get: {
// authTest: `${domain}/v1/auth/perm/config/action`,
// userinfo: `${domain}/v1/manager/userInfo`,
// user: `${domain}/v1/manager/user`
session: `${domain}/v1/thirdAccess/verify-utit/get-infos`,
},
delete: {
// user: `${domain}/v1/manager/user`
},
post: {
session: `${domain}/login`,
// user: `${domain}/v1/manager/user`
},
put: {
// user: `${domain}/v1/manager/user`
}
}
全局变量配置
总全局变量设置
在src里建一个glob文件夹,内有一个index.ts文件,用以配置全局变量。
;(window as any)['global'] = window //申明变量global挂载到window上
//import api from '../api'
//import { IState } from '../store'
//import func from '@/utils/func'
//import { contex as ax } from '@/utils/ax'
//import sql from '../sql'
//import { Store } from 'vuex'
import { Router } from 'vue-router'
import { App } from 'vue'
//https://blog.csdn.net/m0_55613022/article/details/123431456
//申明一个global对象,内部定义其属性
declare global {
let $app: App<Element>
// let $api: typeof api
// let $func: typeof func
// let $ax: typeof ax
let $store: any
let $router: Router
}
//下面这些是给global对象的属性赋值
// //@ts-ignore
// global.$api = api
// //@ts-ignore
// global.$func = func
// //@ts-ignore
// global.$ax = ax
// //@ts-ignore
// global.$sql = sql
常用func放在统一的地方
将上文中$func相关的注释去掉,即可。
然后在utils里创建一个func文件
本项目中,可默认先放入以下函数:
export default {
mSleep(ms: number) {
return new Promise((resolve: any, reject: any) => {
setTimeout(() => {
resolve()
}, ms)
})
},
generateVerifyCode(num: Number) {
const sample = 'ABCDEFGHJKMNPQRSTUVWXYZabcdefghjkmnpqrstuvwxyz23456789'
let ret: string = ''
for (let i = 0; i < num; i++) {
ret += sample[Math.floor(Math.random() * (sample.length - 0) + 0)]
}
return ret
},
uuid() {
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
var r = (Math.random() * 16) | 0,
v = c == 'x' ? r : (r & 0x3) | 0x8
return v.toString(16)
})
},
verifyForm(form: any) {
return new Promise((resove, reject) => {
form.validate((valid: any) => {
resove(valid)
})
})
},
resetForm(form: any) {
return new Promise((resove, reject) => {
form.resetFields((valid: any) => {
resove(valid)
})
})
},
jsonDelNull(ob: any) {
for (let key in ob) {
if (ob[key] === null || ob[key] === 'null' || ob[key] === '' || ob[key] === '""') {
delete ob[key]
}
}
},
arry2str(ob: any[], key = '', split = ',') {
let ret = ''
for (let item of ob) {
ret += `${key ? item[key] : item}${split}`
}
if (ret.endsWith(split)) {
ret = ret.slice(0, ret.length - split.length)
}
return ret
},
arry2arry(ob: any[], cb: (item: any) => any) {
let ret = []
for (let item of ob) {
ret.push(cb(item))
}
return ret
}
}
注意:在该func里有用到element组件库的函数,因此需要在全局中,通过use方法调用element里的方法。
详见:在main.ts里
import { createApp } from 'vue'
import { router } from './router'
import { store } from './store'
import './glob'
import './style.css'
import App from './App.vue'
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'
const app = createApp(App)
app.use(ElementPlus)
app.use(router)
app.use(store)
app.mount('#app')
// //@ts-ignore
// global.$app = app
全局样式统一放置
安装依赖:
npm install less
npm install less-loader
配置vite.config.js
css: {
// css预处理器
preprocessorOptions: {
less: {
charset: false,
additionalData: '@import "./src/style/index.less";',
},
},
},
可以在index.less里定义其他less文件,引用其他样式文件
例如:
@import './color.less';
@import './layout.less';
@import './text.less';
@import './el.less';
打包配置
配置vite.config.js
build: {
target: 'es2015',
outDir: 'dist',
assetsDir: 'assets',
assetsInlineLimit: 2048,
cssCodeSplit: true,
minify: 'terser',
terserOptions: {
compress: {
drop_console: false,
drop_debugger: true
}
}
}
配置path的处理方式:@,/
https://www.cnblogs.com/Dollom/p/17125719.html
在使用vite脚手架生成项目时,会出现一些引入路径失败的错误
例子:router中用 component引入路径时
引入 …/ 路径失败
此时就是没有声明引入地址的方法
解决方法:
找到 vite-env.d.ts
复制以下代码进入
//vue类型声明,让TS知道 .vue文件是什么
declare module "*.vue" {
import type { DefineComponent } from "vue";
const component: DefineComponent<{}, {}, any>;
export default component;
}
引入 @/ 路径失败
出现报错: ts类型错误提示找不到模块“path”或其相应的类型声明
解决方法:
1.安装 npm i @types/node -D
2.配置vite.config.ts
import path from 'path'
export default defineConfig({
plugins: [vue()],
resolve:{
alias:{
"@":path.resolve(__dirname,'./src')
}
}
})
配置tsconfig.json
{
"compilerOptions": {
...
"baseUrl": "./",
"paths": {
"@/*":["src/*"]
}
},
"include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue"],
"references": [{ "path": "./tsconfig.node.json" }]
}
更多推荐
所有评论(0)