vue3+ts項目搭建和封裝(下篇)

這是我參與8月更文挑戰的第11天,活動詳情查看:8月更文挑戰css

# vue3+ts項目搭建和封裝(上篇)vue

配置request.ts

/**
 * axios 二次封裝 
 * @auther 何小生。
 * @time 2021/08/05 05:24
*/
import axios from 'axios'   // 引入axios
import { config } from '../config'  // 引入config
import { ElMessage } from 'element-plus'  // 引入element-plus
import router from '../router'  // 因爲有些token認證失效等須要用到,因此引入router
import { storage } from './storage'  // 引入storage,用於獲取緩存

// 定義初始化狀態碼
const TOKEN_INVALID = 'Token認證失敗, 請從新登陸'
const NETWORK_ERROR = '網絡請求異常, 請稍後重試'

// 建立axios實例對象, 添加全局配置
const service = axios.create({
    // 初始配置請求頭  當環境爲mock的時候,請求mockapi,不然請求正式的api
    baseURL: config.mock ? config.mockApi : config.baseApi,
    // 接口持續時間爲8秒,不然超時
    timeout: 8000
})

// 請求攔截
service.interceptors.request.use((req) => {
    // TO-DO
    // 獲取請求頭
    const headers = req.headers
    // 獲取token 因爲是typescript,因此要作排斥賦值
    const { token = "" } = storage.get('userInfo') || {}
    // 跟後端定義的某個請求頭的值用於解析token身份令牌
    if(!headers.Authorization) headers.Authorization = 'xiaohe ' + token
    // 返回請求頭
    return req
})

// 響應攔截
service.interceptors.response.use((res) => {
    // 獲取後端返回的code,data和提示語
    const { code, data, msg } = res.data
    if(code == 200) return data
    else if(code === 50001) {   // token認證失敗
        ElMessage.error(TOKEN_INVALID)   // 給予5001的狀態碼
        // 而且給予用戶 必定的反應時間後,跳轉登陸頁
        setTimeout(() => {
            router.push('/login')
        }, 15000)
        return Promise.reject(TOKEN_INVALID)  // 拋出異常
    } else {
        // 丟出服務器異常
        ElMessage.error(msg || NETWORK_ERROR)
        return Promise.reject(msg || NETWORK_ERROR)
    }
})

/**
 * @param {*} options   請求配置
*/
function request(options: any) {
    options.method = options.method || 'get'
    if(options.method.toLowerCase() === 'get') options.params = options.data
    if(typeof options.mock != 'undefined') config.mock = options.mock
    if(config.env === 'prod') service.defaults.baseURL = config.baseApi
    else service.defaults.baseURL = config.mock ? config.mockApi : config.baseApi
    return service(options)
}

// 輪詢接口類型,而後根據對應的類型,給予請求方式
['get', 'post', 'put', 'delete', 'patch'].forEach(item => {
    request[item] = (url: string, data: any, options: string[]) => {
        return request({ url, data, method: item, ...options })
    }
})

// 丟出request
export default request
複製代碼

封裝storage.ts

此處用到了storage和sessionStorage兩種方法作緩存封裝ios

/**
 * 封裝操做localstorage本地存儲的方法
 * @auther 何小玍。
 * @date 2021/06/28
 */
export const storage = {
    //存儲
    set(key: string, value: any) {
        window.localStorage.setItem(key, JSON.stringify(value))
    },

    //取出數據
    get<T>(key: string) {
        const value = window.localStorage.getItem(key)
        if (value && value != "undefined" && value != "null") return <T>JSON.parse(value)
        else return "{}"
    },

    // 刪除數據
    remove(key: string) {
        window.localStorage.removeItem(key)
    }
};

/**
 * 封裝操做sessionStorage本地存儲的方法
 */
export const sessionStorage = {
    //存儲
    set(key: string, value: any) {
        window.sessionStorage.setItem(key, JSON.stringify(value))
    },

    //取出數據
    get<T>(key: string) {
        const value = window.sessionStorage.getItem(key);
        if (value && value != "undefined" && value != "null") return JSON.parse(value)
        return null
    },

    // 刪除數據
    remove(key: string) {
        window.sessionStorage.removeItem(key)
    }
}
複製代碼

配置config.ts

在src目錄下建立config文件夾,而後建立index.ts, 用於配置請求的基本配置參數和區分生產環境和開發環境vue-router

export interface IConfig {
    env: string // 開發環境
    mock?: boolean // mock數據
    title: string // 項目title
    baseApi?: string // api請求地址
    mockApi?: string // mock地址
}

const dev: IConfig = {
    env: "development",
    mock: false,
    title: "開發",
    baseApi: "/api", // 本地api請求地址,注意:若是你使用了代理,請設置成'/'
    mockApi: "https://www.fastmock.site/mock/4f8c864d98d32e623e4a452a904ca70b/api"
}

const prod: IConfig = {
    env: "production",
    mock: false,
    title: "生產",
    baseApi: "https://www.baidu.com/api", // 正式api請求地址
    mockApi: 'xxx'
}

export const config: IConfig = import.meta.env.MODE == 'development' ? dev : prod

複製代碼

配置api封裝

在src目錄下,建立api文件夾,而後生成user.ts文件,存放登陸註冊忘記密碼等接口typescript

import request from '../utils/request'
interface userState {
    username: string
    password: string
}
export default {
    /**
     * 登陸接口
     * @param { string } username       用戶名稱
     * @param { string } password       用戶密碼
     */
    
    login( data: userState ) {
        return request({
            url: '/users/login',
            method: 'post',
            data
        })
    }
}
複製代碼

配置router和路由守衛

在src文件夾下建立index.ts、router.config.tsaxios

  • 路由守衛的配置
import { createRouter, createWebHistory } from "vue-router"
import { constantRouterMap } from "./router.config"
import { useDocumentTitle } from "@/hooks/useDocumentTitle"
import store from "@/store"

const router = createRouter({
  history: createWebHistory(import.meta.env.BASE_URL),
  // 在按下 後退/前進 按鈕時,就會像瀏覽器的原生表現那樣
  scrollBehavior(to, from, savedPosition) {
    if (savedPosition) return savedPosition
    else return { top: 0 }
  },
  routes: constantRouterMap
})

// 路由開始進入
router.beforeEach((to: any, from: any, next) => {
  useDocumentTitle(to.meta.title)
  next()
  return false
})

router.afterEach((to, from, next) => {
  // 保存url
})

export default router
複製代碼
  • 路由配置
import { RouteRecordRaw } from "./vue-router"
import Layout from '@/layout/index.vue'

export const constantRouterMap: Array<RouteRecordRaw> = [  
  { path: '/login', name: 'login', component: () => import('@/views/login/login.vue'), meta: { title: '登陸' }, hidden: true },
  { path: '/', name: '/', component: Layout, redirect: '/index', meta: { title: '博客', icon: 'el-icon-help' }, children: [
    { path: '/index', name: 'index', component: () => import('@/views/index/index.vue'), meta: { title: '博客', icon: 'el-icon-link' } }
  ] },
  { path: '/404', name: 'page404', component: () => import('@/views/404.vue'), meta: { title: '404' }, hidden: true },
  { path: '/:catchAll(.*)', redirect: '/404', hidden: true }
]
複製代碼

main.js配置

最後在main.js裏面配置後端

import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'
import svgIcon from './icons/index.vue'
import { storage, sessionStorage } from './utils/storage'

import ElementPlus from 'element-plus'
import 'element-plus/lib/theme-chalk/index.css'

// 引入全局樣式
import "./styles/base.css"
import "./styles/reset.css"

const app = createApp(App)
app.config.globalProperties.storage = storage                   // 全局掛載 緩存方法
app.config.globalProperties.sessionStorage = sessionStorage     // 全局掛載 緩存方法

app
.use(router)
.use(store)
.use(ElementPlus)
.component('svg-icon', svgIcon)
.mount('#app')
複製代碼

最後

公衆號:小何成長,佛系更文,都是本身曾經踩過的坑或者是學到的東西api

有興趣的小夥伴歡迎關注我哦,我是:何小玍。你們一塊兒進步鴨瀏覽器

相關文章
相關標籤/搜索