第二節:三方庫集成和配置(vue cli-webpack、element-plus、axios、vscode、區分不同環境)


一. vue cli-webpack配置

1. 說明

 在vue cli創建的項目中,配置文件為:vue.config.js

 vue.config.js 是一個可選的配置文件,如果項目的 (和 package.json 同級的) 根目錄中存在這個文件,那么它會被 @vue/cli-service 自動加載。

2. vue cli 基本配置

(詳見:https://cli.vuejs.org/zh/config/#全局-cli-配置 ) 

(1). outputDir

(2). publicPath

剖析:

  默認值為‘/’,生成的打包文件的引用的路徑都是以/開頭,沒法直接在vscode中運行,需要部署后才能運行,

  如果改為'./',生成的打包文件的引用路徑如下圖,可以直接在vscode中運行

3. webpack配置 

(詳見:https://cli.vuejs.org/zh/guide/webpack.html#簡單的配置方式 ) 

 在vue cli創建的項目中,不能配置webpack.config.js文件,需要在vue.config.js中的configureWebpack 或 chainWebpack 屬性中配置, configureWebpack 屬性中的配置和webpack中的配置一樣,自動就合並了。

補充:cli中,@符號已經默認配置了,對應的就是src目錄,當然可以重寫。

下面是幾種寫法: 

const path = require('path');

module.exports = {
    //CLI提供的屬性
    outputDir: './build',
    // publicPath: './', //打包后的可以直接使用,不用發布,默認是 '/'
    // webpack寫法1(json格式)
    // 和webpack屬性完全一致, 最后會進行合並
    configureWebpack: {
        resolve: {
            alias: {
                components: '@/components',
            },
        },
    },
    // webpack寫法2(函數形式)
    // configureWebpack: (config) => {
    //   config.resolve.alias = {
    //     '@': path.resolve(__dirname, 'src'),
    //     components: '@/components'
    //   }
    // }
    // webpack寫法3(鏈式編程)
    // chainWebpack: (config) => {
    //     config.resolve.alias
    //         .set('@', path.resolve(__dirname, 'src'))
    //         .set('components', '@/components');
    // },
};

 

二. element-plus配置

1. 全局引用

(1). 說明

  如果你對打包后的文件大小不是很在乎,那么使用完整導入會更方便。

(2). 步驟

A. 安裝生產依賴 【npm install element-plus】

B. 全局引用,在main.ts文件中導入

import { createApp } from 'vue';
import App from './App.vue';
// 全局引入element-plus
import ElementPlus from 'element-plus';
import 'element-plus/dist/index.css';

const app = createApp(App);
app.use(ElementPlus); //全局引用element-plus
app.use(golbalRegister); // 按需引入element-plus

app.mount('#app');

C. 在頁面中直接使用任意組件即可

<template>
    <div>
        <el-button>默認按鈕</el-button>
        <el-button type="primary">主要按鈕</el-button>
        <el-button type="success">成功按鈕</el-button>
        <el-button type="info">信息按鈕</el-button>
    </div>
</template>

<script lang="ts">
    import { defineComponent } from 'vue';
    export default defineComponent({
        setup() {
        },
    });
</script>

<style lang="less"></style>

2. 按需引用

(1).說明

  根據需要導入相應的組件和樣式

(2).步驟

 直接在對應頁面導入組件和組件的樣式,使用即可

<template>
    <div>
        <el-button>默認按鈕</el-button>
        <el-button type="primary">主要按鈕</el-button>
        <el-button type="success">成功按鈕</el-button>
        <el-button type="info">信息按鈕</el-button>
    </div>
</template>

<script lang="ts">
    import { defineComponent } from 'vue';
    import { ElButton } from 'element-plus';
    import 'element-plus/theme-chalk/el-button.css';
    export default defineComponent({
        components: {
            ElButton,
        },
        setup() {
        },
    });
</script>

<style lang="less"></style>

3. 按需引用-全局封裝

(1). 說明

 上述在每個頁面導入組件和組件的樣式過於繁瑣,所以這里將element-plus的組件封裝成全局,然后每個頁面直接使用即可,采用插件的形式進行封裝  (這里有個問題,高版本的按需導入樣式存在問題,這里的封裝僅僅按需導入插件,樣式使用的總樣式)

(2). 步驟 

A. 封裝register-element.ts文件(插件形式)

import { App } from 'vue';
import 'element-plus/dist/index.css'; //全局樣式
import { ElButton, ElCheckbox } from 'element-plus';
const components = [ElButton, ElCheckbox];

export default function (app: App): void {
    // 注冊全局組件
    for (const cItem of components) {
        app.component(cItem.name, cItem);
    }
}

B. 封裝global文件夾下的index.ts文件,統一出口

import { App } from 'vue';
import registerElement from './register-element';

// 插件的形式對外導出(函數模式)
export function golbalRegister(app: App): void {
    app.use(registerElement);
}

C. 在main.ts中進行導入

import { createApp } from 'vue';
import App from './App.vue';
// 按需引入element-plus
import { golbalRegister } from './global';

const app = createApp(App);
app.use(golbalRegister); // 按需引入element-plus

app.mount('#app');

D. 頁面中直接使用即可 

<template>
    <div>
        <el-button>默認按鈕</el-button>
        <el-button type="primary">主要按鈕</el-button>
        <el-button type="success">成功按鈕</el-button>
        <el-button type="info">信息按鈕</el-button>
    </div>
</template>

<script lang="ts">
    import { defineComponent } from 'vue';
    export default defineComponent({
        setup() {
        },
    });
</script>

<style lang="less"></style>

 

三. axios配置

1.  說明

 axios的詳細用法參考之前的文章:https://www.cnblogs.com/yaopengfei/p/12347199.html

 這里補充一個通過創建實例的方式進行請求Post表單提交(實際上axios對象也是一個實例)

import axios from 'axios';
const myAxiosInstance = axios.create({
    baseURL: 'http://xxxx:8002',
    timeout: 1000,
    headers: { 'X-Custom-Header': 'foobar' },
});
const params = new URLSearchParams();
params.append('userAccount', 'admin');
params.append('passWord', '122222');
myAxiosInstance
    .post('/Api/AdminApi_Areas/SysMainApi/CheckLogin', params)
    .then((res) => {
        console.log(res.data);
    })
    .catch((err) => {
        console.log(err);
    });

2. 封裝思路

 封裝1個類,然后創建一個實例,將實例進行對外導出,里面結合Element-plus的組件,進行請求加載效果的配置

類型聲明
import type { AxiosRequestConfig, AxiosResponse } from 'axios';
/* eslint-disable */
export interface HYRequestInterceptors<T = AxiosResponse> {
    requestInterceptor?: (config: AxiosRequestConfig) => AxiosRequestConfig;
    requestInterceptorCatch?: (error: any) => any;
    responseInterceptor?: (res: T) => T;
    responseInterceptorCatch?: (error: any) => any;
}

export interface HYRequestConfig<T = AxiosResponse> extends AxiosRequestConfig {
    interceptors?: HYRequestInterceptors<T>;
    showLoading?: boolean;
}
類的封裝
// 以類的方式來封裝axios
import axios, { AxiosInstance } from 'axios';
import type { HYRequestInterceptors, HYRequestConfig } from './type';
import { ElLoading, ILoadingInstance } from 'element-plus';

const DEAFULT_LOADING = true;

class HYRequest {
    instance: AxiosInstance;
    interceptors?: HYRequestInterceptors;
    showLoading: boolean;
    loading?: ILoadingInstance;

    constructor(config: HYRequestConfig) {
        // 創建axios實例
        this.instance = axios.create(config);

        // 保存基本信息
        this.showLoading = config.showLoading ?? DEAFULT_LOADING;
        this.interceptors = config.interceptors;

        // 使用攔截器
        // 1.從config中取出的攔截器是對應的實例的攔截器
        this.instance.interceptors.request.use(
            this.interceptors?.requestInterceptor,
            this.interceptors?.requestInterceptorCatch,
        );
        this.instance.interceptors.response.use(
            this.interceptors?.responseInterceptor,
            this.interceptors?.responseInterceptorCatch,
        );

        // 2.添加所有的實例都有的攔截器
        this.instance.interceptors.request.use(
            (config) => {
                if (this.showLoading) {
                    this.loading = ElLoading.service({
                        lock: true,
                        text: '正在請求數據....',
                        background: 'rgba(0, 0, 0, 0.5)',
                    });
                }
                return config;
            },
            (err) => {
                return err;
            },
        );
        this.instance.interceptors.response.use(
            (res) => {
                // 將loading移除
                this.loading?.close();

                const data = res.data;
                if (data.returnCode === '-1001') {
                    console.log('請求失敗~, 錯誤信息');
                } else {
                    return data;
                }
            },
            (err) => {
                // 將loading移除
                this.loading?.close();

                // 例子: 判斷不同的HttpErrorCode顯示不同的錯誤信息
                if (err.response.status === 404) {
                    console.log('404的錯誤~');
                }
                return err;
            },
        );
    }

    request<T>(config: HYRequestConfig<T>): Promise<T> {
        return new Promise((resolve, reject) => {
            // 1.單個請求對請求config的處理
            if (config.interceptors?.requestInterceptor) {
                config = config.interceptors.requestInterceptor(config);
            }

            // 2.判斷是否需要顯示loading
            if (config.showLoading === false) {
                this.showLoading = config.showLoading;
            }

            this.instance
                // eslint-disable-next-line @typescript-eslint/no-explicit-any
                .request<any, T>(config)
                .then((res) => {
                    // 1.單個請求對數據的處理
                    if (config.interceptors?.responseInterceptor) {
                        res = config.interceptors.responseInterceptor(res);
                    }
                    // 2.將showLoading設置true, 這樣不會影響下一個請求
                    this.showLoading = DEAFULT_LOADING;

                    // 3.將結果resolve返回出去
                    resolve(res);
                })
                .catch((err) => {
                    // 將showLoading設置true, 這樣不會影響下一個請求
                    this.showLoading = DEAFULT_LOADING;
                    reject(err);
                    return err;
                });
        });
    }

    get<T>(config: HYRequestConfig<T>): Promise<T> {
        return this.request<T>({ ...config, method: 'GET' });
    }

    post<T>(config: HYRequestConfig<T>): Promise<T> {
        return this.request<T>({ ...config, method: 'POST' });
    }

    delete<T>(config: HYRequestConfig<T>): Promise<T> {
        return this.request<T>({ ...config, method: 'DELETE' });
    }

    patch<T>(config: HYRequestConfig<T>): Promise<T> {
        return this.request<T>({ ...config, method: 'PATCH' });
    }
}

export default HYRequest;
View Code

 實例的封裝

// service統一出口
import HYRequest from './request';
import { BASE_URL, TIME_OUT } from './request/config';

const hyRequest = new HYRequest({
    baseURL: BASE_URL,
    timeout: TIME_OUT,
    // 實例級別的攔截器
    interceptors: {
        requestInterceptor: (config) => {
            console.log('請求成功的攔截');
            return config;
        },
        requestInterceptorCatch: (err) => {
            console.log('請求失敗的攔截');
            return err;
        },
        responseInterceptor: (res) => {
            console.log('響應成功的攔截');
            return res;
        },
        responseInterceptorCatch: (err) => {
            console.log('響應失敗的攔截');
            return err;
        },
    },
});

export default hyRequest;
View Code
測試
//測試自己封裝的axios
import hyRequest from './index';
// 下面是表單提交到參數封裝
const params = new URLSearchParams();
params.append('userAccount', 'admin');
params.append('passWord', '123456');
// 封裝返回值類型
interface DataType {
    status: string;
    msg: string;
    data: unknown;
}
hyRequest
    .post<DataType>({
        url: '/Api/AdminApi_Areas/SysMainApi/CheckLogin',
        data: params,
        // showLoading: false,
        // headers: {},
        // baseURL: '',
    })
    .then((res) => {
        console.log(res);
        console.log(res.status, res.msg, res.data);
    })
    .catch((err) => {
        console.log(err);
    });

 

四. vscode配置

 1. 在vscode中設置選項中,輸入配置,然后選擇settings.json,進行配置

 

2.  分享一個vscode的配置

{
  "workbench.iconTheme": "vscode-great-icons",
  "editor.fontSize": 17,
  "eslint.migration.2_x": "off",
  "[javascript]": {
    "editor.defaultFormatter": "dbaeumer.vscode-eslint"
  },
  "files.autoSave": "afterDelay",
  "editor.tabSize": 2,
  "terminal.integrated.fontSize": 16,
  "editor.renderWhitespace": "all",
  "editor.quickSuggestions": {
    "strings": true
  },
  "debug.console.fontSize": 15,
  "window.zoomLevel": 1,
  "emmet.includeLanguages": {
    "javascript": "javascriptreact"
  },
  "explorer.confirmDragAndDrop": false,
  "workbench.tree.indent": 16,
  "javascript.updateImportsOnFileMove.enabled": "always",
  "editor.wordWrap": "on",
  "path-intellisense.mappings": {
    "@": "${workspaceRoot}/src"
  },
  "hediet.vscode-drawio.local-storage": "eyIuZHJhd2lvLWNvbmZpZyI6IntcImxhbmd1YWdlXCI6XCJcIixcImN1c3RvbUZvbnRzXCI6W10sXCJsaWJyYXJpZXNcIjpcImdlbmVyYWw7YmFzaWM7YXJyb3dzMjtmbG93Y2hhcnQ7ZXI7c2l0ZW1hcDt1bWw7YnBtbjt3ZWJpY29uc1wiLFwiY3VzdG9tTGlicmFyaWVzXCI6W1wiTC5zY3JhdGNocGFkXCJdLFwicGx1Z2luc1wiOltdLFwicmVjZW50Q29sb3JzXCI6W1wiRkYwMDAwXCIsXCIwMENDNjZcIixcIm5vbmVcIixcIkNDRTVGRlwiLFwiNTI1MjUyXCIsXCJGRjMzMzNcIixcIjMzMzMzM1wiLFwiMzMwMDAwXCIsXCIwMENDQ0NcIixcIkZGNjZCM1wiLFwiRkZGRkZGMDBcIl0sXCJmb3JtYXRXaWR0aFwiOjI0MCxcImNyZWF0ZVRhcmdldFwiOmZhbHNlLFwicGFnZUZvcm1hdFwiOntcInhcIjowLFwieVwiOjAsXCJ3aWR0aFwiOjExNjksXCJoZWlnaHRcIjoxNjU0fSxcInNlYXJjaFwiOnRydWUsXCJzaG93U3RhcnRTY3JlZW5cIjp0cnVlLFwiZ3JpZENvbG9yXCI6XCIjZDBkMGQwXCIsXCJkYXJrR3JpZENvbG9yXCI6XCIjNmU2ZTZlXCIsXCJhdXRvc2F2ZVwiOnRydWUsXCJyZXNpemVJbWFnZXNcIjpudWxsLFwib3BlbkNvdW50ZXJcIjowLFwidmVyc2lvblwiOjE4LFwidW5pdFwiOjEsXCJpc1J1bGVyT25cIjpmYWxzZSxcInVpXCI6XCJcIn0ifQ==",
  "hediet.vscode-drawio.theme": "Kennedy",
  "editor.fontFamily": "Source Code Pro, 'Courier New', monospace",
  "editor.smoothScrolling": true,
  "editor.formatOnSave": true,
  "editor.defaultFormatter": "esbenp.prettier-vscode",
  "workbench.colorTheme": "Atom One Dark",
  "vetur.completion.autoImport": false,
  "security.workspace.trust.untrustedFiles": "open",
  "eslint.lintTask.enable": true,
  "eslint.alwaysShowStatus": true,
  "editor.codeActionsOnSave": {
    "source.fixAll.eslint": true
  }
}
View Code

 

五. 區分不同環境

1. 方案1-手動修改

(不可取)

//寫法1:每次手動改
const BASE_URL = 'https://www.ypf.org/test';
const BASE_NAME = 'ypf';
export { BASE_URL, BASE_NAME };

2. 方案2-根據process.env.NODE_ENV進行區分

(推薦)

原理:根據cli內置的一個值, process.env.NODE_ENV ,開發環境下為development,生產環境下為production,測試環境下為test,編寫一個config.ts文件,if判斷,從而對外導出。

分享config.ts代碼 

//寫法2:根據process.env.NODE_ENV進行區分
// 開發環境: development
// 生成環境: production
// 測試環境: test
let BASE_URL = '';
if (process.env.NODE_ENV === 'development') {
    BASE_URL = 'http://127.0.0.1:8000/';
} else if (process.env.NODE_ENV === 'production') {
    BASE_URL = 'http://ypf.org/prod';
} else {
    BASE_URL = 'http://ypf.org/test';
}
export { BASE_URL }; 

3. 方案3-編寫不同環境變量配置文件 

(推薦)

詳見:https://cli.vuejs.org/zh/guide/mode-and-env.html#模式

(1). 定義3個不同的文件,分別如下,這三個名稱是固定的,分別在里面定義變量。

  .env  (各種環境都可以獲取)

  .env.development  (開發環境獲取)

  .env.production        (生產環境獲取)

.env代碼如下:

/* 開發和生產環境都能獲取 */
VUE_APP_NAME=ypf0

.env.development 代碼如下:

VUE_APP_BASE_URL=https://ypf.org/dev
VUE_APP_BASE_NAME=ypf2

.env.production代碼如下:

VUE_APP_BASE_URL=https://ypf.org/prod
VUE_APP_BASE_NAME=ypf1

 特別注意:只有 NODE_ENV,BASE_URL 和以 VUE_APP_ 開頭的變量將通過 webpack.DefinePlugin 靜態地嵌入到客戶端側的代碼中。

(2). 測試代碼 

  需要用process.env.xxx進行調用

    export default defineComponent({
        setup() {// 測試寫法3
            console.log('測試寫法3');
            console.log(process.env.VUE_APP_BASE_URL);
            console.log(process.env.VUE_APP_BASE_NAME);
            console.log(process.env.VUE_APP_NAME);
        },
    });

 

 

 

 

 

 

 

!

  • 作       者 : Yaopengfei(姚鵬飛)
  • 博客地址 : http://www.cnblogs.com/yaopengfei/
  • 聲     明1 : 如有錯誤,歡迎討論,請勿謾罵^_^。
  • 聲     明2 : 原創博客請在轉載時保留原文鏈接或在文章開頭加上本人博客地址,否則保留追究法律責任的權利。
 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM