rollup cli开发全面系统性rollup源码分析

目录
  • 引言
  • prefix
  • symlink
  • Executables(可执行文件)
  • rollup 命令行的开发
  • 打包生成 rollup 文件

引言

在学习 rollup CLI 之前我们需要了解 npm 中的 prefix,symlink,Executables 这三个概念。

prefix

当我们使用 --global/-g 选项的时候会将包安装到 prefix 目录下,prefix 默认为 node 的安装位置。在大多数系统上,它是 /usr/local。

在 Windows 上,它是 %AppData%\npm 目录中。在 Unix 系统上,它向上一级,因为 node 通常安装在{prefix}/bin/node 而不是{prefix}/node.exe。

如果未使用 --global/-g 选项的时候,它将安装在当前包的根目录,或者当前工作目录。

具体请参阅 folders

symlink

许多包都有一个或多个可执行文件,并且希望将其安装到 PATH 中。npm 刚好提供了这个功能。

如果想要在用户安装包的时候创建可执行文件,请在 package.json 中提供一个 bin 字段,该字段是命令名称到本地文件名的映射。在安装时,npm 会将该文件符号链接到 prefix/bin 以进行全局安装,或 ./node_modules/.bin/ 用于本地安装。

Executables(可执行文件)

举个例子:

npm install --global rollup

当我们使用上述方式全局安装 rollup 的时候,我们可以 cd 到任何文件目录下直接使用 rollup 命令来使用它。其中的原理就是我们需要了解的可执行文件的概念:

  • 在全局模式下,可执行文件在 Unix 上链接到 {prefix}/bin,或在 Windows 上直接链接到 {prefix}。
  • 在本地模式下,可执行文件链接到 ./node_modules/.bin 中,以便它们可以可用于通过 npm 运行的脚本。

简单来说就是当你使用 npm install 的时候 npm 会自动为你创建对应的可执行文件。如果是使用 npm install 的方式则会将对应的可执行文件放在 /node_modules/.bin 目录下。如果使用 npm install --global 的方式,对应的可执行文件在 Unix 上会放在{prefix}/bin 目录,在 Windows 上则是 {prefix} 目录。

当你执行 npm run 的时候,npm 会在 node 环境变量(Path)中(例如 C:\Users\victorjiang\AppData\Roaming\npm)找到对应的 node 可执行文件并且运行它。可执行文件包括三个:

  • rollup:Unix 系统默认的可执行文件,必须输入完整文件名
  • rollup.cmd:windows cmd 中默认的可执行文件
  • rollup.ps1:Windows PowerShell 中可执行文件,可以跨平台

在了解了 prefix,symlink,Executables 这三个概念之后我们就可以开始学习 rollup 的 CLI 的功能了。

rollup 命令行的开发

Rollup 命令行的源码在项目的根目录的 cli 下:

cli
├─ run              //定义了runRollup函数,以及加载配置文件等业务代码
├─ cli.ts           //命令行解析入口
├─ help.md          //rollup帮助文档
├─ logging.ts       //handleError方法定义

cli/cli.ts 代码定义:

import process from 'node:process';
import help from 'help.md';
import { version } from 'package.json';
import argParser from 'yargs-parser';
import { commandAliases } from '../src/utils/options/mergeOptions';
import run from './run/index';
/**
commandAliases: {
	c: 'config',
	d: 'dir',
	e: 'external',
	f: 'format',
	g: 'globals',
	h: 'help',
	i: 'input',
	m: 'sourcemap',
	n: 'name',
	o: 'file',
	p: 'plugin',
	v: 'version',
	w: 'watch'
};
 */
// process 是一个全局变量,即 global 对象的属性。
// 它用于描述当前Node.js 进程状态的对象,提供了一个与操作系统的简单接口。
// process.argv 属性返回一个数组,由命令行执行脚本时的各个参数组成。
// 它的第一个成员总是node,第二个成员是脚本文件名,其余成员是脚本文件的参数。
// process.argv:  [
//   'C:\\Program Files\\nodejs\\node.exe',
//   'C:\\Program Files\\nodejs\\node_modules\\rollup\\dist\\bin\\rollup'
// ]
/**
 * 1. process.argv.slice(2) 则是从 argv数组下标为2的元素开始直到末尾提取元素,举例来说就是提取诸如 rollup -h 中除了 rollup 之外的参数
 * 2. yargs-parser这个包的作用是把命令行参数转换为json对象,方便访问。
 * 例如:"rollup -h" 会被argParser解析成 { _: [], h: true, help: true }
 * "rollup --help" 会被argParser解析成 { _: [], help: true, h: true }
 * 'camel-case-expansion' 表示连字符参数是否应该扩展为驼峰大小写别名?默认是true.
 * 例如: node example.js --foo-bar 会被解析成 { _: [], 'foo-bar': true, fooBar: true }
 *
 */
const command = argParser(process.argv.slice(2), {
  alias: commandAliases, //alias参数表示键的别名对象
  configuration: { 'camel-case-expansion': false } //为 argParser 解析器提供配置选项, 'camel-case-expansion': false 表示连字符参数不会被扩展为驼峰大小写别名
});
//process.stdin.isTTY 用于检测我们的程序是否直接连到终端
if (command.help || (process.argv.length <= 2 && process.stdin.isTTY)) {
  console.log(`\n${help.replace('__VERSION__', version)}\n`);
} else if (command.version) {
  console.log(`rollup v${version}`);
} else {
  try {
    // eslint-disable-next-line unicorn/prefer-module
    //浏览器是支持source maps的,但node环境原生不支持source maps。所以我们可以通过'source-map-support'包来实现这个功能。这样当程序执行出错的时候方便通过控制台定位到源码位置。
    require('source-map-support').install();
  } catch {
    // do nothing
  }
  run(command);
}

上面代码中的 run 方法就是 cli/run/index.ts 中定义的 runRollup 方法,它的主要作用就是为了解析用户输入的命令行参数。

cli/run/index.ts 代码定义:

import { env } from 'node:process';
import type { MergedRollupOptions } from '../../src/rollup/types';
import { errorDuplicateImportOptions, errorFailAfterWarnings } from '../../src/utils/error';
import { isWatchEnabled } from '../../src/utils/options/mergeOptions';
import { getAliasName } from '../../src/utils/relativeId';
import { loadFsEvents } from '../../src/watch/fsevents-importer';
import { handleError } from '../logging';
import type { BatchWarnings } from './batchWarnings';
import build from './build';
import { getConfigPath } from './getConfigPath';
import { loadConfigFile } from './loadConfigFile';
import loadConfigFromCommand from './loadConfigFromCommand';
export default async function runRollup(command: Record<string, any>): Promise<void> {
  let inputSource; //获取input的值
  if (command._.length > 0) {
    //获取非选项值
    //例如终端输入"rollup -i input.js f es"  =>  command:  { _: [ 'f', 'es' ], i: 'input.js', input: 'input.js' }
    if (command.input) {
      handleError(errorDuplicateImportOptions());
    }
    inputSource = command._;
  } else if (typeof command.input === 'string') {
    inputSource = [command.input];
  } else {
    inputSource = command.input;
  }
  if (inputSource && inputSource.length > 0) {
    if (inputSource.some((input: string) => input.includes('='))) {
      //"rollup -i input.js f=es" => { _: [ 'f=es' ], i: 'input.js', input: 'input.js' }
      command.input = {};
      //处理多入口文件的情况
      for (const input of inputSource) {
        const equalsIndex = input.indexOf('=');
        const value = input.slice(Math.max(0, equalsIndex + 1)); //获取等号右边的字符=> “es”
        const key = input.slice(0, Math.max(0, equalsIndex)) || getAliasName(input); //获取等号左边的字符=> “f”
        command.input[key] = value;
      }
    } else {
      //处理单入口文件的情况
      command.input = inputSource;
    }
  }
  if (command.environment) {
    //获取environment参数用于设置process.env.[XX]
    const environment = Array.isArray(command.environment)
      ? command.environment
      : [command.environment];
    for (const argument of environment) {
      for (const pair of argument.split(',')) {
        const [key, ...value] = pair.split(':');
        env[key] = value.length === 0 ? String(true) : value.join(':');
      }
    }
  }
  if (isWatchEnabled(command.watch)) {
    //观察模式
    await loadFsEvents();
    const { watch } = await import('./watch-cli');
    watch(command);
  } else {
    //非观察模式
    try {
      const { options, warnings } = await getConfigs(command);
      try {
        //因为配置文件可以返回一个数组,所以需要挨个执行
        for (const inputOptions of options) {
          //内部执行 rollup(inputOptions) 进行打包
          await build(inputOptions, warnings, command.silent);
        }
        if (command.failAfterWarnings && warnings.warningOccurred) {
          warnings.flush();
          handleError(errorFailAfterWarnings());
        }
      } catch (error: any) {
        warnings.flush();
        handleError(error);
      }
    } catch (error: any) {
      handleError(error);
    }
  }
}
async function getConfigs(
  command: any
): Promise<{ options: MergedRollupOptions[]; warnings: BatchWarnings }> {
  if (command.config) {
    //获取配置文件
    const configFile = await getConfigPath(command.config);
    //读取配置文件获取配置项
    const { options, warnings } = await loadConfigFile(configFile, command);
    return { options, warnings };
  }
  return await loadConfigFromCommand(command);
}

打包生成 rollup 文件

在 rollup.config.ts 文件中有导出一个方法:

//rollup.config.ts
export default async function (
  command: Record<string, unknown>
): Promise<RollupOptions | RollupOptions[]> {
  const { collectLicenses, writeLicense } = getLicenseHandler(
    fileURLToPath(new URL('.', import.meta.url))
  );
  const commonJSBuild: RollupOptions = {
    // 'fsevents' is a dependency of 'chokidar' that cannot be bundled as it contains binary code
    external: ['fsevents'],
    input: {
      'loadConfigFile.js': 'cli/run/loadConfigFile.ts',
      'rollup.js': 'src/node-entry.ts'
    },
    onwarn,
    output: {
      banner: getBanner,
      chunkFileNames: 'shared/[name].js',
      dir: 'dist',
      entryFileNames: '[name]',
      exports: 'named',
      externalLiveBindings: false,
      format: 'cjs',
      freeze: false,
      generatedCode: 'es2015',
      interop: 'default',
      manualChunks: { rollup: ['src/node-entry.ts'] },
      sourcemap: true
    },
    plugins: [
      ...nodePlugins,
      addCliEntry(), //添加cli入口文件
      esmDynamicImport(),
      !command.configTest && collectLicenses(),
      !command.configTest && copyTypes('rollup.d.ts')
    ],
    strictDeprecations: true,
    treeshake
  };
  /**
	 *
	当我们执行npm run build 的时候就相当于执行了 rollup --config rollup.config.ts --configPlugin typescript
	此时 command 就是如下对象:
	{
		_: [],
		config: 'rollup.config.ts',
		c: 'rollup.config.ts',
		configPlugin: 'typescript'
	}
	*/
  if (command.configTest) {
    return commonJSBuild;
  }
  const esmBuild: RollupOptions = {
    ...commonJSBuild,
    input: { 'rollup.js': 'src/node-entry.ts' },
    output: {
      ...commonJSBuild.output,
      dir: 'dist/es',
      format: 'es',
      minifyInternalExports: false,
      sourcemap: false
    },
    plugins: [...nodePlugins, emitModulePackageFile(), collectLicenses(), writeLicense()]
  };
  const { collectLicenses: collectLicensesBrowser, writeLicense: writeLicenseBrowser } =
    getLicenseHandler(fileURLToPath(new URL('browser', import.meta.url)));
  const browserBuilds: RollupOptions = {
    input: 'src/browser-entry.ts',
    onwarn,
    output: [
      {
        banner: getBanner,
        file: 'browser/dist/rollup.browser.js',
        format: 'umd',
        name: 'rollup',
        plugins: [copyTypes('rollup.browser.d.ts')],
        sourcemap: true
      },
      {
        banner: getBanner,
        file: 'browser/dist/es/rollup.browser.js',
        format: 'es',
        plugins: [emitModulePackageFile()]
      }
    ],
    plugins: [
      replaceBrowserModules(),
      alias(moduleAliases),
      nodeResolve({ browser: true }),
      json(),
      commonjs(),
      typescript(),
      terser({ module: true, output: { comments: 'some' } }),
      collectLicensesBrowser(),
      writeLicenseBrowser(),
      cleanBeforeWrite('browser/dist')
    ],
    strictDeprecations: true,
    treeshake
  };
  return [commonJSBuild, esmBuild, browserBuilds];
}

请注意上面使用了 addCliEntry 插件。它的代码定义在 build-plugins/add-cli-entry.ts:

import { chmod } from 'node:fs/promises';
import { resolve } from 'node:path';
import MagicString from 'magic-string';
import type { Plugin } from 'rollup';
const CLI_CHUNK = 'bin/rollup';
export default function addCliEntry(): Plugin {
  return {
    buildStart() {
      this.emitFile({
        fileName: CLI_CHUNK,
        id: 'cli/cli.ts',
        preserveSignature: false,
        type: 'chunk'
      });
    },
    name: 'add-cli-entry',
    renderChunk(code, chunkInfo) {
      if (chunkInfo.fileName === CLI_CHUNK) {
        const magicString = new MagicString(code);
        //声明在 shell 中使用 node来运行
        magicString.prepend('#!/usr/bin/env node\n\n');
        return { code: magicString.toString(), map: magicString.generateMap({ hires: true }) };
      }
      return null;
    },
    writeBundle({ dir }) {
      return chmod(resolve(dir!, CLI_CHUNK), '755'); //修改文件可读写权限,保证执行的权限
      /*
			在Node.js中,可以调用fs模块,有一个方法chmod,可以用来修改文件或目录的读写权限。方法chmod有三个参数,文件路径、读写权限和回调函数,其中读写权限是用代号表示的,
			(1)0600:所有者可读写,其他的用户不行
			(2)0644:所有者可读写,其他的用户只读
			(3)0740:所有者可读写,所有者所在的组只读
			(4)0755:所有者可读写,其他用户可读可执行
			*/
    }
  };
}

addCliEntry 插件将 /cli/cli.ts 源码添加到输出的 chunk 中,并且在文件的头部增加一行代码:'#!/usr/bin/env node\n\n'。

首先解释一下 #!/usr/bin/env node

  • # 在 shell 脚本中单独使用代表注释
  • #! 组合使用表示要用在 shell 脚本中
  • env 是 Mac 或者 Linux 系统的环境变量,是一个可执行命令
  • env node : 指的是使用当前 env 环境内的配置的 Path 路径下的 node 执行
  • 当前脚本在执行 shell 时,会自动从 env 内调用合适的解释器执行

这样做的目的是为了能够解析当前脚本文件,该命令会自动从当前 env 环境中查找配置的 node 版本来执行脚本。

最终我们使用 npm run build 的命令打包 rollup 源码的时候就会生成 dist/bin/rollup 这个文件了

#!/usr/bin/env node
/*
  @license
	Rollup.js v3.2.3
	Sat, 28 Jan 2023 07:43:49 GMT - commit 5fa73d941c16a6bcbebaa3ae5bb6aaca8b97d0b7
	https://github.com/rollup/rollup
	Released under the MIT License.
*/
'use strict';
Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toStringTag]: { value: 'Module' } });
const process$1 = require('node:process');
const rollup = require('../shared/rollup.js');
const require$$2 = require('util');
const require$$0 = require('path');
const require$$0$1 = require('fs');
const node_fs = require('node:fs');
const node_path = require('node:path');
const loadConfigFile_js = require('../shared/loadConfigFile.js');
require('node:perf_hooks');
require('node:crypto');
require('node:events');
require('tty');
require('node:url');
# ...
const command = argParser(process$1.argv.slice(2), {
    alias: rollup.commandAliases,
    configuration: { 'camel-case-expansion': false } //为 argParser 解析器提供配置选项, 'camel-case-expansion': false 表示连字符参数不会被扩展为驼峰大小写别名
});
//process.stdin.isTTY 用于检测我们的程序是否直接连到终端
if (command.help || (process$1.argv.length <= 2 && process$1.stdin.isTTY)) {
    console.log(`\n${help.replace('__VERSION__', rollup.version)}\n`);
}
else if (command.version) {
    console.log(`rollup v${rollup.version}`);
}
else {
  try {
      // eslint-disable-next-line unicorn/prefer-module
      //浏览器是支持source maps的,但node环境原生不支持source maps。所以我们可以通过'source-map-support'包来实现这个功能。这样当程序执行出错的时候方便通过控制台定位到源码位置。
      require('source-map-support').install();
  }
  catch {
      // do nothing
  }
  runRollup(command);
}
exports.getConfigPath = getConfigPath;
exports.loadConfigFromCommand = loadConfigFromCommand;
exports.prettyMilliseconds = prettyMilliseconds;
exports.printTimings = printTimings;
//# sourceMappingURL=rollup.map

以上就是rollup cli开发全面系统性rollup源码分析的详细内容,更多关于rollup cli开发源码分析的资料请关注我们其它相关文章!

(0)

相关推荐

  • vue3 Vite 进阶rollup命令行使用详解

    目录 rollup介绍 以命令行方式打包 Tree Shaking Rollup 的命令行使用 命令行 format 格式 rollup.config.js 设置/获取环境变量 插件 plugins rollup介绍 开源类库优先选择 以 ESM 标准为目标的构建工具 Tree Shaking 以命令行方式打包 安装 rollup npm install -g rollup 创建 index.js 文件 import path from "path"; console.log(&quo

  • 使用rollup打包JS的方法步骤

    rollup 采用 es6 原生的模块机制进行模块的打包构建,rollup 更着眼于未来,对 commonjs 模块机制不提供内置的支持,是一款更轻量的打包工具.rollup 比较适合打包 js 的 sdk 或者封装的框架等,例如,vue 源码就是 rollup 打包的.而 webpack 比较适合打包一些应用,例如 SPA 或者同构项目等等. 创建项目 目录结构是这样的: hey-rollup/ ├── dist │ ├── bundle-name.js │ └── bundle-name.m

  • rollup打包引发对JS模块循环引用思考

    目录 引言 背景1 背景2 commonjs es modules 总结 引言 最近在项目中使用了typescript + rollup,满心欢喜测试打包结果的时候,发现打包出来的文件竟然无法运行,具体报错如下: throw new ERR_INVALID_ARG_TYPE('superCtor', 'Function', superCtor); ^ TypeError [ERR_INVALID_ARG_TYPE]: The "superCtor" argument must be o

  • 一篇文章带你从零快速上手Rollup

    前言 项目中一直用的都是webpack,前一段需要开发几个类库供其他平台使用,本来打算继续用webpack的,但感觉webpack用来开发js库,不仅繁琐而且打包后的文件体积也比较大.正好之前看vue源码,知道vue也是通过rollup打包的.这次又是开发类库的,于是就快速上手了rollup. 本篇文章是我有了一定的项目实践后,回过来给大家分享一下如何从零快速上手rollup. 什么是rollup? 系统的了解rollup之前,我们先来简单了解下What is rollup? 关于rollup的

  • rollup输出的6种格式详解

    目录 学习本文 为什么要学这个? DEMO与示例构建 一.IIFE 自执行函数 1.1 打包结果分析 1.2 如何运行 1.3 优缺点 二.CommonJS 2.1 分析打包结果 2.2 如何运行 2.3 优缺点 三.AMD 和 requirejs ! 3.1 打包结果分析 3.2 如何运行 3.3 优缺点 四.UMD 伟大的整合 4.1 打包分析 4.2 如何运行? 4.3 优缺点 五.SystemJs 六.ESM 6.1 打包分析 6.2 如何运行 总结:分别适合在什么场景使用? 学习本文

  • Vue源码之rollup环境搭建步骤详解

    目录 搭建环境 建立rollup配置文件 创建入口文件 打包前准备 打包 测试一下 搭建环境 第一步 进行初始化,在终端输入npm init -y生成package.json文件,可以记住所有开发相关的依赖. 第二步 --在终端输,入安装依赖 npm install rollup rollup-plugin-babel @babel/core @babel/preset-env --save-dev 注: 安装rollup打包工具,可能需要编译高级语法所以需要安装babel,安装babel需要在

  • rollup cli开发全面系统性rollup源码分析

    目录 引言 prefix symlink Executables(可执行文件) rollup 命令行的开发 打包生成 rollup 文件 引言 在学习 rollup CLI 之前我们需要了解 npm 中的 prefix,symlink,Executables 这三个概念. prefix 当我们使用 --global/-g 选项的时候会将包安装到 prefix 目录下,prefix 默认为 node 的安装位置.在大多数系统上,它是 /usr/local. 在 Windows 上,它是 %AppD

  • Android开发中线程池源码解析

    线程池(英语:thread pool):一种线程使用模式.线程过多会带来调度开销,进而影响缓存局部性和整体性能.而线程池维护着多个线程,等待着监督管理者分配可并发执行的任务.这避免了在处理短时间任务时创建与销毁线程的代价.线程池不仅能够保证内核的充分利用,还能防止过分调度.可用线程数量应该取决于可用的并发处理器.处理器内核.内存.网络sockets等的数量. 例如,线程数一般取cpu数量+2比较合适,线程数过多会导致额外的线程切换开销.----摘自维基百科 我们在Android或者Java开发中

  • 使用C#开发OPC Server服务器源码解析

    目录 1.需要的DLL 2.添加引用 3.OPC Server 接口开发 5.测试 OPC Server服务器服务器的开发比较繁琐,本示例采用C#提供了一种简单快速实现OPCServer的方法,已经在工程项目中应用,希望对大家有用. 1.需要的DLL 首选将需要dll放置您的开发目录下,本示例放在工程目录下的bin\x86\debug目录下 需要的dll如下图: 2.添加引用 在VS的项目中添加对FKOPCSrvApi的引用 然后在源码文件中添加 using FKOPCSrvApi; 3.OPC

  • Android开发Retrofit源码分析

    目录 项目结构 retrofit 使用 Retrofit #create ServiceMethod #parseAnnotations HttpServiceMethod#parseAnnotations 第二种 非Kotlin协程情况 DefaultCallAdapterFactory#get 第一种 Kotlin协程情况 总结 项目结构 把源码 clone 下来 , 可以看到 retrofit 整体结构如下 图 http包目录下就是一些http协议常用接口 , 比如 请求方法 url ,

  • Android开发数据结构算法ArrayList源码详解

    目录 简介 ArrayList源码讲解 初始化 扩容 增加元素 一个元素 一堆元素 删除元素 一个元素 一堆元素 修改元素 查询元素 总结 ArrayList优点 ArrayList的缺点 简介 ArrayList是List接口的一个实现类,它是一个集合容器,我们通常会通过指定泛型来存储同一类数据,ArrayList默认容器大小为10,自身可以自动扩容,当容量不足时,扩大为原来的1.5倍,和上篇文章的Vector的最大区别应该就是线程安全了,ArrayList不能保证线程安全,但我们也可以通过其

  • Android音视频开发Media FrameWork框架源码解析

    目录 一.Media FrameWork背景 二.Media Framework“路线图” 2.1 代理端 2.2 服务端 2.2.1 Source 2.2.2 Decoder 2.2.3 Renderer 2.2.4 Foundation 2.3 OMX端 2.4 Kernel端 三.media播放的流程 四.Media FrameWork源码分析 一.Media FrameWork背景 Media Framework (媒体函数库):此函数库让Android 可以播放与录制许多常见的音频与视

  • nginx源码分析configure脚本详解

    nginx源码分析--configure脚本 一.前言 在分析源码时,经常可以看到类似 #if (NGX_PCRE) .... #endif 这样的代码段,这样的设计可以在不改动源码的情况下,通过简单的定义宏的方式来实现功能的打开与关闭,但是在nginx/src目录下始终没有找到宏 NGX_PCRE 对应的 #define 语句. 在之前介绍event模块的时候,讲到init_cycle函数中对cycle进行了初始化,其中很重要一步操作就是讲包含所有module信息的数组拷贝到这个cycle对应

  • 深入浅析knockout源码分析之订阅

    Knockout.js是什么? Knockout是一款很优秀的JavaScript库,它可以帮助你仅使用一个清晰整洁的底层数据模型(data model)即可创建一个富文本且具有良好的显示和编辑功能的用户界面.任何时候你的局部UI内容需要自动更新(比如:依赖于用户行为的改变或者外部的数据源发生变化),KO都可以很简单的帮你实现,并且非常易于维护. 一.主类关系图 二.类职责 2.1.observable(普通监控对象类) observable(他其是一个function)的内部实现: 1.首先声

  • jQuery源码分析-03构造jQuery对象-工具函数

    作者:nuysoft/高云 QQ:47214707 EMail:nuysoft@gmail.com 声明:本文为原创文章,如需转载,请注明来源并保留原文链接. 读读写写,不对的地方请告诉我,多多交流共同进步,本章的的PDF等本章写完了发布. jQuery源码分析系列的目录请查看 http://nuysoft.iteye.com/blog/1177451,想系统的好好写写,目前还是从我感兴趣的部分开始,如果大家有对哪个模块感兴趣的,建议优先分析的,可以告诉我,一起学习. 3.4 其他静态工具函数

  • jQuery 1.9.1源码分析系列(十四)之常用jQuery工具

    为了给下一章分析动画处理做准备,先来看一下一些工具.其中队列工具在动画处理中被经常使用. jQuery.fn. queue(([ queueName ] [, newQueue ]) || ([ queueName ,] callback ))(获取或设置当前匹配元素上待执行的函数队列. 如果当前jQuery对象匹配多个元素:获取队列时,只获取第一个匹配元素上的队列:设置队列(替换队列.追加函数)时,则为每个匹配元素都分别进行设置.如果需要移除并执行队列中的第一个函数,请使用dequeue()函

随机推荐