通俗易懂講解vue.config.js的配置參數(shù)

貼上官網(wǎng)
vue-cli3 創(chuàng)建的時(shí)候并不會(huì)自動(dòng)創(chuàng)建vue.config.js,因?yàn)檫@個(gè)是個(gè)可選項(xiàng),所以一般都是需要修改webpack的時(shí)候才會(huì)自己創(chuàng)建一個(gè)vue.config.js
再然后因?yàn)関ue-cli3內(nèi)部高度集成了webpack,一般來(lái)說(shuō)使用者不需要再去知道weboack做了什么,所以沒(méi)有暴露webpack的配置文件,我們可以手動(dòng)去創(chuàng)建vue.config.js 去修改默認(rèn)的webpack。注意,只能叫vue.config.js。

  • 在根目錄中創(chuàng)建 vue.config.js

    image.png

  • vue.config.js配置
    貼上我在項(xiàng)目中,用到的比較全的配置

"use strict";
const path = require("path");

function resolve(dir) {
  return path.join(__dirname, dir);
}

module.exports = {
  // 部署應(yīng)用時(shí)的基本 URL
  publicPath:
    process.env.NODE_ENV === "production"
      ? `/${process.env.VUE_APP_BASE_URL}`
      : "/",
  // build時(shí)構(gòu)建文件的目錄 構(gòu)建時(shí)傳入 --no-clean 可關(guān)閉該行為
  outputDir: "dist",
  // build時(shí)放置生成的靜態(tài)資源 (js、css、img、fonts) 的 (相對(duì)于 outputDir 的) 目錄
  assetsDir: "",
  // 指定生成的 index.html 的輸出路徑 (相對(duì)于 outputDir)。也可以是一個(gè)絕對(duì)路徑。
  indexPath: "index.html",
  // 默認(rèn)在生成的靜態(tài)資源文件名中包含hash以控制緩存
  filenameHashing: true,
  // 是否在開(kāi)發(fā)環(huán)境下通過(guò) eslint-loader 在每次保存時(shí) lint 代碼 (在生產(chǎn)構(gòu)建時(shí)禁用 eslint-loader)
  lintOnSave: process.env.NODE_ENV !== "production",
  // 是否使用包含運(yùn)行時(shí)編譯器的 Vue 構(gòu)建版本
  runtimeCompiler: false,
  // Babel 顯式轉(zhuǎn)譯列表
  transpileDependencies: [],
  // 設(shè)置生成的 HTML 中 <link rel="stylesheet"> 和 <script> 標(biāo)簽的 crossorigin 屬性(注:僅影響構(gòu)建時(shí)注入的標(biāo)簽)

  crossorigin: "",
  // 在生成的 HTML 中的 <link rel="stylesheet"> 和 <script> 標(biāo)簽上啟用 Subresource Integrity (SRI)
  integrity: false,
  // 如果這個(gè)值是一個(gè)對(duì)象,則會(huì)通過(guò) webpack-merge 合并到最終的配置中
  // 如果你需要基于環(huán)境有條件地配置行為,或者想要直接修改配置,那就換成一個(gè)函數(shù) (該函數(shù)會(huì)在環(huán)境變量被設(shè)置之后懶執(zhí)行)。該方法的第一個(gè)參數(shù)會(huì)收到已經(jīng)解析好的配置。在函數(shù)內(nèi),你可以直接修改配置,或者返回一個(gè)將會(huì)被合并的對(duì)象
  configureWebpack: { devtool: "source-map" },
  // 對(duì)內(nèi)部的 webpack 配置(比如修改、增加Loader選項(xiàng))(鏈?zhǔn)讲僮?
  productionSourceMap: process.env.NODE_ENV === "development", // 是否在構(gòu)建生產(chǎn)包時(shí)生成sourcdeMap
  // productionSourceMap: true, // 是否在構(gòu)建生產(chǎn)包時(shí)生成sourcdeMap
  chainWebpack: config => {
    config.entry("main").add("@babel/polyfill");
    config.plugin("html").tap(args => {
      args[0].title = "測(cè)試";
      return args;
    });
    config.resolve.alias.set("@", resolve("src"));
    const svgRule = config.module.rule("svg");
    // 清除已有的所有l(wèi)oader
    svgRule.uses.clear();
    svgRule
      .test(/\.svg$/)
      .include.add(path.resolve(__dirname, "./src/assets/icons"))
      .end()
      .use("svg-sprite-loader")
      .loader("svg-sprite-loader")
      .options({
        symbolId: "icon-[name]"
      });
  },
  // css的處理
  // 所有 webpack-dev-server 的選項(xiàng)都支持
  devServer: {
    host: "0.0.0.0", //局域網(wǎng)和本地訪問(wèn)
    port: "8089",
    hot: true,
    /* 自動(dòng)打開(kāi)瀏覽器 */
    open: false,
    overlay: {
      warning: false,
      error: true
    },
    /* 跨域代理 */
    proxy: {
      [process.env.VUE_APP_BASE_API]: {
        /* 目標(biāo)代理服務(wù)器地址 */
        // target: process.env.VUE_APP_BASE_URI, 
        target: "http://xxx/xx",
        /* 允許跨域 */
        changeOrigin: true,
        ws: true,
        pathRewrite: {
          // "^/dev-api": ""
          ["^" + process.env.VUE_APP_BASE_API]: ""
        }
      }
    }
  },
  // 是否為 Babel 或 TypeScript 使用 thread-loader
  parallel: require("os").cpus().length > 1,
  // 向 PWA 插件傳遞選項(xiàng)
  pwa: {},
  // 可以用來(lái)傳遞任何第三方插件選項(xiàng)
  pluginOptions: {},
  css: {
    loaderOptions: {
      postcss: {
        plugins: [
          require("postcss-pxtorem")({
            rootValue: 37.5, // 換算的基數(shù),數(shù)值具體看你的設(shè)計(jì)稿 另外提醒下vant-UI的官方根字體大小是37.5
            selectorBlackList: [], // 忽略轉(zhuǎn)換正則匹配項(xiàng)
            unitPrecision: 3,
            propList: ["*"], // 需要做轉(zhuǎn)化處理的屬性,如`hight`、`width`、`margin`等,`*`表示全部
            minPixelValue: 3 // 小于或等于`3px`不轉(zhuǎn)換為視窗單位
          })
        ]
      },
      less: {
        modifyVars: {
          hack: `true; @import "${resolve("./src/assets/styles/reset.less")}";`
        }
      }
    }
  }
};

配置選項(xiàng)解析

publicPath(從 Vue CLI 3.3 起已棄用baseUrl,請(qǐng)使用publicPath)
參考:https://my.oschina.net/u/4446873/blog/4882847

Type: string
Default: '/'
部署應(yīng)用包時(shí)的基本 URL, 用法和 webpack 本身的 output.publicPath 一致。
這個(gè)值也可以被設(shè)置為空字符串 ('') 或是相對(duì)路徑 ('./'),這樣所有的資源都會(huì)被鏈接為相對(duì)路徑,這樣打出來(lái)的包可以被部署在任意路徑。

默認(rèn)情況下,Vue CLI 會(huì)假設(shè)你的應(yīng)用是被部署在一個(gè)域名的根路徑上,例如https://www.xxx.com/。如果應(yīng)用被部署在一個(gè)子路徑上,你就需要用這個(gè)選項(xiàng)指定這個(gè)子路徑。例如,如果你的應(yīng)用被部署在https://www.xxx.com/my-app/,則設(shè)置 publicPath 為 /my-app/。

這個(gè)值在開(kāi)發(fā)環(huán)境下同樣生效。如果你想把開(kāi)發(fā)服務(wù)器架設(shè)在根路徑,你可以使用一個(gè)條件式的值:

module.exports={
    //基本路徑
    publicPath:process.env.NODE\_ENV=== 'production' ? '/haining-Admin/' : '/'
}

通常開(kāi)發(fā)環(huán)境,本地運(yùn)行都會(huì)直接部署在根路徑上,publicPath設(shè)置為'/',訪問(wèn)地址是你的IP地址。如下是設(shè)置成'/app'的效果:


image.png

從上面可以得知,靜態(tài)資源文件都是在app下的,所以在dist下新增添一個(gè)app目錄,把dist下文件放到app下,相當(dāng)于一個(gè)文件的路徑,可以發(fā)現(xiàn)項(xiàng)目會(huì)正常啟動(dòng)。一般nginx都會(huì)配置一個(gè)靜態(tài)資源目錄,打包后的文件都會(huì)放到這個(gè)靜態(tài)資源目錄里面,nginx去做映射,所以publicPath這個(gè)屬性基本不用改。'/'就行。

結(jié)論:publicPath配置成'/aaa/bbb/ccc', 則需在相應(yīng)的服務(wù)器路徑中新建aaa>bbb>ccc的文件夾,然后將打包后的文件放進(jìn)去,就ok啦。

項(xiàng)目中,我會(huì)在.env.production文件中設(shè)置一個(gè)變量VUE_APP_BASE_URL ,項(xiàng)目打包后告訴相關(guān)人員 nginx 路由前綴是什么即可

# nginx 路由前綴
VUE_APP_BASE_URL = 'ancientCms'

這里補(bǔ)充一下: base和publicpath
如果在history路由模式下,一般改配置的話(huà),兩個(gè)都要一起改。publicpath針對(duì)的是項(xiàng)目部署的路徑問(wèn)題, base針對(duì)的是頁(yè)面路由url的路徑問(wèn)題,缺一不可。

outputDir

Type: string
Default: 'dist'
輸出文件目錄,當(dāng)運(yùn)行 vue-cli-service build 時(shí)生成的生產(chǎn)環(huán)境構(gòu)建文件的目錄。注意目標(biāo)目錄在構(gòu)建之前會(huì)被清除 (構(gòu)建時(shí)傳入 --no-clean 可關(guān)閉該行為)。

module.exports={
    //build時(shí)構(gòu)建文件的目錄
    outputDir: "dist",
}

assetsDir

Type: string
Default: ''
build時(shí)放置生成的靜態(tài)資源 (js、css、img、fonts) 的 (相對(duì)于 outputDir 的) 目錄。
注:從生成的資源覆寫(xiě) filename 或 chunkFilename 時(shí),assetsDir 會(huì)被忽略。

module.exports={
   //build時(shí)放置靜態(tài)資源的目錄
    assetsDir: "static",
}

indexPath

Type: string
Default: 'index.html'
指定生成的 index.html 的輸出路徑 (相對(duì)于 outputDir)。也可以是一個(gè)絕對(duì)路徑。

module.exports={
   //html 的輸出路徑
    indexPath: "index.html",
}

filenameHashing

Type: boolean
Default: true
默認(rèn)情況下,生成的靜態(tài)資源在它們的文件名中包含了 hash 以便更好的控制緩存。然而,這也要求 index 的 HTML 是被 Vue CLI 自動(dòng)生成的。如果你無(wú)法使用 Vue CLI 生成的 index HTML,你可以通過(guò)將這個(gè)選項(xiàng)設(shè)為 false 來(lái)關(guān)閉文件名哈希

module.exports={
   //默認(rèn)在生成的靜態(tài)資源文件名中包含hash以控制緩存
    filenameHashing: true,
}

直觀效果:當(dāng)運(yùn)行npm run build時(shí),
打包后的文件后面都會(huì)帶一個(gè)8位的hash值,那啥是個(gè)hash值?


image.png

在打包出來(lái)的文件名上加上文件內(nèi)容的hash是目前最常見(jiàn)的有效使用瀏覽器長(zhǎng)緩存的方法,js文件如果有內(nèi)容更新,hash就會(huì)更新,瀏覽器請(qǐng)求路徑變化所以更新緩存,如果js內(nèi)容不變,hash不變,直接用緩存。(這段話(huà)是從別的文章里面參考的)。
將filenameHashing這個(gè)值設(shè)置為false試試,就不會(huì)帶那個(gè)后綴hash值。

pages

Type: Object
Default: undefined
在 multi-page(多頁(yè))模式下構(gòu)建應(yīng)用。每個(gè)“page”應(yīng)該有一個(gè)對(duì)應(yīng)的 JavaScript 入口文件。

module.exports={
  pages:{
    index:{
      //page的入口文件
      entry:'src/index/main.js',
      //模板文件
      template:'public/index.html',
      // 在 dist/index.html 的輸出
      filename:'index.html',
      //當(dāng)使用頁(yè)面titlt選項(xiàng)時(shí),
      // template 中的 title 標(biāo)簽需要是 <title><%= htmlWebpackPlugin.options.title %></title>
      title:'Index Page',
      // 在這個(gè)頁(yè)面中包含的塊,默認(rèn)情況下會(huì)包含
      // 提取出來(lái)的通用 chunk 和 vendor chunk。
      chunks:['chunk-vendors','chunk-common','index']
    },
    subpage:'src/subpage/main.js'
  },
}

lintOnSave

Type: boolean | 'warning' | 'default' | 'error'
Default: 'default'
是否在開(kāi)發(fā)環(huán)境下通過(guò) eslint-loader 在每次保存時(shí) lint 代碼。這個(gè)值會(huì)在 @vue/cli-plugin-eslint 被安裝之后生效。
設(shè)置為 true'warning' 時(shí),eslint-loader 會(huì)將 lint 錯(cuò)誤輸出為編譯警告。默認(rèn)情況下,警告僅僅會(huì)被輸出到命令行,且不會(huì)使得編譯失敗。

module.exports = {
  //是否在開(kāi)發(fā)環(huán)境下通過(guò) eslint-loader 在每次保存時(shí) lint 代碼 (在生產(chǎn)構(gòu)建時(shí)禁用 eslint-loader)
  lintOnSave: process.env.NODE_ENV !== 'production'
}

runtimeCompiler

Type: boolean
Default: false
是否使用包含運(yùn)行時(shí)編譯器的 Vue 構(gòu)建版本。設(shè)置為 true 后你就可以在 Vue 組件中使用 template 選項(xiàng)了,但是這會(huì)讓你的應(yīng)用額外增加 10kb 左右。

module.exports = {
  // 是否使用包含運(yùn)行時(shí)編譯器的 Vue 構(gòu)建版本
  runtimeCompiler: false,
}

transpileDependencies

Type: Array<string | RegExp>
Default: []
默認(rèn)情況下 babel-loader 會(huì)忽略所有 node_modules 中的文件。如果你想要通過(guò) Babel 顯式轉(zhuǎn)譯一個(gè)依賴(lài),可以在這個(gè)選項(xiàng)中列出來(lái)。

module.exports = {
// Babel 顯式轉(zhuǎn)譯列表
  transpileDependencies: [],
}

productionSourceMap

Type: boolean
Default: true
如果你不需要生產(chǎn)環(huán)境的 source map,可以將其設(shè)置為 false 以加速生產(chǎn)環(huán)境構(gòu)建。

module.exports = {
  // 是否在構(gòu)建生產(chǎn)包時(shí)生成sourcdeMap
  productionSourceMap: process.env.NODE_ENV === "development", 
}

crossorigin(不理解)

Type: string
Default: undefined
設(shè)置生成的 HTML 中 <link rel="stylesheet"> 和 <script> 標(biāo)簽的 crossorigin 屬性。
需要注意的是該選項(xiàng)僅影響由 html-webpack-plugin 在構(gòu)建時(shí)注入的標(biāo)簽 - 直接寫(xiě)在模版 (public/index.html) 中的標(biāo)簽不受影響。

module.exports = {
// 設(shè)置生成的 HTML 中 <link rel="stylesheet"> 和 <script> 標(biāo)簽的 crossorigin 屬性(注:僅影響構(gòu)建時(shí)注入的標(biāo)簽)
  crossorigin: "",
}

integrity

Type: boolean
Default: false
在生成的 HTML 中的 <link rel="stylesheet"> 和 <script> 標(biāo)簽上啟用 Subresource Integrity (SRI)。如果你構(gòu)建后的文件是部署在 CDN 上的,啟用該選項(xiàng)可以提供額外的安全性。

module.exports = {
  // 在生成的 HTML 中的 <link rel="stylesheet"> 和 <script> 標(biāo)簽上啟用 Subresource Integrity (SRI)
  integrity: false,
}
  • Webpack相關(guān)配置

configureWebpack

Type: Object | Function
除了上述使用 chainWebpack 來(lái)改變 webpack 內(nèi)部配置外,我們還可以使用 configureWebpack 來(lái)進(jìn)行修改,兩者的不同點(diǎn)在于 chainWebpack 是鏈?zhǔn)叫薷模?configureWebpack 更傾向于整體替換和修改。

 configureWebpack: { devtool: "source-map" },

chainWebpack

Type: Object | Function
chainWebpack 配置項(xiàng)允許我們更細(xì)粒度的控制 webpack 的內(nèi)部配置,其集成的是 webpack-chain這一插件,該插件可以讓我們能夠使用鏈?zhǔn)讲僮鱽?lái)修改配置

 chainWebpack: config => {
    config.resolve.alias
      .set('common', resolve('src/common'))
      .set('components', resolve('src/components'))
      .set('http', resolve('src/http'))
      .set('base', resolve('src/base'))
      .set('views', resolve('src/views'))
      .set('store', resolve('src/store'))
      .set('filters', resolve('src/filters'))
      .set('directives', resolve('src/directives'))
      .set('router', resolve('src/router'));

    config.plugin('preload').tap(() => [
      {
        rel: 'preload',
        fileBlacklist: [/\.map$/, /hot-update\.js$/, /runtime\..*\.js$/],
        include: 'initial',
      },
    ]);

    config.plugins.delete('prefetch');
    config.plugin('provide').use(webpack.ProvidePlugin, [{
      'window.Quill': 'quill'
    }])
  },

Css相關(guān)配置

 css: {
    loaderOptions: {
      postcss: {
        plugins: [
          require("postcss-pxtorem")({
            rootValue: 37.5, // 換算的基數(shù),數(shù)值具體看你的設(shè)計(jì)稿 另外提醒下vant-UI的官方根字體大小是37.5
            selectorBlackList: [], // 忽略轉(zhuǎn)換正則匹配項(xiàng)
            unitPrecision: 3,
            propList: ["*"], // 需要做轉(zhuǎn)化處理的屬性,如`hight`、`width`、`margin`等,`*`表示全部
            minPixelValue: 3 // 小于或等于`3px`不轉(zhuǎn)換為視窗單位
          })
        ]
      },
      less: {
        modifyVars: {
          hack: `true; @import "${resolve("./src/assets/styles/reset.less")}";`
        }
      }
    }
  }

devServer
如果你的前端應(yīng)用和后端 API 服務(wù)器沒(méi)有運(yùn)行在同一個(gè)主機(jī)上,你需要在開(kāi)發(fā)環(huán)境下將 API 請(qǐng)求代理到 API 服務(wù)器。這個(gè)問(wèn)題可以通過(guò) vue.config.js 中的 devServer.proxy 選項(xiàng)來(lái)配置。
補(bǔ)充知識(shí)
所謂的跨域就是不同源,不滿(mǎn)足協(xié)議、域名、端口都相同的約定
http://www.test.com/dir/login.html 同源
https://www.test.com/index.html 不同源 協(xié)議不同(https)
http://www.test.com:90/index.html 不同源 端口不同(90)
http://www.demo.com/index.html 不同源 域名不同(demo)
當(dāng)協(xié)議、域名、端口中任意一個(gè)不相同時(shí),就是不同源。若不同源之間相互請(qǐng)求資源,就算作跨域
補(bǔ)充知識(shí)
反向代理(Reverse Proxy)方式是指以代理服務(wù)器來(lái)接受網(wǎng)絡(luò)上的連接請(qǐng)求,然后將請(qǐng)求轉(zhuǎn)發(fā)給內(nèi)部網(wǎng)絡(luò)上的服務(wù)器,并將服務(wù)器上得到的結(jié)果返回給請(qǐng)求連接的客戶(hù)端,此時(shí)代理服務(wù)器對(duì)外就表現(xiàn)為一個(gè)反向代理服務(wù)器。客戶(hù)端無(wú)需做任何配置。
修改config/index.js /vue.config.js文件(改完之后千萬(wàn)記得要重新 npm run dev)

module.exports = {
   devServer: {
    host: "0.0.0.0", //同一局域網(wǎng)下可以用前端的本地地址訪問(wèn)
    port: "7978",
    hot: true,
    /* 自動(dòng)打開(kāi)瀏覽器 */
    open: false,
    overlay: {
      warning: false,
      error: true
    },
    /* 跨域代理 */
    proxy: {
      [process.env.VUE_APP_BASE_API]: {
        /* 目標(biāo)代理服務(wù)器地址 */
        // target: process.env.VUE_APP_BASE_URI, //
        target: "http://xxx/xx", //
        /* 允許跨域 */
        changeOrigin: true,
        ws: true,
        pathRewrite: {
          // "^/dev-api": ""
          ["^" + process.env.VUE_APP_BASE_API]: ""
        }
      }
    }
  },
}
derServer下的參數(shù)配置

host 將他的值修改為 0.0.0.0,代表可以訪問(wèn)本機(jī)所有的IP地址,讓vue項(xiàng)目可通過(guò)localhost和IP同時(shí)訪問(wèn)。

Type: string
Default: localhost
作用:用于指定devDerve使用的host。

port 設(shè)置端口號(hào)

Type: number
作用: 指定要監(jiān)聽(tīng)請(qǐng)求的端口號(hào)

open 是否在第一次編譯時(shí)是自動(dòng)打開(kāi)瀏覽器

Type: boolean | string
Default: false
作用:用于設(shè)置 server 啟動(dòng)后是否自動(dòng)打開(kāi)瀏覽器。

hot 開(kāi)啟為true,啟動(dòng)熱重載,自動(dòng)刷新頁(yè)面

Type: boolean | string
Default: true
作用:用于設(shè)置代碼保存時(shí)是否進(jìn)行熱更新(局部刷新,不刷新整個(gè)頁(yè)面)。
hot和hotOnly的區(qū)別

  1. hot: true
    單純?cè)O(shè)置為true的時(shí)候,如果編譯報(bào)錯(cuò),會(huì)拋出錯(cuò)誤,你重新改成正確的,這個(gè)時(shí)候又會(huì)觸發(fā)重新編譯,整個(gè)瀏覽器會(huì)重新刷新!
  2. hotOnly: true
    這個(gè)也設(shè)置的話(huà),如果編譯報(bào)錯(cuò),你再改成正確的,重新編譯,瀏覽器不會(huì)刷新!
    區(qū)別在于,刷新,有些復(fù)現(xiàn)步驟比較復(fù)雜的話(huà),刷掉了瀏覽器,要一步步重新點(diǎn)。
    hot 和 hotOnly 的區(qū)別是在某些模塊不支持熱更新的情況下,前者會(huì)自動(dòng)刷新頁(yè)面,后者不會(huì)刷新頁(yè)面,而是在控制臺(tái)輸出熱更新失敗

https

Type: boolean | object
Default: false
作用:用于設(shè)置是否啟用https

inline

Type: boolean | string
Default: true
作用:用于設(shè)置代碼保存時(shí)是否自動(dòng)刷新頁(yè)面。

overlay

 overlay: { // 錯(cuò)誤、警告在頁(yè)面彈出
      warning: false,
      error: true
    },
proxy下的參數(shù)配置
    /* 跨域代理 */
    proxy: {
      '/api/': {
        /* 目標(biāo)代理服務(wù)器地址 */
        target: "http://localhost:8080", //
        /* 允許跨域 */
        changeOrigin: true,
        ws: true,
        pathRewrite: {
          '^/api/': ""
        }
      }
    }

targe 代理的服務(wù)器,也就是api要訪問(wèn)的服務(wù)器。
changeOrigin 允許跨域, 為false時(shí),請(qǐng)求頭中host仍然是瀏覽器發(fā)送過(guò)來(lái)的host;如果設(shè)置成true:發(fā)送請(qǐng)求頭中host會(huì)設(shè)置成target的值
ws 是否代理websocket
pathRewrite 重寫(xiě) url 的 path 部分

問(wèn):pathRewrite里面的'^/api/'是什么意思?
答:用代理,首先你得有一個(gè)標(biāo)識(shí),告訴他,帶有/api/的連接要用代理,不然可能html,css,js這些靜態(tài)資源都跑去代理。所以我們只要接口用代理,靜態(tài)文件用本地。
'/api/':{},就是告訴node,我接口只要是'/api/'開(kāi)頭的才用代理,所以你的接口就要這么寫(xiě):'/api/xx/xx',最后代理的路徑就是:http://xxx.xx.com/api/xx/xx
可是不對(duì)啊,正確的接口路徑里面沒(méi)有/api啊,所以就需要pathRewrite,用 '^/api/':'',把/api給去掉,這樣既能有正確的表示,又能在請(qǐng)求接口的時(shí)候去掉api。

此文記錄下來(lái),方便自己遺忘的時(shí)候能夠快速查閱,如有錯(cuò)誤請(qǐng)指出。

參考鏈接:
http://www.lxweimin.com/p/b358a91bdf2d
https://www.jb51.net/article/174200.htm
https://blog.csdn.net/liu_yunzhao/article/details/90520028

這篇文章講的也很詳細(xì)https://blog.csdn.net/guozhangqiang/article/details/87197870

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容