Vite+Vue3+TypeScript项目创建

  • Post author:
  • Post category:vue




Vite+Vue3+TypeScript项目创建

1、因为使用vite构建项目,与cli、不同,需要自己新建router、vuex、sass

2、你需要有点基础,在博文中我全程以cnpm叙述,因为方便复制,cnpm镜像下载速度快,安装node自有npm,npm去下载cnpm。

3、也可以使用npm的国内淘宝镜像

# 更改npm镜像
npm config set registry https://registry.npm.taobao.org
# 验证是否更换成功
npm config get registry



一、Vite+Vue3项目创建



1、通过

npm

创建项目

npm init @vitejs/app my-vue-app --template vue

img

在项目开始前配置好

vite.config.ts



2、配置vite.config.ts


我们在写vue3的时候 每个组件都要频繁的引入 下面这样 借用插件可以不用引入 直接用,默认只配置了vue vuex、element plus需要自己在配置

//非常的繁琐
import { ref, torefs, nextTick, onMounted..... } from 'vue'


这时候我们只需要下载两个插件

cnpm i -D unplugin-auto-import
cnpm i -D unplugin-vue-components
cnpm i @types/node -D


找到 vite.config.ts/js 配置一下

import AutoImport from 'unplugin-auto-import/vite';
 
 plugins: [
		vue(),
		AutoImport({
			imports: ['vue', 'vue-router','vuex'], // 自动导入vue和vue-router相关函数
			dts: 'src/auto-import.d.ts', // 生成 `auto-import.d.ts` 全局声明
		}),
	],



3、找到 tsconfig.json 配一下

"include": [
		"src/**/*.ts",
		"src/**/*.d.ts",
		"src/**/*.tsx",
		"src/**/*.vue",
		"auto-imports.d.ts"
	],

img

下面配置跨域和路径别名和

element-plus

组件库按需引入 完整

vite.config.ts/js

代码

import vue from "@vitejs/plugin-vue";
import { defineConfig } from "vite";
 
import AutoImport from "unplugin-auto-import/vite";
import Components from "unplugin-vue-components/vite";
import { ElementPlusResolver } from "unplugin-vue-components/resolvers";
 
import { resolve } from "path";
 
export default defineConfig({
  base: "./",
  plugins: [
    vue(),
    //引入自动导入 插件
     AutoImport({
			imports: ['vue', 'vue-router','vuex'], // 自动导入vue和vue-router相关函数
			dts: 'src/auto-import.d.ts', // 生成 `auto-import.d.ts` 全局声明
		}),
    //plus按需引入
    AutoImport({
      resolvers: [ElementPlusResolver()],
    }),
    //plus按需引入
    Components({
      resolvers: [ElementPlusResolver()],
    }),
  ],
  build: {
    minify: "terser",
    terserOptions: {
      compress: {
        //生产环境时移除console
        drop_console: true,
        drop_debugger: true,
      },
    },
  },
 
  resolve: {
    alias: {
      "/@": resolve(__dirname, "src"),
      // 注意一定不要随意命名,a b c这样的,项目的目录也不能为关键字保留字!!
      comp: resolve(__dirname, "src/components"),
      // 配置图片要这样引用
      "/img": "./src/assets",
    },
  },
 
  // 跨域
  server: {
    //使用IP能访问
    host: "0.0.0.0",
    // 热更新
    hmr: true,
    //设为 true 时若端口已被占用则会直接退出,而不是尝试下一个可用端口
    strictPort: false,
    //自定义代理规则
    proxy: {
      // 选项写法
      "/api": {
        // 跨域这里只需要写本地接口就行,线上和test环境已经在network/baseUrl.js中配置好了
        target: "http://192.168.0.52:8083",
        changeOrigin: true,
        rewrite: (path) => path.replace(/^\/api/, ""),
      },
    },
  },
});



4、页面效果:
img

img

路径别名、跨域、自动引入api都配好了,现在整合路由



二、安装路由 :

cnpm install vue-router@next



1、创建一个文件,用来配置router:

img

import { createRouter,createWebHistory} from "vue-router"
 
const routes = [
  {
    path:'/',
    redirect: 'login'
  },
  {
    path:'/login',
    component: () => import('@/pages/login/login.vue')
  },
  {
    path:'/home',
    component: () => import('@/pages/home/home.vue')
  }
]
 
// 导出路由
const router = createRouter({
  history: createWebHistory(),  //开启history模式
  routes
});
 
export default router;



2、创建好了router文件后,记得一定要导出,在main.ts中使用

//main.ts
 
import { createApp } from 'vue'
import App from '@/App.vue'
 
//导入router配置文件
import route from '@/route/router'
 
//类似于:
/**
vue-cli:
Vue.use(router)
const app = new Vue({
	render: h => h(App)
}).$mount("#app")
*/
 
const app = createApp(App)
//全局注册
app.use(route)
 
app.mount('#app')

img

img



三、安装 vuex:

cnpm install vuex@next --save



1、新建文件store.js/ts:

img

//store.ts:
 
import { createStore } from "vuex";
const store = createStore({
    state()
    {
        return {
            count: '666',
        };
    },
    getters: {
        getCount(state)
        {
            return state.count;
        },
    },
    mutations: {
        increment(state)
        {
            state.count++;
        },
    },
});
 
export default store;



2、在main.js中使用:

// main.js/ts:
 
import { createApp } from 'vue'
import App from '@/App.vue'
 
import route from '@/route/router'
import store from '@/store/store'
 
const app = createApp(App)
//全局注册
app.use(route)
app.use(store)
 
app.mount('#app')



3、在页面使用vuex:

// login.vue
 
<script setup lang="ts">
import { useStore } from "vuex";
import { computed, onMounted } from "vue";
let store = useStore();
 
const count = computed(() => store.state.count);
onMounted(() => {
  console.log("插件自动引入,上面没引入onMounted,这里直接用");
});
const addClick = () => {
  store.commit("increment");
};
</script>
 
<template>
  <router-link to="/home">跳转 home</router-link>
  <br />
  <hr />
  <!--这里是vuex的数据,不要直接在这里使用 不然修改vuex数据页面不能及时相应,需要在计算属性中处理下
      在vue3.0中,可以直接写,因为 proxy 可以监听到任意数据的变化
  -->
  <p>{{ $store.state.count }}</p>
 
  <!-- 通过计算属性可以及时变化 -->
  <p>{{count}}</p>
  <button @click="addClick">增加</button>
</template>



四、安装:scss或less

# 安装sass
cnpm install sass
#安装less
cnpm install less
cnpm install less-loader

使用:

  • <style lang=“scss” scoped></style>
  • <style lang=“less” scoped></style>

在vite.config.ts中注册

css: {
    // css预处理器
    preprocessorOptions: {
      less: {
        charset: false,
        additionalData: '@import "./src/assets/style/global.less";',
      },
    },
  },



五、安装axios:

cnpm install axios



1、vue3+vite 封装axios请求

  1. //挂载全局属性或者方法,类似于 Vue.prototype.$api = api
  2. app.config.globalProperties.$api = api



2、创建axios实例

新建一个

api

文件夹并在文件夹里创建

request.ts



error-code-type.ts

import axios from 'axios';
import { errorCodeType } from './error-code-type';
import { ElMessage, ElLoading } from 'element-plus';

// 创建axios实例
const service = axios.create({
    // 服务接口请求
    baseURL: '/api',
    // 超时设置
    // timeout: 15000,
    headers:{'Content-Type':'application/json;charset=utf-8'}
})

let loading:any;
//正在请求的数量
let requestCount:number = 0
//显示loading
const showLoading = () => {
    if (requestCount === 0 && !loading) {
        //加载中显示样式可以自行修改
        loading = ElLoading.service({
            text: "拼命加载中,请稍后...",
            background: 'rgba(0, 0, 0, 0.7)',
            spinner: 'el-icon-loading',
        })
    }
    requestCount++;
}
//隐藏loading
const hideLoading = () => {
    requestCount--
    if (requestCount == 0) {
        loading.close()
    }
}

// 请求拦截
service.interceptors.request.use(config => {
    showLoading()
    // 是否需要设置 token放在请求头
    // config.headers['Authorization'] = 'Bearer ' + getToken() // 让每个请求携带自定义token 请根据实际情况自行修改
    // get请求映射params参数
    if (config.method === 'get' && config.params) {
        let url = config.url + '?';
        for (const propName of Object.keys(config.params)) {
            const value = config.params[propName];
            const part = encodeURIComponent(propName) + "=";
            if (value !== null && typeof(value) !== "undefined") {
                // 对象处理
                if (typeof value === 'object') {
                    for (const key of Object.keys(value)) {
                        let params = propName + '[' + key + ']';
                        const subPart = encodeURIComponent(params) + "=";
                        url += subPart + encodeURIComponent(value[key]) + "&";
                    }
                } else {
                    url += part + encodeURIComponent(value) + "&";
                }
            }
        }
        url = url.slice(0, -1);
        config.params = {};
        config.url = url;
    }
    return config
}, error => {
    Promise.reject(error).then(r => {
        console.log(error);
    })
})

// 响应拦截器
service.interceptors.response.use((res:any) => {
        hideLoading()
        // 未设置状态码则默认成功状态
        const code = res.data['code'] || 200;
        // 获取错误信息
        const msg = errorCodeType(code) || res.data['msg'] || errorCodeType('default')
        if(code === 200){
            return Promise.resolve(res.data)
        }else{
            return Promise.reject(res.data)
        }
    },
    error => {
        console.log('err' + error)
        hideLoading()
        let { message } = error;
        if (message == "Network Error") {
            message = "后端接口连接异常";
        }
        else if (message.includes("timeout")) {
            message = "系统接口请求超时";
        }
        else if (message.includes("Request failed with status code")) {
            message = "系统接口" + message.substr(message.length - 3) + "异常";
        }
        ElMessage.error({
            message: message,
            duration: 5 * 1000
        })
        return Promise.reject(error)
    }
)

export default service;
// error-code-type.ts
export const errorCodeType = function(code:string):string{
    let errMessage:string = "未知错误"
    switch (code) {
        // @ts-ignore
        case 400:
            errMessage = '错误的请求'
            break
        // @ts-ignore
        case 401:
            errMessage = '未授权,请重新登录'
            break
        // @ts-ignore
        case 403:
            errMessage = '拒绝访问'
            break
        // @ts-ignore
        case 404:
            errMessage = '请求错误,未找到该资源'
            break
        // @ts-ignore
        case 405:
            errMessage = '请求方法未允许'
            break
        // @ts-ignore
        case 408:
            errMessage = '请求超时'
            break
        // @ts-ignore
        case 500:
            errMessage = '服务器端出错'
            break
        // @ts-ignore
        case 501:
            errMessage = '网络未实现'
            break
        // @ts-ignore
        case 502:
            errMessage = '网络错误'
            break
        // @ts-ignore
        case 503:
            errMessage = '服务不可用'
            break
        // @ts-ignore
        case 504:
            errMessage = '网络超时'
            break
        // @ts-ignore
        case 505:
            errMessage = 'http版本不支持该请求'
            break
        default:
            errMessage = `其他连接错误 --${code}`
    }
    return errMessage
}



4、封装请求接口

// api.ts
import service from "./request";

export function getFile(){
    return new Promise((resolve,reject)=>{
        service.get("/file").then((res)=>{
            resolve(res);
        })
    })
}



6、vue中调用

import { mokePost } from "@/api";
import {onMounted} from "vue"
export default {
  setup() {
     onMounted(() => {
      getFile().then(res=>{
        console.log(res)
      })
    })
    return {};
  },
};
 



版权声明:本文为admin6608原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。