第二节:三方库集成和配置(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 : 原创博客请在转载时保留原文链接或在文章开头加上本人博客地址,否则保留追究法律责任的权利。
 
posted @ 2021-11-18 17:10  Yaopengfei  阅读(796)  评论(1编辑  收藏  举报