Vue3+Vite+TS (新手入门)

235 阅读1分钟

很多新手刚接触ts无从下手,以下代码可作为敲门砖,仅供初学者借鉴,大佬轻喷!!

showCode

views/index.vue

<template>
    <div @click="click">button1111</div>
    <van-button class="submit" type="primary" :block="true">主要按钮</van-button>
    <van-button type="primary" :loading="isLoading" loading-text="Loading" :block="true"/>

    <ul  v-for="(item, index) in list">
        <li>{{item.time}}</li>
        <li>{{item.context}}</li>
    </ul>
    
    <div>{{count}}</div>
    <div>
        <img :src="imgUrl" alt="1111">
    </div>
</template>


<script lang="ts" setup>
import {ref, reactive, onMounted} from 'vue'
import {search} from '@/api/home'
import axios from 'axios'


const count = ref(0)
const imgUrl = "data:image/jpeg;base64,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"
const isLoading = true
const click = () => {
    count.value++
}

onMounted(() => {
    console.log('onMounted')
})


console.log(import.meta.env.VITE_NODE_ENV)
let list: any = ref([])
const searchRequestParam = {
    type: 'yuantong',
    postid: 11111
}
const getList = search(searchRequestParam).then(res => {
    console.log(res)
    list.value = res.data?.ftime
})

// // 会出现跨域 使用proxy  配置 target 快递100的地址   匹配前缀kuaidi/
// axios.get('https://www.kuaidi100.com/query?type=sut56&postid=8000028687536').then(res => {
//     console.log(res)
// })

</script>

<style>

</style>

api/home.ts

import request from '../utils/request'

namespace Search {
    export interface RequestParam {
        type: string,
        postid: number
    }

    export interface ResponseData {
        time: string,
        context: string,
        ftime: string
    }
}


export const search = (_params: Search.RequestParam) => {
    return request.get<Search.ResponseData>('/query', _params);
}

utils/request.ts

import axios, {AxiosInstance, AxiosRequestConfig, AxiosError, AxiosResponse} from 'axios'

// 响应结构体 不含data
interface Result {
    status: number,
    message: string
}

interface ResultData<T> extends Result {
    data?: T
}

interface ResultDataTest<T> extends Result {
    hits?: T
}

const URL: string = ''
enum RequestEnums {
    TIMEOUT = 20000,
    OVERDUE = 600, // 登录失败
    FAIL = 999, // 请求失败
    SUCCESS = 200 // 请求成功
}

const config = {
    baseURL: URL as string,
    timeout: RequestEnums.TIMEOUT as number,
    withCredentials: true
}
const apiPrefix = import.meta.env.VITE_API_PREFIX
class RequestHttp {
    service: AxiosInstance;
    public constructor(config: AxiosRequestConfig) {
        this.service = axios.create(config)
        
        /**
         * 请求拦截器
         */
        this.service.interceptors.request.use((config: AxiosRequestConfig) => {
            const token = localStorage.getItem('token') || '';
            return {
                ...config,
                headers: {
                    'x-access-token': token
                }
            }
        }, (error: AxiosError) => {
            Promise.reject(error)
        })

        /**
         * 响应拦截器
         */
        this.service.interceptors.response.use((response: AxiosResponse) => {
            const {data, config} = response; // 响应数据
            if (data.code === RequestEnums.OVERDUE) {
                localStorage.setItem('token', '')
                return Promise.reject(data)
            }

            if (data.code && data.code !== RequestEnums.SUCCESS) {
                console.log("error message")
                return Promise.reject(data)
            }
            return data
        }, (error: AxiosError) => {
            const {response} = error
            if (response) {
                this.handleCode(response.status)
            }
            if (!window.navigator.onLine) {
                console.log('网络连接失败')
            }
        })
    }

    handleCode(code: number): void {
        switch(code) {
            case 401:
                console.log('登录失败,请重新登录')
                break;
            default:
                console.log('请求失败')
                break;
        }
    }

    
    get<T>(url: string, params?: object): Promise<ResultData<T>> {
        return this.service.get(apiPrefix + url, {params})
    }

    post<T>(url: string, data?: object): Promise<ResultData<T>> {
        return this.service.post(apiPrefix + url, data)
    }

    put<T>(url: string, data?: object): Promise<ResultData<T>> {
        return this.service.put(apiPrefix + url, data)
    }

    delete<T>(url: string, data?: object): Promise<ResultData<T>> {
        return this.service.delete(apiPrefix + url, data)
    }

}

export default new RequestHttp(config)

注意

main.ts

import { createApp } from 'vue'
import './style.css'
import App from './App.vue'
import router from './router/index'
import axios from 'axios'
import VueAxios from 'vue-axios'

const app = createApp(App)
app.use(VueAxios, axios)
app.use(router)
app.mount('#app')

App.vue

<template>
  <router-view></router-view>
</template>

tsconfig.json

    // 路径配置
    "baseUrl": ".",
    "paths": {
        "@/*": ["src/*"]
    }

vite.config.js

  resolve: {
    alias: {
      "@": path.resolve(__dirname, "src"),
      "@assets": path.resolve(__dirname, "src/assets"),
      "@components": path.resolve(__dirname, "src/components"),
      "@views": path.resolve(__dirname, "src/views"),
      "@store": path.resolve(__dirname, "src/store"),
    },
  },