web前端框架配置:vite+vue3+ts

新建项目

新建项目的操作
使用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" }]
}
  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值