vue-cli webpack配置文件分析


Posted in Javascript onMay 20, 2019

相信vue使用者对vue-cli都不会陌生,甚至可以说,很熟悉了,但对其webpack的配置可能知之甚少吧。

过完年回来后,我接手了公司的新项目。新项目是一个spa。很自然,我就想到了vue-cli脚手架了,当时研究一下它的webpack配置。于是,就有了其他的内容。

今天这篇文章,是在原来的基础上,增加了一些新版本的内容,但实质上变化不大。

说明

此仓库为vue-cli webpack的配置分析,其实只是在源码中加上注释而已。大家查看详细分析,可以从后面提到的入口文件开始查看。

分析不包括check-versions.js文件,因为check-versions.js是检测npm和node版本,不涉及webpack,所以就没有对check-versions.js进行分析。同时,也不包括测试部分的代码,该分析只是针对开发和生产环境的webpack配置进行分析。

vue-cli 版本

2.8.1

入口

从package.json可以看到开发和生产环境的入口。

"scripts": {
  "dev": "node build/dev-server.js",
  "build": "node build/build.js"
 }

开发环境

开发环境的入口文件是 build/dev-server.js。

dev-server.js

该文件中,使用express作为后端框架,结合一些关于webpack的中间件,搭建了一个开发环境。

// 配置文件
var config = require('../config')
// 如果 Node 的环境无法判断当前是 dev / product 环境
// 使用 config.dev.env.NODE_ENV 作为当前的环境
if (!process.env.NODE_ENV) {
 process.env.NODE_ENV = JSON.parse(config.dev.env.NODE_ENV)
}

// 可以强制打开浏览器并跳转到指定 url 的插件
// https://github.com/sindresorhus/opn
var opn = require('opn')
// node自带的文件路径工具
var path = require('path')
// express框架
var express = require('express')
var webpack = require('webpack')
// 测试环境,使用的配置与生产环境的配置一样
// 非测试环境,即为开发环境,因为此文件只有测试环境和开发环境使用
var proxyMiddleware = require('http-proxy-middleware')
var webpackConfig = process.env.NODE_ENV === 'testing'
// 生产环境配置文件
 ? require('./webpack.prod.conf')
 // 开发环境配置文件
 : require('./webpack.dev.conf')

// 端口号为命令行输入的PORT参数或者配置文件中的默认值
var port = process.env.PORT || config.dev.port
// 配置文件中 是否自动打开浏览器
var autoOpenBrowser = !!config.dev.autoOpenBrowser
// 配置文件中 http代理配置
// https://github.com/chimurai/http-proxy-middleware
var proxyTable = config.dev.proxyTable

// 启动 express 服务
var app = express()
// 启动 webpack 编译
var compiler = webpack(webpackConfig)

// 可以将编译后的文件暂存到内存中的插件
// https://github.com/webpack/webpack-dev-middleware
var devMiddleware = require('webpack-dev-middleware')(compiler, {
 // 公共路径,与webpack的publicPath一样
 publicPath: webpackConfig.output.publicPath,
 // 不打印
 quiet: true
})

// Hot-reload 热重载插件
// https://github.com/glenjamin/webpack-hot-middleware
var hotMiddleware = require('webpack-hot-middleware')(compiler, {
 log: () => {}
})
// 当tml-webpack-plugin template更改之后,强制刷新浏览器
compiler.plugin('compilation', function (compilation) {
 compilation.plugin('html-webpack-plugin-after-emit', function (data, cb) {
  hotMiddleware.publish({ action: 'reload' })
  cb()
 })
})

// 将 proxyTable 中的请求配置挂在到启动的 express 服务上
Object.keys(proxyTable).forEach(function (context) {
 var options = proxyTable[context]
 // 如果options的数据类型为string,则表示只设置了url,
 // 所以需要将url设置为对象中的 target的值
 if (typeof options === 'string') {
  options = { target: options }
 }
 app.use(proxyMiddleware(options.filter || context, options))
})

// 使用 connect-history-api-fallback 匹配资源
// 如果不匹配就可以重定向到指定地址
// https://github.com/bripkens/connect-history-api-fallback
app.use(require('connect-history-api-fallback')())

// 将暂存到内存中的 webpack 编译后的文件挂在到 express 服务上
app.use(devMiddleware)

// 将 Hot-reload 挂在到 express 服务上
app.use(hotMiddleware)

// 拼接 static 文件夹的静态资源路径
var staticPath = path.posix.join(config.dev.assetsPublicPath, config.dev.assetsSubDirectory)
// 静态文件服务
app.use(staticPath, express.static('./static'))

var uri = 'http://localhost:' + port

// 编译成功后打印网址信息
devMiddleware.waitUntilValid(function () {
 console.log('> Listening at ' + uri + '\n')
})

module.exports = app.listen(port, function (err) {
 if (err) {
  console.log(err)
  return
 }

 // 如果配置了自动打开浏览器,且不是测试环境,则自动打开浏览器并跳到我们的开发地址
 if (autoOpenBrowser && process.env.NODE_ENV !== 'testing') {
  opn(uri)
 }
})

webpack.dev.conf.js

dev-server.js中使用了webpack.dev.conf.js文件,该文件是开发环境中webpack的配置入口。

// 工具函数集合
var utils = require('./utils')
var webpack = require('webpack')
 // 配置文件
var config = require('../config')
 // webpack 配置合并插件
var merge = require('webpack-merge')
 // webpac基本配置
var baseWebpackConfig = require('./webpack.base.conf')
 // 自动生成 html 并且注入到 .html 文件中的插件
 // https://github.com/ampedandwired/html-webpack-plugin
var HtmlWebpackPlugin = require('html-webpack-plugin')
 // webpack错误信息提示插件
 // https://github.com/geowarin/friendly-errors-webpack-plugin
var FriendlyErrorsPlugin = require('friendly-errors-webpack-plugin')

// 将 Hol-reload 热重载的客户端代码添加到 webpack.base.conf 的 对应 entry 中,一起打包
Object.keys(baseWebpackConfig.entry).forEach(function(name) {
 baseWebpackConfig.entry[name] = ['./build/dev-client'].concat(baseWebpackConfig.entry[name])
})

module.exports = merge(baseWebpackConfig, {
 module: {
  // styleLoaders
  rules: utils.styleLoaders({ sourceMap: config.dev.cssSourceMap })
 },
 // 最新的配置为 cheap-module-eval-source-map,虽然 cheap-module-eval-source-map更快,但它的定位不准确
 // 所以,换成 eval-source-map
 devtool: '#eval-source-map',
 plugins: [
  // definePlugin 接收字符串插入到代码当中, 所以你需要的话可以写上 JS 的字符串
  // 此处,插入适当的环境
  // https://webpack.js.org/plugins/define-plugin/
  new webpack.DefinePlugin({
   'process.env': config.dev.env
  }),
  // HotModule 插件在页面进行变更的时候只会重绘对应的页面模块,不会重绘整个 html 文件
  // https://github.com/glenjamin/webpack-hot-middleware#installation--usage
  new webpack.HotModuleReplacementPlugin(),
  new webpack.NoEmitOnErrorsPlugin(),
  // 将 index.html 作为入口,注入 html 代码后生成 index.html文件
  // https://github.com/ampedandwired/html-webpack-plugin
  new HtmlWebpackPlugin({
   filename: 'index.html',
   template: 'index.html',
   inject: true
  }),
  // webpack错误信息提示插件
  new FriendlyErrorsPlugin()
 ]
})

webpack.base.conf.js

在webpack.dev.conf.js中出现webpack.base.conf.js,这个文件是开发环境和生产环境,甚至测试环境,这些环境的公共webpack配置。可以说,这个文件相当重要。

// node自带的文件路径工具
var path = require('path')
// 工具函数集合
var utils = require('./utils')
 // 配置文件
var config = require('../config')
 // 工具函数集合
var vueLoaderConfig = require('./vue-loader.conf')

/**
 * 获得绝对路径
 * @method resolve
 * @param {String} dir 相对于本文件的路径
 * @return {String}   绝对路径
 */
function resolve(dir) {
 return path.join(__dirname, '..', dir)
}

module.exports = {
 entry: {
  app: './src/main.js'
 },
 output: {
  // 编译输出的静态资源根路径
  path: config.build.assetsRoot,
  // 编译输出的文件名
  filename: '[name].js',
  // 正式发布环境下编译输出的上线路径的根路径
  publicPath: process.env.NODE_ENV === 'production' ?
   config.build.assetsPublicPath : config.dev.assetsPublicPath
 },
 resolve: {
  // 自动补全的扩展名
  extensions: ['.js', '.vue', '.json'],
  // 路径别名
  alias: {
   // 例如 import Vue from 'vue',会自动到 'vue/dist/vue.common.js'中寻找
   'vue$': 'vue/dist/vue.esm.js',
   '@': resolve('src'),
  }
 },
 module: {
  rules: [{
    // 审查 js 和 vue 文件
    // https://github.com/MoOx/eslint-loader
    test: /\.(js|vue)$/,
    loader: 'eslint-loader',
    // 表示预先处理
    enforce: "pre",
    include: [resolve('src'), resolve('test')],
    options: {
     formatter: require('eslint-friendly-formatter')
    }
   },
   {
    // 处理 vue文件
    // https://github.com/vuejs/vue-loader
    test: /\.vue$/,
    loader: 'vue-loader',
    options: vueLoaderConfig
   },
   {
    // 编译 js
    // https://github.com/babel/babel-loader
    test: /\.js$/,
    loader: 'babel-loader',
    include: [resolve('src'), resolve('test')]
   },
   {
    // 处理图片文件
    // https://github.com/webpack-contrib/url-loader
    test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
    loader: 'url-loader',
    query: {
     limit: 10000,
     name: utils.assetsPath('img/[name].[hash:7].[ext]')
    }
   },
   {
    // 处理字体文件
    test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
    loader: 'url-loader',
    query: {
     limit: 10000,
     name: utils.assetsPath('fonts/[name].[hash:7].[ext]')
    }
   }
  ]
 }
}

config/index.js

该文件在很多文件中都用到,是主要的配置文件,包含静态文件的路径、是否开启sourceMap等。其中,分为两个部分dev(开发环境的配置)和build(生产环境的配置)。

// 详情见文档:https://vuejs-templates.github.io/webpack/env.html
var path = require('path')

module.exports = {
 // production 生产环境
 build: {
  // 构建环境
  env: require('./prod.env'),
  // 构建输出的index.html文件
  index: path.resolve(__dirname, '../dist/index.html'),
  // 构建输出的静态资源路径
  assetsRoot: path.resolve(__dirname, '../dist'),
  // 构建输出的二级目录
  assetsSubDirectory: 'static',
  // 构建发布的根目录,可配置为资源服务器域名或 CDN 域名
  assetsPublicPath: '/',
  // 是否开启 cssSourceMap
  productionSourceMap: true,
  // Gzip off by default as many popular static hosts such as
  // Surge or Netlify already gzip all static assets for you.
  // Before setting to `true`, make sure to:
  // npm install --save-dev compression-webpack-plugin
  // 默认关闭 gzip,因为很多流行的静态资源主机,例如 Surge、Netlify,已经为所有静态资源开启gzip
  productionGzip: false,
  // 需要使用 gzip 压缩的文件扩展名
  productionGzipExtensions: ['js', 'css'],
  // Run the build command with an extra argument to
  // View the bundle analyzer report after build finishes:
  // `npm run build --report`
  // Set to `true` or `false` to always turn it on or off
  // 运行“build”命令行时,加上一个参数,可以在构建完成后参看包分析报告
  // true为开启,false为关闭
  bundleAnalyzerReport: process.env.npm_config_report
 },
 // dev 开发环境
 dev: {
  // 构建环境
  env: require('./dev.env'),
  // 端口号
  port: 3333,
  // 是否自动打开浏览器
  autoOpenBrowser: true,
  assetsSubDirectory: 'static',
  // 编译发布的根目录,可配置为资源服务器域名或 CDN 域名
  assetsPublicPath: '/',
  // proxyTable 代理的接口(可跨域)
  // 使用方法:https://vuejs-templates.github.io/webpack/proxy.html
  proxyTable: {},
  // CSS Sourcemaps off by default because relative paths are "buggy"
  // with this option, according to the CSS-Loader README
  // (https://github.com/webpack/css-loader#sourcemaps)
  // In our experience, they generally work as expected,
  // just be aware of this issue when enabling this option.
  // 默认情况下,关闭 CSS Sourcemaps,因为使用相对路径会报错。
  // CSS-Loader README:https://github.com/webpack/css-loader#sourcemaps
  cssSourceMap: false
 }
}

utils.js

utils.js也是一个被使用频率的文件,这个文件包含了三个工具函数:

  • 生成静态资源的路径
  • 生成 ExtractTextPlugin对象或loader字符串
  • 生成 style-loader的配置
// node自带的文件路径工具
var path = require('path')
// 配置文件
var config = require('../config')
// 提取css的插件
// https://github.com/webpack-contrib/extract-text-webpack-plugin
var ExtractTextPlugin = require('extract-text-webpack-plugin')

/**
 * 生成静态资源的路径
 * @method assertsPath
 * @param {String}  _path 相对于静态资源文件夹的文件路径
 * @return {String}     静态资源完整路径
 */
exports.assetsPath = function (_path) {
 var assetsSubDirectory = process.env.NODE_ENV === 'production'
  ? config.build.assetsSubDirectory
  : config.dev.assetsSubDirectory
  // path.posix.join与path.join一样,不过总是以 posix 兼容的方式交互
 return path.posix.join(assetsSubDirectory, _path)
}

/**
 * 生成处理css的loaders配置
 * @method cssLoaders
 * @param {Object}  options 生成配置
 *              option = {
 *               // 是否开启 sourceMap
 *               sourceMap: true,
 *               // 是否提取css
 *               extract: true
 *              }
 * @return {Object}      处理css的loaders配置对象
 */
exports.cssLoaders = function (options) {
 options = options || {}

 var cssLoader = {
  loader: 'css-loader',
  options: {
   minimize: process.env.NODE_ENV === 'production',
   sourceMap: options.sourceMap
  }
 }
 /**
  * 生成 ExtractTextPlugin对象或loader字符串
  * @method generateLoaders
  * @param {Array}    loaders loader名称数组
  * @return {String|Object}    ExtractTextPlugin对象或loader字符串
  */
 function generateLoaders (loader, loaderOptions) {
  var loaders = [cssLoader]
  if (loader) {
   loaders.push({
    // 例如,sass?indentedSyntax
    // 在?号前加上“-loader”
    loader: loader + '-loader',
    options: Object.assign({}, loaderOptions, {
     sourceMap: options.sourceMap
    })
   })
  }

  // extract为true时,提取css
  // 生产环境中,默认为true
  if (options.extract) {
   return ExtractTextPlugin.extract({
    use: loaders,
    fallback: 'vue-style-loader'
   })
  } else {
   return ['vue-style-loader'].concat(loaders)
  }
 }

 // http://vuejs.github.io/vue-loader/en/configurations/extract-css.html
 return {
  css: generateLoaders(),
  postcss: generateLoaders(),
  less: generateLoaders('less'),
  sass: generateLoaders('sass', { indentedSyntax: true }),
  scss: generateLoaders('sass'),
  stylus: generateLoaders('stylus'),
  styl: generateLoaders('stylus')
 }
}

/**
 * 生成 style-loader的配置
 * style-loader文档:https://github.com/webpack/style-loader
 * @method styleLoaders
 * @param {Object}   options 生成配置
 *               option = {
 *                // 是否开启 sourceMap
 *                sourceMap: true,
 *                // 是否提取css
 *                extract: true
 *               }
 * @return {Array}       style-loader的配置
 */
exports.styleLoaders = function (options) {
 var output = []
 var loaders = exports.cssLoaders(options)
 for (var extension in loaders) {
  var loader = loaders[extension]
  output.push({
   test: new RegExp('\\.' + extension + '$'),
   use: loader
  })
 }
 return output
}

生产环境

开发环境的入口文件是build/build.js 。

build.js

该文件,为构建打包文件,会将源码进行构建(编译、压缩等)后打包。

// 设置当前环境为生产环境
process.env.NODE_ENV = 'production'

// loading 插件
// https://github.com/sindresorhus/ora
var ora = require('ora')
// 可以在 node 中执行`rm -rf`的工具
// https://github.com/isaacs/rimraf
var rm = require('rimraf')
// node自带的文件路径工具
var path = require('path')
// 在终端输出带颜色的文字
// https://github.com/chalk/chalk
var chalk = require('chalk')
var webpack = require('webpack')
// 配置文件
var config = require('../config')
var webpackConfig = require('./webpack.prod.conf')

// 在终端显示loading效果,并输出提示
var spinner = ora('building for production...')
spinner.start()

// 删除这个文件夹 (递归删除)
rm(path.join(config.build.assetsRoot, config.build.assetsSubDirectory), err => {
 if (err) throw err
 // 构建
 webpack(webpackConfig, function (err, stats) {
  // 构建成功

  // 停止 loading动画
  spinner.stop()
  if (err) throw err
  process.stdout.write(stats.toString({
   colors: true,
   modules: false,
   children: false,
   chunks: false,
   chunkModules: false
  }) + '\n\n')

  // 打印提示
  console.log(chalk.cyan(' Build complete.\n'))
  console.log(chalk.yellow(
   ' Tip: built files are meant to be served over an HTTP server.\n' +
   ' Opening index.html over file:// won\'t work.\n'
  ))
 })
})

webpack.prod.conf

该文件,为生产环境中webpack的配置入口。同时,它也依赖于前面提到的webpack.base.conf.js、utils.js和config/index.js。

// node自带的文件路径工具
var path = require('path')
// 工具函数集合
var utils = require('./utils')
var webpack = require('webpack')
// 配置文件
var config = require('../config')
// webpack 配置合并插件
var merge = require('webpack-merge')
// webpack 基本配置
var baseWebpackConfig = require('./webpack.base.conf')
// webpack 复制文件和文件夹的插件
// https://github.com/kevlened/copy-webpack-plugin
var CopyWebpackPlugin = require('copy-webpack-plugin')
// 自动生成 html 并且注入到 .html 文件中的插件
// https://github.com/ampedandwired/html-webpack-plugin
var HtmlWebpackPlugin = require('html-webpack-plugin')
// 提取css的插件
// https://github.com/webpack-contrib/extract-text-webpack-plugin
var ExtractTextPlugin = require('extract-text-webpack-plugin')
// webpack 优化压缩和优化 css 的插件
// https://github.com/NMFR/optimize-css-assets-webpack-plugin
var OptimizeCSSPlugin = require('optimize-css-assets-webpack-plugin')

// 如果当前环境为测试环境,则使用测试环境
// 否则,使用生产环境
var env = process.env.NODE_ENV === 'testing'
 ? require('../config/test.env')
 : config.build.env

var webpackConfig = merge(baseWebpackConfig, {
 module: {
  // styleLoaders
  rules: utils.styleLoaders({
   sourceMap: config.build.productionSourceMap,
   extract: true
  })
 },
 // 是否开启 sourceMap
 devtool: config.build.productionSourceMap ? '#source-map' : false,
 output: {
  // 编译输出的静态资源根路径
  path: config.build.assetsRoot,
  // 编译输出的文件名
  filename: utils.assetsPath('js/[name].[chunkhash].js'),
  // 没有指定输出名的文件输出的文件名
  chunkFilename: utils.assetsPath('js/[id].[chunkhash].js')
 },
 plugins: [
  // definePlugin 接收字符串插入到代码当中, 所以你需要的话可以写上 JS 的字符串
  // 此处,插入适当的环境
  // http://vuejs.github.io/vue-loader/en/workflow/production.html
  new webpack.DefinePlugin({
   'process.env': env
  }),
  // 压缩 js
  new webpack.optimize.UglifyJsPlugin({
   compress: {
    warnings: false
   },
   sourceMap: true
  }),
  // 提取 css
  new ExtractTextPlugin({
   filename: utils.assetsPath('css/[name].[contenthash].css')
  }),
  // 压缩提取出来的 css
  // 可以删除来自不同组件的冗余代码
  // Compress extracted CSS. We are using this plugin so that possible
  // duplicated CSS from different components can be deduped.
  new OptimizeCSSPlugin(),
  // 将 index.html 作为入口,注入 html 代码后生成 index.html文件
  // https://github.com/ampedandwired/html-webpack-plugin
  new HtmlWebpackPlugin({
   filename: process.env.NODE_ENV === 'testing'
    ? 'index.html'
    : config.build.index,
   template: 'index.html',
   inject: true,
   minify: {
    removeComments: true,
    collapseWhitespace: true,
    removeAttributeQuotes: true
    // 更多选项 https://github.com/kangax/html-minifier#options-quick-reference
   },
   // 必须通过 CommonsChunkPlugin一致地处理多个 chunks
   chunksSortMode: 'dependency'
  }),
  // 分割公共 js 到独立的文件
  // https://webpack.js.org/guides/code-splitting-libraries/#commonschunkplugin
  new webpack.optimize.CommonsChunkPlugin({
   name: 'vendor',
   minChunks: function (module, count) {
    // node_modules中的任何所需模块都提取到vendor
    return (
     module.resource &&
     /\.js$/.test(module.resource) &&
     module.resource.indexOf(
      path.join(__dirname, '../node_modules')
     ) === 0
    )
   }
  }),
  // 将webpack runtime 和模块清单 提取到独立的文件,以防止当 app包更新时导致公共 jsd hash也更新
  // extract webpack runtime and module manifest to its own file in order to
  // prevent vendor hash from being updated whenever app bundle is updated
  new webpack.optimize.CommonsChunkPlugin({
   name: 'manifest',
   chunks: ['vendor']
  }),
  // 复制静态资源
  // https://github.com/kevlened/copy-webpack-plugin
  new CopyWebpackPlugin([
   {
    from: path.resolve(__dirname, '../static'),
    to: config.build.assetsSubDirectory,
    ignore: ['.*']
   }
  ])
 ]
})

// 开启 gzip 的情况时,给 webpack plugins添加 compression-webpack-plugin 插件
if (config.build.productionGzip) {
  // webpack 压缩插件
  // https://github.com/webpack-contrib/compression-webpack-plugin
 var CompressionWebpackPlugin = require('compression-webpack-plugin')

 // 向webpackconfig.plugins中加入下方的插件
 webpackConfig.plugins.push(
  new CompressionWebpackPlugin({
   asset: '[path].gz[query]',
   algorithm: 'gzip',
   test: new RegExp(
    '\\.(' +
    config.build.productionGzipExtensions.join('|') +
    ')$'
   ),
   threshold: 10240,
   minRatio: 0.8
  })
 )
}

// 开启包分析的情况时, 给 webpack plugins添加 webpack-bundle-analyzer 插件
if (config.build.bundleAnalyzerReport) {
 // https://github.com/th0r/webpack-bundle-analyzer
 var BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin
 webpackConfig.plugins.push(new BundleAnalyzerPlugin())
}

module.exports = webpackConfig

其他

如果你觉得在segmentfault的代码阅读体验不好,你可以到我github上将代码clone下来看。

vue-cli-webpack-analysis

总结

这次研究webpack配置的时候,我自己跟着源码敲了一遍(很笨的方法),然后,在github和webpack官网上查使用到的插件的作用和用法。经过这一次折腾,加深对webpack的认识。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
js实现异步循环实现代码
Feb 16 Javascript
深入理解JavaScript中的浮点数
May 18 Javascript
javascript 将共享属性迁移到原型中去的实现方法
Aug 31 Javascript
基于JS组件实现拖动滑块验证功能(代码分享)
Nov 18 Javascript
Angular2 PrimeNG分页模块学习
Jan 14 Javascript
如何在Angular2中使用jQuery及其插件的方法
Feb 09 Javascript
Bootstrap.css与layDate日期选择样式起冲突的解决办法
Apr 07 Javascript
[js高手之路]HTML标签解释成DOM节点的实现方法
Aug 31 Javascript
Vue 让元素抖动/摆动起来的实现代码
May 31 Javascript
vue-cli在 history模式下的配置详解
Nov 26 Javascript
这样回答继承可能面试官更满意
Dec 10 Javascript
Vant Weapp组件踩坑:picker的初始赋值解决
Nov 12 Javascript
微信小程序开发之左右分栏效果的实例代码
May 20 #Javascript
微信小程序rich-text富文本用法实例分析
May 20 #Javascript
bootstrap中的导航条实例代码详解
May 20 #Javascript
详解小程序云开发数据库
May 20 #Javascript
VUE脚手架具体使用方法
May 20 #Javascript
Vue CLI2升级至Vue CLI3的方法步骤
May 20 #Javascript
解决Vue+Electron下Vuex的Dispatch没有效果问题
May 20 #Javascript
You might like
php 魔术方法使用说明
2009/10/20 PHP
Linux下CoreSeek及PHP扩展模块的安装
2012/09/23 PHP
php实现的mongodb操作类实例
2015/04/03 PHP
自制PHP框架之模型与数据库
2017/05/07 PHP
JavaScript窗口功能指南之在窗口中书写内容
2006/07/21 Javascript
javascript  Error 对象 错误处理
2008/05/18 Javascript
javascript 处理事件绑定的一些兼容写法
2009/12/24 Javascript
解决jquery1.9不支持browser对象的问题
2013/11/13 Javascript
Js 去掉字符串中的空格(实现代码)
2013/11/19 Javascript
JS截取url中问号后面参数的值信息
2014/04/29 Javascript
JavaScript实现DIV层拖动及动态增加新层的方法
2015/05/12 Javascript
基于angularjs实现图片放大镜效果
2016/08/31 Javascript
jQuery+正则+文本框只能输入数字的实现方法
2016/10/07 Javascript
浅述Javascript的外部对象
2016/12/07 Javascript
关于Vue背景图打包之后访问路径错误问题的解决
2017/11/03 Javascript
Vue 换肤的示例实践
2018/01/23 Javascript
dts文件中删除一个node或属性的操作方法
2018/08/05 Javascript
Vue前后端不同端口的实现方法
2018/09/19 Javascript
Layui事件监听的实现(表单和数据表格)
2019/10/17 Javascript
使用Vue生成动态表单
2019/11/26 Javascript
js判断浏览器的环境(pc端,移动端,还是微信浏览器)
2020/12/24 Javascript
extjs图形绘制之饼图实现方法分析
2020/03/06 Javascript
vue插件--仿微信小程序showModel实现模态提示窗功能
2020/08/19 Javascript
Windows下PyCharm配置Anaconda环境(超详细教程)
2020/07/31 Python
利用Python实现Json序列化库的方法步骤
2020/09/09 Python
matplotlib之多边形选区(PolygonSelector)的使用
2021/02/24 Python
PurCotton全棉时代官网:100%天然棉花生产的生活护理用品
2016/11/18 全球购物
澳大利亚拥有最好的家具和家居用品在线目的地:Nestz
2019/02/23 全球购物
什么是方法的重载
2013/06/24 面试题
大学毕业登记表自我鉴定
2013/10/09 职场文书
小学社会实践活动总结
2014/07/03 职场文书
2014年民警工作总结
2014/11/25 职场文书
食品药品安全责任书
2015/05/11 职场文书
JS数组方法some、every和find的使用详情
2021/10/05 Javascript
JavaScript阻止事件冒泡的方法
2021/12/06 Javascript
redis lua限流算法实现示例
2022/07/15 Redis