详解vue-cli 2.0配置文件(小结)


Posted in Javascript onJanuary 14, 2019

上次给大家分享的是用vue-cli快速搭建vue项目,虽然很省时间和精力,但想要真正搞明白,我们还需要对其原理一探究竟。

大家拿到一个项目,要快速上手,正确的思路是这样的:

首先,如果在项目有readme.md的情况下,大家要先读readme,项目的一些基本介绍,包括项目信息、运行的脚本、采用何种框架,以及项目维护者等信息通常都会有。一般在git上维护的项目都会有readme.md,不熟悉markdown语法的同学可以先了解下markdown入门。

第二步,要看package.json。现代的前端项目中通常都会有package.json文件。在package.json里,会介绍项目名称、版本、描述、作者、脚本、依赖包,对环境的要求,以及对浏览器要求。

{
 "name": "uccn",
 "version": "1.0.0",
 "description": "uccn3.0",
 "author": "v_yangtianjiao <v_yangtianjiao@baidu.com>",
 "private": true,
 // 这里的脚本是分析项目的主要入口
 "scripts": {
 "dev": "node build/dev-server.js",
 "start": "node build/dev-server.js",
 "build": "node build/build.js",
 "jsonp": "node build/jsonp-server.js"
 },

 // 项目依赖
 "dependencies": {
 "fetch-jsonp": "^1.1.3",
 "less": "^2.7.2",
 "less-loader": "^4.0.4",
 "stylus": "^0.54.5",
 "stylus-loader": "^3.0.1",
 "vue": "^2.4.2"
 },
 "devDependencies": {
 "autoprefixer": "^7.1.2",
 "babel-core": "^6.22.1",
 "babel-loader": "^7.1.1",
 "babel-plugin-component": "^0.10.1",
 "babel-plugin-transform-runtime": "^6.22.0",
 "babel-preset-env": "^1.3.2",
 "babel-preset-es2015": "^6.24.1",
 "babel-preset-stage-2": "^6.22.0",
 "babel-register": "^6.22.0",
 "chalk": "^2.0.1",
 "connect-history-api-fallback": "^1.3.0",
 "copy-webpack-plugin": "^4.0.1",
 "css-loader": "^0.28.0",
 "cssnano": "^3.10.0",
 "eventsource-polyfill": "^0.9.6",
 "express": "^4.14.1",
 "extract-text-webpack-plugin": "^2.0.0",
 "file-loader": "^0.11.1",
 "friendly-errors-webpack-plugin": "^1.1.3",
 "html-webpack-plugin": "^2.28.0",
 "http-proxy-middleware": "^0.17.3",
 "opn": "^5.1.0",
 "optimize-css-assets-webpack-plugin": "^2.0.0",
 "ora": "^1.2.0",
 "rimraf": "^2.6.0",
 "semver": "^5.3.0",
 "shelljs": "^0.7.6",
 "url-loader": "^0.5.8",
 "vue-loader": "^13.0.4",
 "vue-style-loader": "^3.0.1",
 "vue-template-compiler": "^2.4.2",
 "webpack": "^2.6.1",
 "webpack-bundle-analyzer": "^2.2.1",
 "webpack-dev-middleware": "^1.10.0",
 "webpack-hot-middleware": "^2.18.0",
 "webpack-merge": "^4.1.0"
 },
  // 对node版本的以及npm版本的要求
 "engines": {
 "node": ">= 4.0.0",
 "npm": ">= 3.0.0"
 },

 // 浏览器要求,vue项目不支持ie8,因为ie8是es3,尚没有Object.defineProperty属性
 "browserslist": [
 "> 1%",
 "last 2 versions",
 "not ie <= 8"
 ]
}

上面的package.json是从实际vue项目中摘出来的,大家从package.json中就会对项目有一个大概的了解,最主要的是脚本部分。通过npm的自动化任务,可以很方便的执行配置文件中的脚本。通过配置 "jsonp": "node build/jsonp-server.js",可以方便的使用npm run jsonp命令,代替node build/jsonp-server.js或者更复杂的一系列命令。详细的npm自动化命令可以移步npm 自动化。

详解vue-cli 2.0配置文件(小结)

现在的项目目录结构如上,我们从刚才的脚本入手。首先是启服务的脚本npm run dev,实际上是执行node build/dev-server.js,我们在build文件夹中找到dev-server.js,一步步分析。

/* eslint-disable */

// 首先检查node和npm的版本
require('./check-versions')()

// 获取配置文件中默认的配置
var config = require('../config')
// 如果node无法判断当前是开发环境还是生产环境,则使用config.dev.env.NODE_ENV作为当前的环境
if (!process.env.NODE_ENV) {
 process.env.NODE_ENV = JSON.parse(config.dev.env.NODE_ENV)
}

var opn = require('opn')// 用来在起来服务之后,打开浏览器并跳转指定URL
var path = require('path')// node自带文件路径工具
var express = require('express')// node框架express(本地开发的核心,起服务)
var webpack = require('webpack')// webpack,压缩打包
var proxyMiddleware = require('http-proxy-middleware')// 中间件
var webpackConfig = require('./webpack.dev.conf')// 开发环境的webpack配置
var mockMiddleware = require('../config/dev.mock')// 开发环境本地mock数据中间件

var port = process.env.PORT || config.dev.port
var autoOpenBrowser = !!config.dev.autoOpenBrowser
var proxyTable = config.dev.proxyTable

var app = express()// 起服务
var compiler = webpack(webpackConfig)// webpack进行编译

// webpack-dev-middleware将编译的文件放在内存中,后续注入
var devMiddleware = require('webpack-dev-middleware')(compiler, {
 publicPath: webpackConfig.output.publicPath,
 quiet: true
})
// 热加载
var hotMiddleware = require('webpack-hot-middleware')(compiler, {
 log: false,
 heartbeat: 2000
})
compiler.plugin('compilation', function (compilation) {
 compilation.plugin('html-webpack-plugin-after-emit', function (data, cb) {
 hotMiddleware.publish({ action: 'reload' })
 cb()
 })
})

// proxy api requests
// proxyTable中的配置挂载到express中
Object.keys(proxyTable).forEach(function (context) {
 var options = proxyTable[context]
 if (typeof options === 'string') {
 options = { target: options }
 }
 app.use(proxyMiddleware(options.filter || context, options))
})

// 处理后退的时候匹配资源
app.use(require('connect-history-api-fallback')())

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

// 将本地mock中间件挂载到express上
app.use(mockMiddleware);

// 热加载挂载到express上
app.use(hotMiddleware)

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

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

var _resolve
var readyPromise = new Promise(resolve => {
 _resolve = resolve
})

console.log('> Starting dev server...')
devMiddleware.waitUntilValid(() => {
 console.log('> Listening at ' + uri + '\n')
 if (autoOpenBrowser && process.env.NODE_ENV !== 'testing') {
 opn(uri)
 }
 _resolve()
})
// 通过配置的端口,自动打开浏览器,并跳转拼好的URL,至此,发开环境已经跑起来了
var server = app.listen(port)

module.exports = {
 ready: readyPromise,
 close: () => {
 server.close()
 }
}

在上面的dev-server中,有很多变量来自于./config/index.js和webpack.dev.conf.js,我们一个个看上述配置文件。

首先看./config/index.js,这里是整个项目主要的配置入口,我们在代码中一步步分析:

// node自带路径工具.
var path = require('path')
// 分为两种环境,dev和production
module.exports = {
 build: {
 env: require('./prod.env'),// 使用config/prod.env.js中定义的编译环境
 index: path.resolve(__dirname, '../dist/index.html'),// 编译输入的index.html文件。node.js中,在任何模块文件内部,可以使用__filename变量获取当前模块文件的带有完整绝对路径的文件名,
 assetsRoot: path.resolve(__dirname, '../dist'),// 编译输出的静态资源路径
 assetsSubDirectory: 'static',// 编译输出的二级目录
 assetsPublicPath: './', // 编译发布的根目录,可配置为资源服务器或者cdn域名
 productionSourceMap: false,//是否开启cssSourceMap
 productionGzip: false,// 是否开启gzip
 productionGzipExtensions: ['js', 'css'],// 需要用gzip压缩的文件扩展名
 bundleAnalyzerReport: process.env.npm_config_report
 },
 dev: {
 env: require('./dev.env'),
 port: 8989,// 起服务的端口
 autoOpenBrowser: true,
 assetsSubDirectory: 'static',
 assetsPublicPath: '/',
 proxyTable: {},// 需要代理的接口,可以跨域
 cssSourceMap: false
 }
}

接着我们分析webpack.dev.conf.js:

var utils = require('./utils')// 工具类
var webpack = require('webpack')
var config = require('../config')
var merge = require('webpack-merge')// 使用webpack配置合并插件
var baseWebpackConfig = require('./webpack.base.conf')
var HtmlWebpackPlugin = require('html-webpack-plugin')// 这个插件自动生成HTML,并注入到.html文件中
var FriendlyErrorsPlugin = require('friendly-errors-webpack-plugin')

// 将hot-reload相对路径添加到webpack.base.conf的对应的entry前面
Object.keys(baseWebpackConfig.entry).forEach(function (name) {
 baseWebpackConfig.entry[name] = ['./build/dev-client'].concat(baseWebpackConfig.entry[name])
})

// webpack.dev.conf.js与webpack.base.conf.js中的配置合并
module.exports = merge(baseWebpackConfig, {
 module: {
 rules: utils.styleLoaders({ sourceMap: config.dev.cssSourceMap })
 },
 // webpack-devtool有7种模式,cheap-module-eval-source-map模式是比较快的开发模式
 
 devtool: '#cheap-module-eval-source-map',
 plugins: [
// 你可以理解为,通过配置了DefinePlugin,那么这里面的标识就相当于全局变量,你的业务代码可以直接使用配置的标识。
 new webpack.DefinePlugin({
  'process.env': config.dev.env
 }),
 // hotModule插件让页面变动时,只重绘对应的模块,不会重绘整个HTML文件
 new webpack.HotModuleReplacementPlugin(),

// 在编译出现错误时,使用 NoEmitOnErrorsPlugin 来跳过输出阶段。这样可以确保输出资源不会包含错误
 new webpack.NoEmitOnErrorsPlugin(),
 // 将生成的HTML代码注入index.html文件
 new HtmlWebpackPlugin({
  filename: 'index.html',
  template: 'index.html',
  inject: true
 }),

// friendly-errors-webpack-plugin用于更友好地输出webpack的警告、错误等信息
 new FriendlyErrorsPlugin()
 ]
})

刚才的webpack.dev.conf.js中有引到webpack.base.conf.js,我们就把他们一网打尽,继续看webpack.base.conf.js!

/* eslint-disable */
var path = require('path')// node自带的文件路径插件
var utils = require('./utils')// 工具类
var config = require('../config')// 上面说过的config/index
var vueLoaderConfig = require('./vue-loader.conf')// vue-loader.conf配置文件是用来解决各种css文件的,定义了诸如css,less,sass之类的和样式有关的loader
// 此函数是用来返回当前目录的平行目录的路径,
function resolve (dir) {
 return path.join(__dirname, '..', dir)
}

module.exports = {
 entry: {
 uccn: './src/main.js'// 入口
 },
 output: {
// 路径是config目录下的index.js中的build配置中的assetsRoot,也就是dist目录
 path: config.build.assetsRoot,
 filename: '[name].js',

// 上线地址,也就是真正的文件引用路径,如果是production生产环境,其实这里都是 '/'
 publicPath: process.env.NODE_ENV === 'production'
  ? config.build.assetsPublicPath
  : config.dev.assetsPublicPath
 },
 // resolve是webpack的内置选项,顾名思义,决定要做的事情,也就是说当使用 import "jquery",该如何去执行这件事情,就是resolve配置项要做的,import jQuery from "./additional/dist/js/jquery" 这样会很麻烦,可以起个别名简化操作
 resolve: {

// 省略扩展名,比方说import index form '../js/index', 会默认去找index文件,然后找index.js,.vue,.josn.
 extensions: ['.js', '.vue', '.json'],
 alias: {
  'vue$': 'vue/dist/vue.esm.js',


// 使用上面的resolve函数,意思是用@代替src的绝对路径
  '@': resolve('src'),
 }
 },
 // 不同的模块使用不同的loader
 module: {
 rules: [
  {


 // 对vue文件,使用vue-loader解析
  test: /\.vue$/,
  loader: 'vue-loader',
  options: vueLoaderConfig
  },
  {


 // babel-loader把es6解析成es5
  test: /\.js$/,
  loader: 'babel-loader',
  include: [resolve('src'), resolve('test')]
  },
  {


 // url-loader将文件大小低于下面option中limit的图片,转化为一个64位的DataURL,这样会省去很多请求,大于limit的,按[name].[hash:7].[ext]的命名方式放到了static/img下面,方便做cache
  test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
  loader: 'url-loader',
  options: {
   limit: 20000,
   name: utils.assetsPath('img/[name].[hash:7].[ext]')
  }
  },
  {


 // 音频和视频文件处理,同上
  test: /\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/,
  loader: 'url-loader',
  options: {
   limit: 10000,
   name: utils.assetsPath('media/[name].[hash:7].[ext]')
  }
  },
  {


 // 字体处理,同上 
  test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
  loader: 'url-loader',
  options: {
   limit: 10000,
   name: utils.assetsPath('fonts/[name].[hash:7].[ext]')
  }
  }
 ]
 }
}

至此,npm run dev起本地开发环境相关的配置文件基本说完了,接着说一下上面都用到的util工具类:

var path = require('path')
var config = require('../config')
// extract-text-webpack-plugin该插件的主要是为了抽离css样式,防止将样式打包在js中引起页面样式加载错乱的现象
var ExtractTextPlugin = require('extract-text-webpack-plugin')

// 返回资源文件路径,path.posix以posix兼容的方式交互,是跨平台的,如果是path.win32的话,只能在win上
exports.assetsPath = function (_path) {
 var assetsSubDirectory = process.env.NODE_ENV === 'production'
 ? config.build.assetsSubDirectory
 : config.dev.assetsSubDirectory
 return path.posix.join(assetsSubDirectory, _path)
}

// 通过判断是否是生产环境,配置不同的样式语言的loader配置
exports.cssLoaders = function (options) {
 options = options || {}

 var cssLoader = {
 loader: 'css-loader',
 options: {
  minimize: process.env.NODE_ENV === 'production',
  sourceMap: options.sourceMap
 }
 }

 // 生成各种loader配置,通过传入不同的loader和option,将不同样式文件语言的loader拼好,push到loader配置中。
 function generateLoaders (loader, loaderOptions) {
 var loaders = [cssLoader]
 if (loader) {
  loaders.push({
  loader: loader + '-loader',
  options: Object.assign({}, loaderOptions, {
   sourceMap: options.sourceMap
  })
  })
 }

 // extract-text-webpack-plugin有三个参数,use指需要用什么loader去编译文件;fallback指编译后用什么loader去提取文件;还有一个publicfile用来覆盖项目路径
 if (options.extract) {
  return ExtractTextPlugin.extract({
  use: loaders,
  fallback: 'vue-style-loader'
  })
 } else {
  return ['vue-style-loader'].concat(loaders)
 }
 }

 // 对不同的样式语言,返回相应的loader
 return {
 css: generateLoaders(),
 postcss: generateLoaders(),
 less: generateLoaders('less'),
 sass: generateLoaders('sass', { indentedSyntax: true }),
 scss: generateLoaders('sass'),
 stylus: generateLoaders('stylus'),
 styl: generateLoaders('stylus')
 }
}

// 生成处理不同的样式文件处理规则
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
}

———————————————— 华丽的分隔符 —————————————————

下面我们继续说npm run build,打包编译的一系列操作~

从package.json 中可以看出,npm run build,其实是执行了 node build/build.js,我们在build文件夹中找到build.js,build主要的工作是:检测node和npm版本,删除dist包,webpack构建打包,在终端输出构建信息并结束,如果报错,则输出报错信息

require('./check-versions')()

process.env.NODE_ENV = 'production'

// 在终端显示的旋转器插件
var ora = require('ora')
// 用于删除文件夹
var rm = require('rimraf')
var path = require('path')
// 终端文字颜色插件
var chalk = require('chalk')
var webpack = require('webpack')
var config = require('../config')
var webpackConfig = require('./webpack.prod.conf')

var spinner = ora('building for production...')
spinner.start()

// 删除dist文件夹,之后webpack打包
rm(path.join(config.build.assetsRoot, config.build.assetsSubDirectory), err => {
 if (err) throw err
 webpack(webpackConfig, function (err, stats) {
 spinner.stop()
 if (err) throw err
 process.stdout.write(stats.toString({
  colors: true,
  modules: false,
  children: false,
  chunks: false,
  chunkModules: false
 }) + '\n\n')

 if (stats.hasErrors()) {
  console.log(chalk.red(' Build failed with errors.\n'))
  process.exit(1)
 }

 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'
 ))
 })
})

build.js用到了webpack.prod.conf.js,他与webpack.base.conf.js merge之后,作为webpack配置文件,我们再看看webpack.prod.conf.js,主要做的工作是:

1.提取webpack生成的bundle中的文本,到特定的文件,使得css,js文件与webpack输出的bundle分离。

2.合并基本的webpack配置

3.配置webpack的输出,包括输出路径,文件名格式。

4.配置webpack插件,包括丑化代码。

5.gzip下引入compression插件进行压缩。

/* eslint-disable */
var path = require('path')
var utils = require('./utils')
var webpack = require('webpack')
var config = require('../config')
var merge = require('webpack-merge')
var baseWebpackConfig = require('./webpack.base.conf')
var CopyWebpackPlugin = require('copy-webpack-plugin')
var HtmlWebpackPlugin = require('html-webpack-plugin')
// 用于从webpack生成的bundle中提取文本到特定文件中的插件
// 可以抽取出css,js文件将其与webpack输出的bundle分离
var ExtractTextPlugin = require('extract-text-webpack-plugin')
var OptimizeCSSPlugin = require('optimize-css-assets-webpack-plugin')

var env = config.build.env
// 合并基础的webpack配置
var webpackConfig = merge(baseWebpackConfig, {
 module: {
 rules: utils.styleLoaders({
  sourceMap: config.build.productionSourceMap,
  extract: true
 })
 },
 // 7中sourceMap上面有讲过
 devtool: config.build.productionSourceMap ? '#source-map' : false,
 // 配置webpack输出的目录,及文件命名规则
 output: {
 path: config.build.assetsRoot,
 filename: utils.assetsPath('js/[name].min.js'),
 chunkFilename: utils.assetsPath('js/[id].[chunkhash].js')
 },
 // webpack插件配置
 plugins: [
 // 同webpack.dev.conf.js
 new webpack.DefinePlugin({
  'process.env': env
 }),
// 丑化代码
 new webpack.optimize.UglifyJsPlugin({
  compress: {
  warnings: false
  },
  sourceMap: true
 }),
 // 抽离css文件到单独的文件
 new ExtractTextPlugin({
  filename: utils.assetsPath('css/[name].min.css')
 }),
 new OptimizeCSSPlugin({
  cssProcessorOptions: {
  safe: true
  }
 }),
 // 生成并注入index.html
 new HtmlWebpackPlugin({
  filename: config.build.index,
  template: 'index.html',
  inject: true,
  minify: {
  removeComments: true,
  collapseWhitespace: false,
  removeAttributeQuotes: true
  },
  chunksSortMode: 'dependency'
 }),
 // keep module.id stable when vender modules does not change
 new webpack.HashedModuleIdsPlugin(),
 split vendor js into its own file
 new webpack.optimize.CommonsChunkPlugin({
  name: 'vendor',
  minChunks: function (module, count) {
  // any required modules inside node_modules are extracted to vendor
  return (
   module.resource &&
   /\.js$/.test(module.resource) &&
   module.resource.indexOf(
   path.join(__dirname, '../node_modules')
   ) === 0
  )
  }
 }),
 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']
 }),
 copy custom static assets
 new CopyWebpackPlugin([
  {
  from: path.resolve(__dirname, '../static'),
  to: config.build.assetsSubDirectory,
  ignore: ['.*']
  }
 ])
 ]
})
// gzip模式下需要引入compression插件进行压缩
if (config.build.productionGzip) {
 var CompressionWebpackPlugin = require('compression-webpack-plugin')

 webpackConfig.plugins.push(
 new CompressionWebpackPlugin({
  asset: '[path].gz[query]',
  algorithm: 'gzip',
  test: new RegExp(
  '\\.(' +
  config.build.productionGzipExtensions.join('|') +
  ')$'
  ),
  threshold: 10240,
  minRatio: 0.8
 })
 )
}

if (config.build.bundleAnalyzerReport) {
 var BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin
 webpackConfig.plugins.push(new BundleAnalyzerPlugin())
}

module.exports = webpackConfig

到此为止,vue官方脚手架工具vue-cli 2.0的所有配置文件都已介绍完毕,从头到尾再梳理一遍:

执行npm run dev或者npm run start,实际是在node环境执行build/dev-server.js, dev-server.js会去拿到config中的端口等配置,通过express起一个服务,通过插件自动打开浏览器,加载webpack编译后放在内存的bundle。

执行npm run build,实际上执行了build/build.js,通过webpack的一系列配置及插件,将文件打包合并丑化,并创建dist目录,放置编译打包后的文件,这将是未来用在生产环境的包。

写这篇文章我自身的收获也挺多,第一是对vue-cli整体的认知更加清晰条理,第二是对webpack的一些插件有了新的认识。以前对一些插件模棱两可,直接越过,这是不对的,要一步一个脚印儿,遇坑填坑,这样才会有收获。虽然过程可能是艰辛的,但收获将会是巨大的~希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
Jquery知识点一 Jquery的ready和Dom的onload的区别
Jan 15 Javascript
使用JavaScript实现网页版Pongo设计思路及源代码分享
Jun 16 Javascript
jQuery创建DOM元素实例解析
Jan 19 Javascript
bootstrap中使用google prettify让代码高亮的方法
Oct 21 Javascript
微信小程序 页面跳转和数据传递实例详解
Jan 19 Javascript
jQuery插件echarts去掉垂直网格线用法示例
Mar 03 Javascript
javascript中this用法实例详解
Apr 06 Javascript
微信小程序实现跑马灯效果完整代码(附效果图)
May 30 Javascript
vue router的基本使用和配置教程
Nov 05 Javascript
详解Vue组件之间通信的七种方式
Apr 14 Javascript
详解小程序云开发攻略(解决最棘手的问题)
Sep 30 Javascript
vue data恢复初始化数据的实现方法
Oct 31 Javascript
使用vue-cli脚手架工具搭建vue-webpack项目
Jan 14 #Javascript
vue-cli系列之vue-cli-service整体架构浅析
Jan 14 #Javascript
JS数组求和的常用方法总结【5种方法】
Jan 14 #Javascript
JS实现根据数组对象的某一属性排序操作示例
Jan 14 #Javascript
vue项目中使用vue-i18n报错的解决方法
Jan 13 #Javascript
vscode下vue项目中eslint的使用方法
Jan 13 #Javascript
jQuery实现的中英文切换功能示例
Jan 11 #jQuery
You might like
PHP按行读取、处理较大CSV文件的代码实例
2014/04/09 PHP
PHP中的命名空间相关概念浅析
2015/01/22 PHP
php字符串分割函数用法实例
2015/03/17 PHP
以实例全面讲解PHP中多进程编程的相关函数的使用
2015/08/18 PHP
php、java、android、ios通用的3des方法(推荐)
2016/09/09 PHP
laravel自定义分页的实现案例offset()和limit()
2019/10/15 PHP
javascript中的undefined 与 null 的区别  补充篇
2010/03/17 Javascript
jquery插件实现鼠标经过图片右侧显示大图的效果(类似淘宝)
2013/02/04 Javascript
页面元素绑定jquery toggle后元素隐藏的解决方法
2014/03/27 Javascript
jquery 新建的元素事件绑定问题解决方案
2014/06/12 Javascript
javascript验证身份证号
2015/03/03 Javascript
学习javascript面向对象 实例讲解面向对象选项卡
2016/01/04 Javascript
js实现无缝循环滚动
2020/06/23 Javascript
js前端解决跨域问题的8种方案(最新最全)
2016/11/18 Javascript
vue单页面打包文件大?首次加载慢?nginx带你飞,从7.5M到1.3M蜕变过程(推荐)
2018/01/16 Javascript
Vue实现移动端左右滑动效果的方法
2018/11/27 Javascript
小程序云函数调用API接口的方法
2019/05/17 Javascript
JS前端面试必备——基本排序算法原理与实现方法详解【插入/选择/归并/冒泡/快速排序】
2020/02/24 Javascript
[05:20]卡尔工作室_DOTA2新手教学_DOTA2超强新手功能
2013/04/22 DOTA
使用PDB简单调试Python程序简明指南
2015/04/25 Python
Python中的with...as用法介绍
2015/05/28 Python
Python捕捉和模拟鼠标事件的方法
2015/06/03 Python
利用python实现命令行有道词典的方法示例
2017/01/31 Python
Tensorflow实现AlexNet卷积神经网络及运算时间评测
2018/05/24 Python
Python3爬虫教程之利用Python实现发送天气预报邮件
2018/12/16 Python
使用Python3+PyQT5+Pyserial 实现简单的串口工具方法
2019/02/13 Python
python函数参数(必须参数、可变参数、关键字参数)
2019/08/16 Python
基于python生成英文版词云图代码实例
2020/05/16 Python
python自动化测试三部曲之unittest框架的实现
2020/10/07 Python
CSS3色彩模式有哪些?CSS3 HSL色彩模式的定义
2016/04/26 HTML / CSS
香港现代设计家具品牌:Ziinlife Furniture
2018/11/13 全球购物
德国珠宝和配件商店:Styleserver
2021/02/23 全球购物
高考升学宴答谢词
2015/01/20 职场文书
管理失职检讨书范文
2015/05/05 职场文书
文明礼仪主题班会
2015/08/13 职场文书
virtualenv隔离Python环境的问题解析
2022/06/21 Python