├── circular-dependency ├── esmodule │ ├── README.md │ ├── demo1 │ │ ├── a.mjs │ │ └── b.mjs │ └── demo2 │ │ ├── a.mjs │ │ └── b.mjs ├── commonjs │ ├── README.md │ ├── main.js │ ├── a.js │ └── b.js ├── requirejs │ ├── app.js │ ├── index.html │ ├── a.js │ ├── b.js │ ├── package.json │ └── package-lock.json └── seajs │ ├── index.html │ ├── app.js │ ├── a.js │ ├── b.js │ ├── package.json │ ├── package-lock.json │ └── sea.js ├── swipe ├── README.md └── index.html ├── .gitignore ├── let-const ├── index.js ├── dist.js ├── build.js └── package.json ├── css-skills ├── images │ └── captain.jpeg ├── font-size-0.html ├── first-child.html ├── color.html ├── callout.html ├── ellipsis.html ├── scale.html ├── object-fit.html ├── pointer-events.html └── margin-merge.html ├── image-handler ├── images │ ├── error.jpg │ ├── loading.gif │ ├── success.jpg │ └── success_2.jpg ├── tpl.html ├── jquery.html ├── vue.1.html └── vue.2.html ├── webpack-cjs-esm ├── index.html ├── cjs │ ├── a.js │ └── app.js ├── esm │ ├── a.js │ └── app.js ├── webpack.config.js ├── package.json ├── bundle.cjs.js └── bundle.esm.js ├── tail-calls ├── error │ ├── normal.js │ └── tail-calls.js ├── call-stack │ ├── normal.js │ └── tail-calls.js ├── get-stack-depth.js ├── fibonacci │ ├── recursion.js │ └── tail-calls.js ├── factorial │ ├── recursion.js │ ├── trampoline.js │ └── tail-calls.js └── index.html ├── exports-cjs-esm ├── esm │ ├── demo1 │ │ ├── a.mjs │ │ └── b.mjs │ └── demo2 │ │ ├── b.mjs │ │ └── a.mjs └── cjs │ ├── a.js │ └── b.js ├── reverse-polish-notation ├── float.js └── index.js ├── svn-batch-operation └── svn-deploy.sh ├── css-triangle ├── border.html └── box.html ├── momentum-scrolling ├── list.html └── index.html ├── pull-damping ├── test.js └── index.html ├── README.md └── css-stacking-context └── index.html /circular-dependency/esmodule/README.md: -------------------------------------------------------------------------------- 1 | node@^8 -------------------------------------------------------------------------------- /swipe/README.md: -------------------------------------------------------------------------------- 1 | ### TODOLIST 2 | 3 | 1. 支持页码及点击页码展示子项; -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | **/node_modules 2 | **/.DS_Store 3 | **/package-lock.json -------------------------------------------------------------------------------- /let-const/index.js: -------------------------------------------------------------------------------- 1 | for (let i = 0; i < 5; i++) { 2 | var c = function() { console.log(i)}; 3 | } -------------------------------------------------------------------------------- /circular-dependency/commonjs/README.md: -------------------------------------------------------------------------------- 1 | Source code from https://nodejs.org/api/modules.html#modules_cycles -------------------------------------------------------------------------------- /css-skills/images/captain.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JaredCen/blog/HEAD/css-skills/images/captain.jpeg -------------------------------------------------------------------------------- /image-handler/images/error.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JaredCen/blog/HEAD/image-handler/images/error.jpg -------------------------------------------------------------------------------- /image-handler/images/loading.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JaredCen/blog/HEAD/image-handler/images/loading.gif -------------------------------------------------------------------------------- /image-handler/images/success.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JaredCen/blog/HEAD/image-handler/images/success.jpg -------------------------------------------------------------------------------- /image-handler/images/success_2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JaredCen/blog/HEAD/image-handler/images/success_2.jpg -------------------------------------------------------------------------------- /webpack-cjs-esm/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /tail-calls/error/normal.js: -------------------------------------------------------------------------------- 1 | function fa() { 2 | throw new Error(); 3 | } 4 | 5 | function fb() { 6 | return fa(); 7 | } 8 | 9 | fb(); -------------------------------------------------------------------------------- /circular-dependency/requirejs/app.js: -------------------------------------------------------------------------------- 1 | define(['./a', './b'], function(a, b) { 2 | console.log('app starting'); 3 | console.log('in app', a, b); 4 | }); -------------------------------------------------------------------------------- /circular-dependency/requirejs/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /exports-cjs-esm/esm/demo1/a.mjs: -------------------------------------------------------------------------------- 1 | import b from './b.mjs'; 2 | 3 | console.log(b.count); 4 | b.add(); 5 | console.log(b.count); 6 | console.log(b.get()); -------------------------------------------------------------------------------- /exports-cjs-esm/cjs/a.js: -------------------------------------------------------------------------------- 1 | const { count, add, get } = require('./b'); 2 | 3 | console.log(count); 4 | add(); 5 | console.log(count); 6 | console.log(get()); -------------------------------------------------------------------------------- /exports-cjs-esm/esm/demo2/b.mjs: -------------------------------------------------------------------------------- 1 | export let count = 1; 2 | export function add() { 3 | count++; 4 | } 5 | export function get() { 6 | return count; 7 | } -------------------------------------------------------------------------------- /exports-cjs-esm/esm/demo2/a.mjs: -------------------------------------------------------------------------------- 1 | import { count, add, get } from './b.mjs'; 2 | 3 | console.log(count); 4 | add(); 5 | console.log(count); 6 | console.log(get()); -------------------------------------------------------------------------------- /tail-calls/error/tail-calls.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | function fa() { 4 | throw new Error(); 5 | } 6 | 7 | function fb() { 8 | return fa(); 9 | } 10 | 11 | fb(); -------------------------------------------------------------------------------- /exports-cjs-esm/cjs/b.js: -------------------------------------------------------------------------------- 1 | let count = 1; 2 | 3 | module.exports = { 4 | count, 5 | add() { 6 | count++; 7 | }, 8 | get() { 9 | return count; 10 | } 11 | }; -------------------------------------------------------------------------------- /exports-cjs-esm/esm/demo1/b.mjs: -------------------------------------------------------------------------------- 1 | let count = 1; 2 | export default { 3 | count, 4 | add() { 5 | count++; 6 | }, 7 | get() { 8 | return count; 9 | } 10 | } -------------------------------------------------------------------------------- /tail-calls/call-stack/normal.js: -------------------------------------------------------------------------------- 1 | function fa(x) { 2 | return x; 3 | } 4 | 5 | function fb(x) { 6 | const b = 1; 7 | return fa(x) + b; 8 | } 9 | 10 | console.log(fb(5)); -------------------------------------------------------------------------------- /webpack-cjs-esm/cjs/a.js: -------------------------------------------------------------------------------- 1 | console.log('a starting'); 2 | const app = require('./app'); 3 | console.log('in a, app.done =', app.done); 4 | exports.done = true; 5 | console.log('a done'); -------------------------------------------------------------------------------- /webpack-cjs-esm/cjs/app.js: -------------------------------------------------------------------------------- 1 | console.log('app starting'); 2 | const a = require('./a'); 3 | console.log('in app, a.done =', a.done); 4 | exports.done = true; 5 | console.log('app done'); 6 | -------------------------------------------------------------------------------- /circular-dependency/seajs/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | 8 | -------------------------------------------------------------------------------- /tail-calls/call-stack/tail-calls.js: -------------------------------------------------------------------------------- 1 | function fa(x, y) { 2 | return x + y; 3 | } 4 | 5 | function fb(x) { 6 | const b = 1; 7 | return fa(x, b); 8 | } 9 | 10 | console.log(fb(5)); -------------------------------------------------------------------------------- /circular-dependency/seajs/app.js: -------------------------------------------------------------------------------- 1 | define(function(require) { 2 | console.log('app starting'); 3 | var a = require('./a'); 4 | var b = require('./b'); 5 | console.log('in app', a, b); 6 | }); -------------------------------------------------------------------------------- /reverse-polish-notation/float.js: -------------------------------------------------------------------------------- 1 | console.log('0.1 + 0.2 =', 0.1 + 0.2); 2 | console.log('1 - 0.9 =', 1 - 0.9); 3 | console.log('19.9 * 100 =', 19.9 * 100); 4 | console.log('0.3 / 0.1 =', 0.3 / 0.1); -------------------------------------------------------------------------------- /tail-calls/get-stack-depth.js: -------------------------------------------------------------------------------- 1 | function getDeep() { 2 | try { 3 | return 1 + getDeep(); 4 | } catch(e) { 5 | return 1; 6 | } 7 | } 8 | 9 | // 12500 10 | console.log(getDeep()); -------------------------------------------------------------------------------- /webpack-cjs-esm/esm/a.js: -------------------------------------------------------------------------------- 1 | console.log('a starting'); 2 | export default { 3 | done: true, 4 | } 5 | import app from './app'; 6 | console.log('in a, app.done =', app.done); 7 | console.log('a done'); -------------------------------------------------------------------------------- /webpack-cjs-esm/esm/app.js: -------------------------------------------------------------------------------- 1 | console.log('app starting'); 2 | export default { 3 | done: true, 4 | } 5 | import a from './a'; 6 | console.log('in app, a.done =', a.done); 7 | console.log('app done'); -------------------------------------------------------------------------------- /circular-dependency/commonjs/main.js: -------------------------------------------------------------------------------- 1 | console.log('main starting'); 2 | const a = require('./a.js'); 3 | const b = require('./b.js'); 4 | console.log('in main, a.done = %j, b.done = %j', a.done, b.done); -------------------------------------------------------------------------------- /circular-dependency/esmodule/demo1/a.mjs: -------------------------------------------------------------------------------- 1 | console.log('a starting'); 2 | export default { 3 | done: true, 4 | } 5 | import b from './b.mjs'; 6 | console.log('in a, b.done = %j', b.done); 7 | console.log('a done'); -------------------------------------------------------------------------------- /circular-dependency/esmodule/demo1/b.mjs: -------------------------------------------------------------------------------- 1 | console.log('b starting'); 2 | export default { 3 | done: true, 4 | } 5 | import a from './a.mjs'; 6 | console.log('in b, a.done = %j', a.done); 7 | console.log('b done'); -------------------------------------------------------------------------------- /circular-dependency/esmodule/demo2/a.mjs: -------------------------------------------------------------------------------- 1 | import b from './b.mjs'; 2 | console.log('a starting'); 3 | console.log(b()); 4 | export default function () { 5 | return 'run func A'; 6 | } 7 | console.log('a done'); -------------------------------------------------------------------------------- /circular-dependency/esmodule/demo2/b.mjs: -------------------------------------------------------------------------------- 1 | import a from './a.mjs'; 2 | console.log('b starting'); 3 | console.log(a()); 4 | export default function () { 5 | return 'run func B'; 6 | } 7 | console.log('b done'); -------------------------------------------------------------------------------- /circular-dependency/commonjs/a.js: -------------------------------------------------------------------------------- 1 | console.log('a starting'); 2 | exports.done = false; 3 | const b = require('./b.js'); 4 | console.log('in a, b.done = %j', b.done); 5 | exports.done = true; 6 | console.log('a done'); -------------------------------------------------------------------------------- /circular-dependency/commonjs/b.js: -------------------------------------------------------------------------------- 1 | console.log('b starting'); 2 | exports.done = false; 3 | const a = require('./a.js'); 4 | console.log('in b, a.done = %j', a.done); 5 | exports.done = true; 6 | console.log('b done'); -------------------------------------------------------------------------------- /let-const/dist.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | var _loop = function _loop(i) { 4 | c = function c() { 5 | console.log(i); 6 | }; 7 | }; 8 | 9 | for (var i = 0; i < 5; i++) { 10 | var c; 11 | 12 | _loop(i); 13 | } -------------------------------------------------------------------------------- /circular-dependency/requirejs/a.js: -------------------------------------------------------------------------------- 1 | define(['./b', 'exports'], function(b, exports) { 2 | console.log('a starting'); 3 | exports.done = false; 4 | console.log('in a, b.done =', b.done); 5 | console.log('a done'); 6 | exports.done = true; 7 | }); -------------------------------------------------------------------------------- /circular-dependency/requirejs/b.js: -------------------------------------------------------------------------------- 1 | define(['./a', 'exports'], function(a, exports) { 2 | console.log('b starting'); 3 | exports.done = false; 4 | console.log('in b, a.done =', a.done); 5 | console.log('b done'); 6 | exports.done = true; 7 | }); -------------------------------------------------------------------------------- /circular-dependency/seajs/a.js: -------------------------------------------------------------------------------- 1 | define(function(require, exports) { 2 | console.log('a starting'); 3 | exports.done = false; 4 | var b = require('./b'); 5 | console.log('in a, b.done =', b.done); 6 | console.log('a done'); 7 | exports.done = true; 8 | }); -------------------------------------------------------------------------------- /circular-dependency/seajs/b.js: -------------------------------------------------------------------------------- 1 | define(function(require, exports) { 2 | console.log('b starting'); 3 | exports.done = false; 4 | var a = require('./a'); 5 | console.log('in b, a.done =', a.done); 6 | console.log('b done'); 7 | exports.done = true; 8 | }); -------------------------------------------------------------------------------- /tail-calls/fibonacci/recursion.js: -------------------------------------------------------------------------------- 1 | let count = 0; 2 | function fib(n) { 3 | count++; 4 | return n <= 1 ? 1 : fib(n - 1) + fib(n - 2); 5 | } 6 | const n = 40; 7 | try { 8 | fib(n); 9 | console.log(`[success], n = ${n}, num = ${count}`); 10 | } catch(e) { 11 | console.log(`[stack overflow], num = ${count}`); 12 | } -------------------------------------------------------------------------------- /let-const/build.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs'); 2 | const path = require('path'); 3 | const babel = require('@babel/core'); 4 | 5 | babel.transformFile(path.resolve(__dirname, './index.js'), {}, (err, result) => { 6 | if (!err) fs.writeFile('dist.js', result.code, (err) => { 7 | if (!err) console.log(`编译完成:dist.js`); 8 | }); 9 | }); -------------------------------------------------------------------------------- /tail-calls/factorial/recursion.js: -------------------------------------------------------------------------------- 1 | let count = 0; 2 | function factorial(n) { 3 | count++; 4 | return n === 1 ? 1 : n * factorial(n - 1); 5 | } 6 | const n = 100000; 7 | try { 8 | factorial(n); 9 | console.log(`[success], n = ${n}, num = ${count}`); 10 | } catch(e) { 11 | console.log(`[stack overflow], num = ${count}`); 12 | } -------------------------------------------------------------------------------- /css-skills/font-size-0.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 9 | 10 |
11 | 12 | 13 |
14 | 15 | -------------------------------------------------------------------------------- /circular-dependency/seajs/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "circular-dependency-seajs-demo", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "a.js", 6 | "scripts": { 7 | "serve": "http-server" 8 | }, 9 | "author": "Junrey", 10 | "license": "ISC", 11 | "devDependencies": { 12 | "http-server": "^0.11.1" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /tail-calls/fibonacci/tail-calls.js: -------------------------------------------------------------------------------- 1 | let count = 0; 2 | function fib(n, ac1 = 1, ac2 = 1) { 3 | count++; 4 | return n <= 1 ? ac2 : fib(n - 1, ac2, ac1 + ac2); 5 | } 6 | const n = 40; 7 | try { 8 | console.log(fib(n)); 9 | console.log(`[success], n = ${n}, num = ${count}`); 10 | } catch(e) { 11 | console.log(`[stack overflow], num = ${count}`); 12 | } -------------------------------------------------------------------------------- /circular-dependency/requirejs/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "circular-dependency-requirejs-demo", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "serve": "http-server" 8 | }, 9 | "author": "Junrey", 10 | "license": "ISC", 11 | "devDependencies": { 12 | "http-server": "^0.11.1" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /tail-calls/factorial/trampoline.js: -------------------------------------------------------------------------------- 1 | function trampoline(f) { 2 | while (f && f instanceof Function) { 3 | f = f(); 4 | } 5 | return f; 6 | } 7 | 8 | function factorial(n, r = 1) { 9 | return n === 1 ? r : factorial.bind(null, n - 1, n * r); 10 | } 11 | 12 | console.time('t1'); 13 | console.log(trampoline(factorial(100000))); 14 | console.timeEnd('t1'); -------------------------------------------------------------------------------- /tail-calls/factorial/tail-calls.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | let count = 0; 4 | function factorial(n, r = 1) { 5 | count++; 6 | return n === 1 ? r : factorial(n - 1, n * r); 7 | } 8 | const n = 100000; 9 | try { 10 | factorial(n); 11 | console.log(`[success], n = ${n}, num = ${count}`); 12 | } catch(e) { 13 | console.log(`[stack overflow], num = ${count}`); 14 | } -------------------------------------------------------------------------------- /webpack-cjs-esm/webpack.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | 3 | module.exports = { 4 | mode: 'production', 5 | entry: { 6 | cjs: './cjs/app.js', 7 | esm: './esm/app.js', 8 | }, 9 | output: { 10 | filename: 'bundle.[name].js', 11 | path: path.resolve(__dirname), 12 | }, 13 | optimization: { 14 | minimize: false, 15 | concatenateModules: false, 16 | }, 17 | }; -------------------------------------------------------------------------------- /let-const/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "let-const", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "build": "node ./build.js" 8 | }, 9 | "author": "", 10 | "license": "ISC", 11 | "devDependencies": { 12 | "@babel/core": "^7.4.5", 13 | "@babel/preset-env": "^7.4.5" 14 | }, 15 | "babel": { 16 | "presets": [ 17 | "@babel/preset-env" 18 | ] 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /webpack-cjs-esm/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "webpack-cjs-esm", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "serve": "http-server", 8 | "build": "webpack --config webpack.config.js" 9 | }, 10 | "author": "cenjw", 11 | "license": "ISC", 12 | "devDependencies": { 13 | "http-server": "^0.11.1", 14 | "webpack": "^4.29.6", 15 | "webpack-cli": "^3.3.0" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /css-skills/first-child.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 11 | 12 | 13 |
14 |

父元素的第一个元素,第一个 h2 元素

15 |

父元素的第二个元素,第一个 h3 元素

16 |
17 |
18 |

父元素的第一个元素,第一个 h2 元素

19 |

父元素的第二个元素,第一个 h3 元素

20 |
21 | 22 | -------------------------------------------------------------------------------- /tail-calls/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /svn-batch-operation/svn-deploy.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | while getopts :s:d:m: opt 4 | do 5 | case "$opt" in 6 | s) SRC_DIR=$OPTARG ;; # 源目录 7 | d) SVN_DIR=$OPTARG ;; # svn目录 8 | m) COMMIT_INFO=$OPTARG ;; # commit info 9 | *) 10 | echo "ERROR: unknown option" 11 | exit 0 ;; 12 | esac 13 | done 14 | 15 | # 设置-s,-d参数必填 16 | if [ -z $SRC_DIR ] || [ -z $SVN_DIR ] 17 | then 18 | echo "ERROR: options -s, -d is null"; 19 | exit 0; 20 | fi 21 | 22 | cd $SVN_DIR 23 | svn update 24 | svn delete * 25 | cp -rf $SRC_DIR/* $SVN_DIR 26 | svn add * 27 | svn commit -m "$COMMIT_INFO" 28 | 29 | # cd $SVN_DIR 30 | # svn update 31 | # rm -rf * 32 | # cp -rf $SRC_DIR/* $SVN_DIR 33 | # svn add `svn st | grep "^?"| awk '{print $2}'` 34 | # svn delete `svn st | grep "^!" | awk '{print $2}'` 35 | # svn commit -m $COMMIT_INFO -------------------------------------------------------------------------------- /css-skills/color.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 14 | 15 | 16 |

这里没有做任何处理

17 |

这里设置了 border,但不指定 border-color

18 |

这里设置了 outline,但不指定 outline-color

19 |

这里设置了 text-decoration,但不指定 text-decoration-color

20 |

这里设置了 box-shadow,但不指定颜色

21 |

这里设置了 text-shadow,但不指定颜色

22 |
23 | 这里设置了 column-rule,但不指定 column-rule-color 24 | 第二列第二列第二列第二列第二列第二列第二列第二列 25 |
26 | 27 | -------------------------------------------------------------------------------- /css-triangle/border.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 39 | 40 | 41 |
42 | 盒模型 43 |
44 |
45 | 46 | -------------------------------------------------------------------------------- /momentum-scrolling/list.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 20 | 21 | 22 |
23 | 24 | 29 | 30 | 31 | 46 | 47 | -------------------------------------------------------------------------------- /css-skills/callout.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 13 | 14 | 15 |

这里没有做任何处理

16 |

这里拦截了 contextmenu 事件

17 |

这里设置了 -webkit-user-select: none;

18 |

这里设置了 user-select: none;

19 | 24 |

这里拦截了 touchstart 事件

25 | 35 | 36 | -------------------------------------------------------------------------------- /image-handler/tpl.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 17 | 18 | 19 |
20 | 21 | 29 | 30 | 31 | 32 | 41 | 42 | -------------------------------------------------------------------------------- /pull-damping/test.js: -------------------------------------------------------------------------------- 1 | function linear(x, max) { 2 | const breakPoints = [ 3 | 0, 4 | max, 5 | max * 2, 6 | max * 3, 7 | max * 5, 8 | max * 12, 9 | ]; 10 | const factors = [ 11 | 0.18, 12 | 0.14, 13 | 0.1, 14 | 0.05, 15 | 0.025, 16 | 0.005, 17 | ]; 18 | 19 | let y = Math.abs(x); 20 | for (let i = breakPoints.length; i > 0; i--) { 21 | if (y > breakPoints[i - 1]) { 22 | y = (y - breakPoints[i - 1]) * factors[i - 1]; 23 | for (let j = i - 1; j > 0; j--) { 24 | y += (breakPoints[j] - breakPoints[j - 1]) * factors[j - 1]; 25 | } 26 | break; 27 | } 28 | } 29 | return Math.round(x < 0 ? -y : y); 30 | } 31 | 32 | function pow(x, max) { 33 | let y = Math.abs(x); 34 | y = 0.12 * max * Math.pow(y, 1/5); 35 | return Math.round(x < 0 ? -y : y); 36 | } 37 | 38 | function log(x, max) { 39 | let y = Math.abs(x); 40 | y = 0.08 * max * Math.log(y + 1); 41 | return Math.round(x < 0 ? -y : y); 42 | } 43 | 44 | function curve(x, max) { 45 | let y = Math.abs(x); 46 | y = 0.82231 * max / (1 + 4338.47 / Math.pow(y, 1.14791)); 47 | return Math.round(x < 0 ? -y : y); 48 | } 49 | 50 | console.time('linear'); 51 | linear(6000, 500); 52 | console.timeEnd('linear'); 53 | console.time('pow'); 54 | pow(6000, 500); 55 | console.timeEnd('pow'); 56 | console.time('log'); 57 | log(6000, 500); 58 | console.timeEnd('log'); 59 | console.time('curve'); 60 | curve(6000, 500); 61 | console.timeEnd('curve'); -------------------------------------------------------------------------------- /image-handler/jquery.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 17 | 18 | 19 |
20 |
21 |
22 | 23 | 24 | 47 | 48 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Demo 目录和对应文章 2 | 3 | | Demo Dir | Article Link | 4 | |----------|--------------| 5 | | circular-dependency | [Commonjs、esm、Amd和Cmd的循环依赖表现和原理](https://github.com/JunreyCen/blog-demo/issues/2) | 6 | | exports-cjs-esm | [如何正确证明Commonjs模块导出是值的拷贝,而ES module是值的引用?](https://github.com/JunreyCen/blog-demo/issues/1) | 7 | | svn-batch-operation | [Mac/Linux svn命令行批量处理及自动化部署](https://github.com/JunreyCen/blog-demo/issues/3) | 8 | | tail-calls | [关于 Javascript 尾调用优化的错误论证](https://github.com/JunreyCen/blog-demo/issues/4) | 9 | | reverse-polish-notation | [利用栈实现四则混合运算引擎](https://github.com/JunreyCen/blog-demo/issues/5) | 10 | | swipe | [Vue 实现无缝轮播](https://github.com/JunreyCen/blog-demo/issues/6) | 11 | | momentum-scrolling | [物理学的 H5 应用:模拟惯性滑动](https://github.com/JunreyCen/blog-demo/issues/7) | 12 | | pull-damping | [数学的 H5 应用:拖动阻尼](https://github.com/JunreyCen/blog-demo/issues/8) | 13 | | image-handler | [Vue 和 jQuery 的图片容错处理方案](https://github.com/JunreyCen/blog-demo/issues/9) | 14 | | css-triangle | [CSS 精确绘制三角形](https://github.com/JunreyCen/blog/issues/16) | 15 | | css-skills | [CSS 技巧收录](https://github.com/JunreyCen/blog/issues/17) | 16 | | css-stacking-context | [深入浅出 CSS 层叠上下文](https://github.com/JunreyCen/blog/issues/19) | 17 | 18 | ## 其他文章 19 | 20 | - [CSS 权重详解](https://github.com/JunreyCen/blog/issues/18) 21 | - [Mac 设置 Git 代理](https://github.com/JunreyCen/blog/issues/15) 22 | - [Mac 终端设置代理](https://github.com/JunreyCen/blog/issues/14) 23 | - [Git 使用技巧](https://github.com/JunreyCen/blog/issues/13) 24 | - [JS 运算符技巧](https://github.com/JunreyCen/blog/issues/12) 25 | - [NaN 和 isNaN 的彩蛋](https://github.com/JunreyCen/blog/issues/11) 26 | - [JS 稀疏数组](https://github.com/JunreyCen/blog/issues/10) -------------------------------------------------------------------------------- /css-skills/ellipsis.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 39 | 40 | 41 |

单行文本字数超出时显示省略号,单行文本字数超出时显示省略号

42 |

line-clamp 设置多行文本字数超出时最后一行显示省略号,line-clamp 设置多行文本字数超出时最后一行显示省略号

43 |

JS 和 CSS 设置多行文本字数超出时最后一行显示省略号,JS 和 CSS 设置多行文本字数超出时最后一行显示省略号

44 | 53 | 54 | -------------------------------------------------------------------------------- /image-handler/vue.1.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 17 | 18 | 19 |
20 | 21 | 28 | 29 | 30 | 75 | 76 | -------------------------------------------------------------------------------- /css-skills/scale.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 65 | 66 | 67 |
68 | 百分比宽高 69 |
70 |
71 |
72 | 利用 padding 等比缩放 73 |
74 |
75 |
76 |
77 |
78 | 200 x 300 79 |
80 | 200 x 200 81 |
82 |
83 | 93 | 94 | -------------------------------------------------------------------------------- /css-skills/object-fit.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 24 | 25 | 26 |

使用背景图

27 |
28 | 不设置 background-size 29 |
30 |
31 |
32 | background-size: contain; 33 |
34 |
35 |
36 | background-size: contain;
background-position: center;
37 |
38 |
39 |
40 | background-size: 100% 100%; 41 |
42 |
43 |
44 | background-size: cover;
background-position: center;
45 |
46 |
47 |

使用 img 标签

48 |
49 | object-fit: none; 50 | 51 |
52 |
53 | object-fit: contain;
object-position: 0 0;
54 | 55 |
56 |
57 | object-fit: contain; 58 | 59 |
60 |
61 | object-fit: fill; 62 | 63 |
64 |
65 | object-fit: cover; 66 | 67 |
68 |
69 | object-fit: scale-down; 70 | 71 |
72 | 73 | -------------------------------------------------------------------------------- /reverse-polish-notation/index.js: -------------------------------------------------------------------------------- 1 | function Calculate(options = {}) { 2 | // 运算符权重 3 | this.weight = options.weight || { 4 | '+': 1, 5 | '-': 1, 6 | '*': 2, 7 | '/': 2, 8 | }; 9 | // 小数位精度 10 | this.precision = options.precision || 2; 11 | this.operatorStack = []; // 运算符栈 12 | this.outputQueue = []; // 逆波兰表达式队列 13 | } 14 | 15 | Calculate.prototype = { 16 | 17 | /** 18 | * @desc 四则运算,浮点数处理 19 | */ 20 | operate(left, right, operator) { 21 | const factor = +'1000000000000'.slice(0, this.precision + 1); 22 | if (operator === '+') { 23 | return Math.round(left * factor + right * factor) / factor; 24 | } else if (operator === '-') { 25 | return Math.round(left * factor - right * factor) / factor; 26 | } else if (operator === '*') { 27 | return Math.round(left * right * factor) / factor; 28 | } else if (operator === '/') { 29 | return Math.round(left / right * factor) / factor; 30 | } 31 | }, 32 | 33 | /** 34 | * @desc 调度场算法 35 | */ 36 | shuntingYard(token) { 37 | if (!isNaN(+token)) { 38 | this.outputQueue.push(+token); 39 | } else if (token === '(') { 40 | this.operatorStack.push(token); 41 | } else if (token === ')') { 42 | let top = this.operatorStack.pop(); 43 | while (top && top !== '(') { 44 | this.outputQueue.push(top); 45 | top = this.operatorStack.pop(); 46 | } 47 | if (!top) throw new Error('表达式格式错误:括号不闭合'); 48 | } else { 49 | let top = this.operatorStack.pop(); 50 | while (top && top !== '(' && this.weight[token] <= this.weight[top]) { 51 | this.outputQueue.push(top); 52 | top = this.operatorStack.pop(); 53 | } 54 | top ? this.operatorStack.push(top, token) : this.operatorStack.push(token); 55 | } 56 | }, 57 | 58 | /** 59 | * @desc 计算逆波兰表达式 60 | */ 61 | calRpn() { 62 | const stack = []; 63 | while (this.outputQueue.length) { 64 | let token = this.outputQueue.shift(); 65 | if (typeof token === 'number') { 66 | stack.push(token); 67 | } else { 68 | const right = stack.pop(); 69 | const left = stack.pop(); 70 | if (!right || !left) throw new Error('计算错误'); 71 | stack.push(this.operate(left, right, token)); 72 | } 73 | } 74 | if (stack.length !== 1) throw new Error('计算错误'); 75 | return stack[0]; 76 | }, 77 | 78 | /** 79 | * @desc 校验表达式合法性,预处理等 80 | * @todo 更详细的格式校验 81 | */ 82 | preValid(expStr) { 83 | return expStr; 84 | }, 85 | 86 | run(expStr) { 87 | this.operatorStack = []; 88 | this.outputQueue = []; 89 | 90 | let chars; 91 | const str = this.preValid(expStr); 92 | const reg = /(((? 2 | 3 | 93 | 94 | 95 |
96 | 盒模型 97 |
98 |
99 |
100 | 内容宽高为0 101 |
102 |
103 |
104 | 内容宽高为0,顶部边框宽为0 105 |
106 |
107 |
108 | 实心三角形 109 |
110 |
111 |
112 | 非直角三角形 113 |
114 |
115 |
116 | 空心三角形 117 |
118 |
119 |
120 | 箭头 121 |
122 | 1px边框 123 |
124 |
125 | 126 | -------------------------------------------------------------------------------- /image-handler/vue.2.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 20 | 21 | 22 |
23 | 24 | 31 | 32 | 33 | 118 | 119 | -------------------------------------------------------------------------------- /css-skills/pointer-events.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 84 | 85 | 86 |

1. 对事件传递的影响

87 |
88 | 不作处理 89 |
90 | parent 91 |
92 | target 93 |
94 | child 95 |
96 |
97 |
98 |
99 |
100 | target 设置 pointer-events: none; 101 |
102 | parent 103 |
104 | target 105 |
106 | child 107 |
108 |
109 |
110 |
111 |

2. 点击穿透,避免同层元素的遮盖

112 |
113 | 不作处理 114 |
115 | 116 |
117 |
118 |
119 | :after 设置 pointer-events: none; 120 |
121 | 122 |
123 |
124 |

3. 阻止 :hover 等鼠标行为

125 |
126 | 鼠标 hover 时变为蓝色 127 |
128 |
129 |
130 | 设置 pointer-events: none;
不响应 hover
131 |
132 |
133 | 134 | -------------------------------------------------------------------------------- /css-skills/margin-merge.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 53 | 54 | 55 |

1. 相邻的垂直外边距会合并

56 |
57 | 外边距都为正数 58 |
59 | margin-bottom: 20px; 60 |
61 |
62 | margin-top: 10px; 63 |
64 |
65 |
66 | 外边距一正一负 67 |
68 | margin-bottom: 20px; 69 |
70 |
71 | margin-top: -10px; 72 |
73 |
74 |
75 | 外边距都为负数 76 |
77 | margin-bottom: -20px; 78 |
79 |
80 | margin-top: -10px; 81 |
82 |
83 |

2. 无内边距和边框的父元素的垂直外边距会与子元素的垂直外边距合并

84 |
85 | 父元素 margin: 20px;
子元素 margin: 10px; 86 |
87 |
88 |
89 |
90 |
91 | 水平外边距差为:
垂直外边距差为: 92 |
93 |

3. 空元素的垂直外边距会合并

94 |
95 | margin: 50px 100px; 96 |
97 |
98 |
99 | 水平外边距差为:
垂直外边距差为: 100 |
101 | 102 | 118 | 119 | -------------------------------------------------------------------------------- /webpack-cjs-esm/bundle.cjs.js: -------------------------------------------------------------------------------- 1 | /******/ (function(modules) { // webpackBootstrap 2 | /******/ // The module cache 3 | /******/ var installedModules = {}; 4 | /******/ 5 | /******/ // The require function 6 | /******/ function __webpack_require__(moduleId) { 7 | /******/ 8 | /******/ // Check if module is in cache 9 | /******/ if(installedModules[moduleId]) { 10 | /******/ return installedModules[moduleId].exports; 11 | /******/ } 12 | /******/ // Create a new module (and put it into the cache) 13 | /******/ var module = installedModules[moduleId] = { 14 | /******/ i: moduleId, 15 | /******/ l: false, 16 | /******/ exports: {} 17 | /******/ }; 18 | /******/ 19 | /******/ // Execute the module function 20 | /******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); 21 | /******/ 22 | /******/ // Flag the module as loaded 23 | /******/ module.l = true; 24 | /******/ 25 | /******/ // Return the exports of the module 26 | /******/ return module.exports; 27 | /******/ } 28 | /******/ 29 | /******/ 30 | /******/ // expose the modules object (__webpack_modules__) 31 | /******/ __webpack_require__.m = modules; 32 | /******/ 33 | /******/ // expose the module cache 34 | /******/ __webpack_require__.c = installedModules; 35 | /******/ 36 | /******/ // define getter function for harmony exports 37 | /******/ __webpack_require__.d = function(exports, name, getter) { 38 | /******/ if(!__webpack_require__.o(exports, name)) { 39 | /******/ Object.defineProperty(exports, name, { enumerable: true, get: getter }); 40 | /******/ } 41 | /******/ }; 42 | /******/ 43 | /******/ // define __esModule on exports 44 | /******/ __webpack_require__.r = function(exports) { 45 | /******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) { 46 | /******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); 47 | /******/ } 48 | /******/ Object.defineProperty(exports, '__esModule', { value: true }); 49 | /******/ }; 50 | /******/ 51 | /******/ // create a fake namespace object 52 | /******/ // mode & 1: value is a module id, require it 53 | /******/ // mode & 2: merge all properties of value into the ns 54 | /******/ // mode & 4: return value when already ns object 55 | /******/ // mode & 8|1: behave like require 56 | /******/ __webpack_require__.t = function(value, mode) { 57 | /******/ if(mode & 1) value = __webpack_require__(value); 58 | /******/ if(mode & 8) return value; 59 | /******/ if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value; 60 | /******/ var ns = Object.create(null); 61 | /******/ __webpack_require__.r(ns); 62 | /******/ Object.defineProperty(ns, 'default', { enumerable: true, value: value }); 63 | /******/ if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key)); 64 | /******/ return ns; 65 | /******/ }; 66 | /******/ 67 | /******/ // getDefaultExport function for compatibility with non-harmony modules 68 | /******/ __webpack_require__.n = function(module) { 69 | /******/ var getter = module && module.__esModule ? 70 | /******/ function getDefault() { return module['default']; } : 71 | /******/ function getModuleExports() { return module; }; 72 | /******/ __webpack_require__.d(getter, 'a', getter); 73 | /******/ return getter; 74 | /******/ }; 75 | /******/ 76 | /******/ // Object.prototype.hasOwnProperty.call 77 | /******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; 78 | /******/ 79 | /******/ // __webpack_public_path__ 80 | /******/ __webpack_require__.p = ""; 81 | /******/ 82 | /******/ 83 | /******/ // Load entry module and return exports 84 | /******/ return __webpack_require__(__webpack_require__.s = 1); 85 | /******/ }) 86 | /************************************************************************/ 87 | /******/ ([ 88 | /* 0 */, 89 | /* 1 */ 90 | /***/ (function(module, exports, __webpack_require__) { 91 | 92 | console.log('app starting'); 93 | const a = __webpack_require__(3); 94 | console.log('in app, a.done =', a.done); 95 | exports.done = true; 96 | console.log('app done'); 97 | 98 | 99 | /***/ }), 100 | /* 2 */, 101 | /* 3 */ 102 | /***/ (function(module, exports, __webpack_require__) { 103 | 104 | console.log('a starting'); 105 | const app = __webpack_require__(1); 106 | console.log('in a, app.done =', app.done); 107 | exports.done = true; 108 | console.log('a done'); 109 | 110 | /***/ }) 111 | /******/ ]); -------------------------------------------------------------------------------- /webpack-cjs-esm/bundle.esm.js: -------------------------------------------------------------------------------- 1 | /******/ (function(modules) { // webpackBootstrap 2 | /******/ // The module cache 3 | /******/ var installedModules = {}; 4 | /******/ 5 | /******/ // The require function 6 | /******/ function __webpack_require__(moduleId) { 7 | /******/ 8 | /******/ // Check if module is in cache 9 | /******/ if(installedModules[moduleId]) { 10 | /******/ return installedModules[moduleId].exports; 11 | /******/ } 12 | /******/ // Create a new module (and put it into the cache) 13 | /******/ var module = installedModules[moduleId] = { 14 | /******/ i: moduleId, 15 | /******/ l: false, 16 | /******/ exports: {} 17 | /******/ }; 18 | /******/ 19 | /******/ // Execute the module function 20 | /******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); 21 | /******/ 22 | /******/ // Flag the module as loaded 23 | /******/ module.l = true; 24 | /******/ 25 | /******/ // Return the exports of the module 26 | /******/ return module.exports; 27 | /******/ } 28 | /******/ 29 | /******/ 30 | /******/ // expose the modules object (__webpack_modules__) 31 | /******/ __webpack_require__.m = modules; 32 | /******/ 33 | /******/ // expose the module cache 34 | /******/ __webpack_require__.c = installedModules; 35 | /******/ 36 | /******/ // define getter function for harmony exports 37 | /******/ __webpack_require__.d = function(exports, name, getter) { 38 | /******/ if(!__webpack_require__.o(exports, name)) { 39 | /******/ Object.defineProperty(exports, name, { enumerable: true, get: getter }); 40 | /******/ } 41 | /******/ }; 42 | /******/ 43 | /******/ // define __esModule on exports 44 | /******/ __webpack_require__.r = function(exports) { 45 | /******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) { 46 | /******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); 47 | /******/ } 48 | /******/ Object.defineProperty(exports, '__esModule', { value: true }); 49 | /******/ }; 50 | /******/ 51 | /******/ // create a fake namespace object 52 | /******/ // mode & 1: value is a module id, require it 53 | /******/ // mode & 2: merge all properties of value into the ns 54 | /******/ // mode & 4: return value when already ns object 55 | /******/ // mode & 8|1: behave like require 56 | /******/ __webpack_require__.t = function(value, mode) { 57 | /******/ if(mode & 1) value = __webpack_require__(value); 58 | /******/ if(mode & 8) return value; 59 | /******/ if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value; 60 | /******/ var ns = Object.create(null); 61 | /******/ __webpack_require__.r(ns); 62 | /******/ Object.defineProperty(ns, 'default', { enumerable: true, value: value }); 63 | /******/ if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key)); 64 | /******/ return ns; 65 | /******/ }; 66 | /******/ 67 | /******/ // getDefaultExport function for compatibility with non-harmony modules 68 | /******/ __webpack_require__.n = function(module) { 69 | /******/ var getter = module && module.__esModule ? 70 | /******/ function getDefault() { return module['default']; } : 71 | /******/ function getModuleExports() { return module; }; 72 | /******/ __webpack_require__.d(getter, 'a', getter); 73 | /******/ return getter; 74 | /******/ }; 75 | /******/ 76 | /******/ // Object.prototype.hasOwnProperty.call 77 | /******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; 78 | /******/ 79 | /******/ // __webpack_public_path__ 80 | /******/ __webpack_require__.p = ""; 81 | /******/ 82 | /******/ 83 | /******/ // Load entry module and return exports 84 | /******/ return __webpack_require__(__webpack_require__.s = 0); 85 | /******/ }) 86 | /************************************************************************/ 87 | /******/ ([ 88 | /* 0 */ 89 | /***/ (function(module, __webpack_exports__, __webpack_require__) { 90 | 91 | "use strict"; 92 | __webpack_require__.r(__webpack_exports__); 93 | /* harmony import */ var _a__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(2); 94 | console.log('app starting'); 95 | /* harmony default export */ __webpack_exports__["default"] = ({ 96 | done: true, 97 | }); 98 | 99 | console.log('in app, a.done =', _a__WEBPACK_IMPORTED_MODULE_0__[/* default */ "a"].done); 100 | console.log('app done'); 101 | 102 | /***/ }), 103 | /* 1 */, 104 | /* 2 */ 105 | /***/ (function(module, __webpack_exports__, __webpack_require__) { 106 | 107 | "use strict"; 108 | /* harmony import */ var _app__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(0); 109 | console.log('a starting'); 110 | /* harmony default export */ __webpack_exports__["a"] = ({ 111 | done: true, 112 | }); 113 | 114 | console.log('in a, app.done =', _app__WEBPACK_IMPORTED_MODULE_0__["default"].done); 115 | console.log('a done'); 116 | 117 | /***/ }) 118 | /******/ ]); -------------------------------------------------------------------------------- /swipe/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 44 | 45 | 46 |
47 | 48 | 61 | 62 | 63 | 154 | 155 | -------------------------------------------------------------------------------- /pull-damping/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 38 | 39 | 40 |
41 | 42 | 62 | 63 | 64 | 181 | 182 | -------------------------------------------------------------------------------- /circular-dependency/seajs/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "seajs-demo", 3 | "version": "1.0.0", 4 | "lockfileVersion": 1, 5 | "requires": true, 6 | "dependencies": { 7 | "async": { 8 | "version": "1.5.2", 9 | "resolved": "http://registry-npm.firstshare.cn/async/-/async-1.5.2.tgz", 10 | "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=", 11 | "dev": true 12 | }, 13 | "colors": { 14 | "version": "1.0.3", 15 | "resolved": "http://registry-npm.firstshare.cn/colors/-/colors-1.0.3.tgz", 16 | "integrity": "sha1-BDP0TYCWgP3rYO0mDxsMJi6CpAs=", 17 | "dev": true 18 | }, 19 | "corser": { 20 | "version": "2.0.1", 21 | "resolved": "http://registry-npm.firstshare.cn/corser/-/corser-2.0.1.tgz", 22 | "integrity": "sha1-jtolLsqrWEDc2XXOuQ2TcMgZ/4c=", 23 | "dev": true 24 | }, 25 | "debug": { 26 | "version": "3.2.6", 27 | "resolved": "http://registry-npm.firstshare.cn/debug/-/debug-3.2.6.tgz", 28 | "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", 29 | "dev": true, 30 | "requires": { 31 | "ms": "^2.1.1" 32 | } 33 | }, 34 | "ecstatic": { 35 | "version": "3.3.1", 36 | "resolved": "http://registry-npm.firstshare.cn/ecstatic/-/ecstatic-3.3.1.tgz", 37 | "integrity": "sha512-/rrctvxZ78HMI/tPIsqdvFKHHscxR3IJuKrZI2ZoUgkt2SiufyLFBmcco+aqQBIu6P1qBsUNG3drAAGLx80vTQ==", 38 | "dev": true, 39 | "requires": { 40 | "he": "^1.1.1", 41 | "mime": "^1.6.0", 42 | "minimist": "^1.1.0", 43 | "url-join": "^2.0.5" 44 | } 45 | }, 46 | "eventemitter3": { 47 | "version": "3.1.0", 48 | "resolved": "http://registry-npm.firstshare.cn/eventemitter3/-/eventemitter3-3.1.0.tgz", 49 | "integrity": "sha512-ivIvhpq/Y0uSjcHDcOIccjmYjGLcP09MFGE7ysAwkAvkXfpZlC985pH2/ui64DKazbTW/4kN3yqozUxlXzI6cA==", 50 | "dev": true 51 | }, 52 | "follow-redirects": { 53 | "version": "1.7.0", 54 | "resolved": "http://registry-npm.firstshare.cn/follow-redirects/-/follow-redirects-1.7.0.tgz", 55 | "integrity": "sha512-m/pZQy4Gj287eNy94nivy5wchN3Kp+Q5WgUPNy5lJSZ3sgkVKSYV/ZChMAQVIgx1SqfZ2zBZtPA2YlXIWxxJOQ==", 56 | "dev": true, 57 | "requires": { 58 | "debug": "^3.2.6" 59 | } 60 | }, 61 | "he": { 62 | "version": "1.2.0", 63 | "resolved": "http://registry-npm.firstshare.cn/he/-/he-1.2.0.tgz", 64 | "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", 65 | "dev": true 66 | }, 67 | "http-proxy": { 68 | "version": "1.17.0", 69 | "resolved": "http://registry-npm.firstshare.cn/http-proxy/-/http-proxy-1.17.0.tgz", 70 | "integrity": "sha512-Taqn+3nNvYRfJ3bGvKfBSRwy1v6eePlm3oc/aWVxZp57DQr5Eq3xhKJi7Z4hZpS8PC3H4qI+Yly5EmFacGuA/g==", 71 | "dev": true, 72 | "requires": { 73 | "eventemitter3": "^3.0.0", 74 | "follow-redirects": "^1.0.0", 75 | "requires-port": "^1.0.0" 76 | } 77 | }, 78 | "http-server": { 79 | "version": "0.11.1", 80 | "resolved": "http://registry-npm.firstshare.cn/http-server/-/http-server-0.11.1.tgz", 81 | "integrity": "sha512-6JeGDGoujJLmhjiRGlt8yK8Z9Kl0vnl/dQoQZlc4oeqaUoAKQg94NILLfrY3oWzSyFaQCVNTcKE5PZ3cH8VP9w==", 82 | "dev": true, 83 | "requires": { 84 | "colors": "1.0.3", 85 | "corser": "~2.0.0", 86 | "ecstatic": "^3.0.0", 87 | "http-proxy": "^1.8.1", 88 | "opener": "~1.4.0", 89 | "optimist": "0.6.x", 90 | "portfinder": "^1.0.13", 91 | "union": "~0.4.3" 92 | } 93 | }, 94 | "mime": { 95 | "version": "1.6.0", 96 | "resolved": "http://registry-npm.firstshare.cn/mime/-/mime-1.6.0.tgz", 97 | "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", 98 | "dev": true 99 | }, 100 | "minimist": { 101 | "version": "1.2.0", 102 | "resolved": "http://registry-npm.firstshare.cn/minimist/-/minimist-1.2.0.tgz", 103 | "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", 104 | "dev": true 105 | }, 106 | "mkdirp": { 107 | "version": "0.5.1", 108 | "resolved": "http://registry-npm.firstshare.cn/mkdirp/-/mkdirp-0.5.1.tgz", 109 | "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", 110 | "dev": true, 111 | "requires": { 112 | "minimist": "0.0.8" 113 | }, 114 | "dependencies": { 115 | "minimist": { 116 | "version": "0.0.8", 117 | "resolved": "http://registry-npm.firstshare.cn/minimist/-/minimist-0.0.8.tgz", 118 | "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", 119 | "dev": true 120 | } 121 | } 122 | }, 123 | "ms": { 124 | "version": "2.1.1", 125 | "resolved": "http://registry-npm.firstshare.cn/ms/-/ms-2.1.1.tgz", 126 | "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", 127 | "dev": true 128 | }, 129 | "opener": { 130 | "version": "1.4.3", 131 | "resolved": "http://registry-npm.firstshare.cn/opener/-/opener-1.4.3.tgz", 132 | "integrity": "sha1-XG2ixdflgx6P+jlklQ+NZnSskLg=", 133 | "dev": true 134 | }, 135 | "optimist": { 136 | "version": "0.6.1", 137 | "resolved": "http://registry-npm.firstshare.cn/optimist/-/optimist-0.6.1.tgz", 138 | "integrity": "sha1-2j6nRob6IaGaERwybpDrFaAZZoY=", 139 | "dev": true, 140 | "requires": { 141 | "minimist": "~0.0.1", 142 | "wordwrap": "~0.0.2" 143 | }, 144 | "dependencies": { 145 | "minimist": { 146 | "version": "0.0.10", 147 | "resolved": "http://registry-npm.firstshare.cn/minimist/-/minimist-0.0.10.tgz", 148 | "integrity": "sha1-3j+YVD2/lggr5IrRoMfNqDYwHc8=", 149 | "dev": true 150 | } 151 | } 152 | }, 153 | "portfinder": { 154 | "version": "1.0.20", 155 | "resolved": "http://registry-npm.firstshare.cn/portfinder/-/portfinder-1.0.20.tgz", 156 | "integrity": "sha512-Yxe4mTyDzTd59PZJY4ojZR8F+E5e97iq2ZOHPz3HDgSvYC5siNad2tLooQ5y5QHyQhc3xVqvyk/eNA3wuoa7Sw==", 157 | "dev": true, 158 | "requires": { 159 | "async": "^1.5.2", 160 | "debug": "^2.2.0", 161 | "mkdirp": "0.5.x" 162 | }, 163 | "dependencies": { 164 | "debug": { 165 | "version": "2.6.9", 166 | "resolved": "http://registry-npm.firstshare.cn/debug/-/debug-2.6.9.tgz", 167 | "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", 168 | "dev": true, 169 | "requires": { 170 | "ms": "2.0.0" 171 | } 172 | }, 173 | "ms": { 174 | "version": "2.0.0", 175 | "resolved": "http://registry-npm.firstshare.cn/ms/-/ms-2.0.0.tgz", 176 | "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", 177 | "dev": true 178 | } 179 | } 180 | }, 181 | "qs": { 182 | "version": "2.3.3", 183 | "resolved": "http://registry-npm.firstshare.cn/qs/-/qs-2.3.3.tgz", 184 | "integrity": "sha1-6eha2+ddoLvkyOBHaghikPhjtAQ=", 185 | "dev": true 186 | }, 187 | "requires-port": { 188 | "version": "1.0.0", 189 | "resolved": "http://registry-npm.firstshare.cn/requires-port/-/requires-port-1.0.0.tgz", 190 | "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=", 191 | "dev": true 192 | }, 193 | "union": { 194 | "version": "0.4.6", 195 | "resolved": "http://registry-npm.firstshare.cn/union/-/union-0.4.6.tgz", 196 | "integrity": "sha1-GY+9rrolTniLDvy2MLwR8kopWeA=", 197 | "dev": true, 198 | "requires": { 199 | "qs": "~2.3.3" 200 | } 201 | }, 202 | "url-join": { 203 | "version": "2.0.5", 204 | "resolved": "http://registry-npm.firstshare.cn/url-join/-/url-join-2.0.5.tgz", 205 | "integrity": "sha1-WvIvGMBSoACkjXuCxenC4v7tpyg=", 206 | "dev": true 207 | }, 208 | "wordwrap": { 209 | "version": "0.0.3", 210 | "resolved": "http://registry-npm.firstshare.cn/wordwrap/-/wordwrap-0.0.3.tgz", 211 | "integrity": "sha1-o9XabNXAvAAI03I0u68b7WMFkQc=", 212 | "dev": true 213 | } 214 | } 215 | } 216 | -------------------------------------------------------------------------------- /circular-dependency/requirejs/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "requirejs-demo", 3 | "version": "1.0.0", 4 | "lockfileVersion": 1, 5 | "requires": true, 6 | "dependencies": { 7 | "async": { 8 | "version": "1.5.2", 9 | "resolved": "http://registry-npm.firstshare.cn/async/-/async-1.5.2.tgz", 10 | "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=", 11 | "dev": true 12 | }, 13 | "colors": { 14 | "version": "1.0.3", 15 | "resolved": "http://registry-npm.firstshare.cn/colors/-/colors-1.0.3.tgz", 16 | "integrity": "sha1-BDP0TYCWgP3rYO0mDxsMJi6CpAs=", 17 | "dev": true 18 | }, 19 | "corser": { 20 | "version": "2.0.1", 21 | "resolved": "http://registry-npm.firstshare.cn/corser/-/corser-2.0.1.tgz", 22 | "integrity": "sha1-jtolLsqrWEDc2XXOuQ2TcMgZ/4c=", 23 | "dev": true 24 | }, 25 | "debug": { 26 | "version": "3.2.6", 27 | "resolved": "http://registry-npm.firstshare.cn/debug/-/debug-3.2.6.tgz", 28 | "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", 29 | "dev": true, 30 | "requires": { 31 | "ms": "^2.1.1" 32 | } 33 | }, 34 | "ecstatic": { 35 | "version": "3.3.1", 36 | "resolved": "http://registry-npm.firstshare.cn/ecstatic/-/ecstatic-3.3.1.tgz", 37 | "integrity": "sha512-/rrctvxZ78HMI/tPIsqdvFKHHscxR3IJuKrZI2ZoUgkt2SiufyLFBmcco+aqQBIu6P1qBsUNG3drAAGLx80vTQ==", 38 | "dev": true, 39 | "requires": { 40 | "he": "^1.1.1", 41 | "mime": "^1.6.0", 42 | "minimist": "^1.1.0", 43 | "url-join": "^2.0.5" 44 | } 45 | }, 46 | "eventemitter3": { 47 | "version": "3.1.0", 48 | "resolved": "http://registry-npm.firstshare.cn/eventemitter3/-/eventemitter3-3.1.0.tgz", 49 | "integrity": "sha512-ivIvhpq/Y0uSjcHDcOIccjmYjGLcP09MFGE7ysAwkAvkXfpZlC985pH2/ui64DKazbTW/4kN3yqozUxlXzI6cA==", 50 | "dev": true 51 | }, 52 | "follow-redirects": { 53 | "version": "1.7.0", 54 | "resolved": "http://registry-npm.firstshare.cn/follow-redirects/-/follow-redirects-1.7.0.tgz", 55 | "integrity": "sha512-m/pZQy4Gj287eNy94nivy5wchN3Kp+Q5WgUPNy5lJSZ3sgkVKSYV/ZChMAQVIgx1SqfZ2zBZtPA2YlXIWxxJOQ==", 56 | "dev": true, 57 | "requires": { 58 | "debug": "^3.2.6" 59 | } 60 | }, 61 | "he": { 62 | "version": "1.2.0", 63 | "resolved": "http://registry-npm.firstshare.cn/he/-/he-1.2.0.tgz", 64 | "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", 65 | "dev": true 66 | }, 67 | "http-proxy": { 68 | "version": "1.17.0", 69 | "resolved": "http://registry-npm.firstshare.cn/http-proxy/-/http-proxy-1.17.0.tgz", 70 | "integrity": "sha512-Taqn+3nNvYRfJ3bGvKfBSRwy1v6eePlm3oc/aWVxZp57DQr5Eq3xhKJi7Z4hZpS8PC3H4qI+Yly5EmFacGuA/g==", 71 | "dev": true, 72 | "requires": { 73 | "eventemitter3": "^3.0.0", 74 | "follow-redirects": "^1.0.0", 75 | "requires-port": "^1.0.0" 76 | } 77 | }, 78 | "http-server": { 79 | "version": "0.11.1", 80 | "resolved": "http://registry-npm.firstshare.cn/http-server/-/http-server-0.11.1.tgz", 81 | "integrity": "sha512-6JeGDGoujJLmhjiRGlt8yK8Z9Kl0vnl/dQoQZlc4oeqaUoAKQg94NILLfrY3oWzSyFaQCVNTcKE5PZ3cH8VP9w==", 82 | "dev": true, 83 | "requires": { 84 | "colors": "1.0.3", 85 | "corser": "~2.0.0", 86 | "ecstatic": "^3.0.0", 87 | "http-proxy": "^1.8.1", 88 | "opener": "~1.4.0", 89 | "optimist": "0.6.x", 90 | "portfinder": "^1.0.13", 91 | "union": "~0.4.3" 92 | } 93 | }, 94 | "mime": { 95 | "version": "1.6.0", 96 | "resolved": "http://registry-npm.firstshare.cn/mime/-/mime-1.6.0.tgz", 97 | "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", 98 | "dev": true 99 | }, 100 | "minimist": { 101 | "version": "1.2.0", 102 | "resolved": "http://registry-npm.firstshare.cn/minimist/-/minimist-1.2.0.tgz", 103 | "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", 104 | "dev": true 105 | }, 106 | "mkdirp": { 107 | "version": "0.5.1", 108 | "resolved": "http://registry-npm.firstshare.cn/mkdirp/-/mkdirp-0.5.1.tgz", 109 | "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", 110 | "dev": true, 111 | "requires": { 112 | "minimist": "0.0.8" 113 | }, 114 | "dependencies": { 115 | "minimist": { 116 | "version": "0.0.8", 117 | "resolved": "http://registry-npm.firstshare.cn/minimist/-/minimist-0.0.8.tgz", 118 | "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", 119 | "dev": true 120 | } 121 | } 122 | }, 123 | "ms": { 124 | "version": "2.1.1", 125 | "resolved": "http://registry-npm.firstshare.cn/ms/-/ms-2.1.1.tgz", 126 | "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", 127 | "dev": true 128 | }, 129 | "opener": { 130 | "version": "1.4.3", 131 | "resolved": "http://registry-npm.firstshare.cn/opener/-/opener-1.4.3.tgz", 132 | "integrity": "sha1-XG2ixdflgx6P+jlklQ+NZnSskLg=", 133 | "dev": true 134 | }, 135 | "optimist": { 136 | "version": "0.6.1", 137 | "resolved": "http://registry-npm.firstshare.cn/optimist/-/optimist-0.6.1.tgz", 138 | "integrity": "sha1-2j6nRob6IaGaERwybpDrFaAZZoY=", 139 | "dev": true, 140 | "requires": { 141 | "minimist": "~0.0.1", 142 | "wordwrap": "~0.0.2" 143 | }, 144 | "dependencies": { 145 | "minimist": { 146 | "version": "0.0.10", 147 | "resolved": "http://registry-npm.firstshare.cn/minimist/-/minimist-0.0.10.tgz", 148 | "integrity": "sha1-3j+YVD2/lggr5IrRoMfNqDYwHc8=", 149 | "dev": true 150 | } 151 | } 152 | }, 153 | "portfinder": { 154 | "version": "1.0.20", 155 | "resolved": "http://registry-npm.firstshare.cn/portfinder/-/portfinder-1.0.20.tgz", 156 | "integrity": "sha512-Yxe4mTyDzTd59PZJY4ojZR8F+E5e97iq2ZOHPz3HDgSvYC5siNad2tLooQ5y5QHyQhc3xVqvyk/eNA3wuoa7Sw==", 157 | "dev": true, 158 | "requires": { 159 | "async": "^1.5.2", 160 | "debug": "^2.2.0", 161 | "mkdirp": "0.5.x" 162 | }, 163 | "dependencies": { 164 | "debug": { 165 | "version": "2.6.9", 166 | "resolved": "http://registry-npm.firstshare.cn/debug/-/debug-2.6.9.tgz", 167 | "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", 168 | "dev": true, 169 | "requires": { 170 | "ms": "2.0.0" 171 | } 172 | }, 173 | "ms": { 174 | "version": "2.0.0", 175 | "resolved": "http://registry-npm.firstshare.cn/ms/-/ms-2.0.0.tgz", 176 | "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", 177 | "dev": true 178 | } 179 | } 180 | }, 181 | "qs": { 182 | "version": "2.3.3", 183 | "resolved": "http://registry-npm.firstshare.cn/qs/-/qs-2.3.3.tgz", 184 | "integrity": "sha1-6eha2+ddoLvkyOBHaghikPhjtAQ=", 185 | "dev": true 186 | }, 187 | "requires-port": { 188 | "version": "1.0.0", 189 | "resolved": "http://registry-npm.firstshare.cn/requires-port/-/requires-port-1.0.0.tgz", 190 | "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=", 191 | "dev": true 192 | }, 193 | "union": { 194 | "version": "0.4.6", 195 | "resolved": "http://registry-npm.firstshare.cn/union/-/union-0.4.6.tgz", 196 | "integrity": "sha1-GY+9rrolTniLDvy2MLwR8kopWeA=", 197 | "dev": true, 198 | "requires": { 199 | "qs": "~2.3.3" 200 | } 201 | }, 202 | "url-join": { 203 | "version": "2.0.5", 204 | "resolved": "http://registry-npm.firstshare.cn/url-join/-/url-join-2.0.5.tgz", 205 | "integrity": "sha1-WvIvGMBSoACkjXuCxenC4v7tpyg=", 206 | "dev": true 207 | }, 208 | "wordwrap": { 209 | "version": "0.0.3", 210 | "resolved": "http://registry-npm.firstshare.cn/wordwrap/-/wordwrap-0.0.3.tgz", 211 | "integrity": "sha1-o9XabNXAvAAI03I0u68b7WMFkQc=", 212 | "dev": true 213 | } 214 | } 215 | } 216 | -------------------------------------------------------------------------------- /momentum-scrolling/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 37 | 38 | 39 |
40 | 41 | 67 | 68 | 69 | 228 | 229 | -------------------------------------------------------------------------------- /css-stacking-context/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 308 | 309 | 310 | 311 |

不同层叠顺序

312 |
313 |
position: relative;
z-index: -1;
314 |
display: block;
315 |
float: left;
316 |
display: inline-block;
317 |
position: relative;
318 |
position: absolute;
z-index: 1;
319 |
320 | 321 |

不关心结构关系

322 |
323 |
Parent
324 |
Child
325 |
326 |
327 |
328 |
329 |
330 |
Parent
opacity: 0.6;
331 |
Child
332 |
333 |
334 |
335 |
336 | 337 |

按照 HTML 中出现的顺序

338 |
339 |
340 |
341 |
box-1
342 |
box-2
343 |
344 |
345 |
346 |
347 |
box-1
348 |
box-2
349 |
350 | 351 |

自包含

352 |
353 |
354 |
355 |
356 |
357 |
358 |
359 |
Parent-1
position: relative;
z-index: 2;
360 |
Parent-2
position: relative;
z-index: 1;
361 |
Child-1
position: relative;
z-index: -1;
362 |
Child-2
position: relative;
z-index: 10;
363 |
364 | 365 |

7阶层叠顺序图

366 |
367 | background / border 368 |
z-index < 0 定位元素
369 |
display: block;
370 |
float
371 |
display: inline;
display: inline-block;
372 |
z-index: 0 / auto 定位元素
其他子级层叠上下文元素
373 |
z-index > 0 定位元素
374 |
375 | 376 |

第 6 阶层叠顺序

377 |
378 |
379 |
380 |
box-1
381 |
box-2
382 |
383 |
384 |
385 |
386 |
box-1
387 |
box-2
388 |
389 | 390 |

伸缩盒 flex 项目

391 |
392 |
393 |
394 |
395 |
Container
396 |
Item
397 |
398 |
399 |
400 |
401 |
402 |
Container
403 |
Item
404 |
Child
405 |
406 |
407 |
408 |
409 |
410 |
Container
411 |
412 | 413 |

固定布局的特殊性

414 |
415 | 416 | 417 | 418 |
419 |
420 |
421 |
固定定位元素
422 |
负 z-index 定位元素
423 |
424 | 425 | -------------------------------------------------------------------------------- /circular-dependency/seajs/sea.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Sea.js 3.0.0 | seajs.org/LICENSE.md 3 | */ 4 | (function(global, undefined) { 5 | 6 | // Avoid conflicting when `sea.js` is loaded multiple times 7 | if (global.seajs) { 8 | return 9 | } 10 | 11 | var seajs = global.seajs = { 12 | // The current version of Sea.js being used 13 | version: "3.0.0" 14 | } 15 | 16 | var data = seajs.data = {} 17 | 18 | 19 | /** 20 | * util-lang.js - The minimal language enhancement 21 | */ 22 | 23 | function isType(type) { 24 | return function(obj) { 25 | return {}.toString.call(obj) == "[object " + type + "]" 26 | } 27 | } 28 | 29 | var isObject = isType("Object") 30 | var isString = isType("String") 31 | var isArray = Array.isArray || isType("Array") 32 | var isFunction = isType("Function") 33 | 34 | var _cid = 0 35 | function cid() { 36 | return _cid++ 37 | } 38 | 39 | 40 | /** 41 | * util-events.js - The minimal events support 42 | */ 43 | 44 | var events = data.events = {} 45 | 46 | // Bind event 47 | seajs.on = function(name, callback) { 48 | var list = events[name] || (events[name] = []) 49 | list.push(callback) 50 | return seajs 51 | } 52 | 53 | // Remove event. If `callback` is undefined, remove all callbacks for the 54 | // event. If `event` and `callback` are both undefined, remove all callbacks 55 | // for all events 56 | seajs.off = function(name, callback) { 57 | // Remove *all* events 58 | if (!(name || callback)) { 59 | events = data.events = {} 60 | return seajs 61 | } 62 | 63 | var list = events[name] 64 | if (list) { 65 | if (callback) { 66 | for (var i = list.length - 1; i >= 0; i--) { 67 | if (list[i] === callback) { 68 | list.splice(i, 1) 69 | } 70 | } 71 | } 72 | else { 73 | delete events[name] 74 | } 75 | } 76 | 77 | return seajs 78 | } 79 | 80 | // Emit event, firing all bound callbacks. Callbacks receive the same 81 | // arguments as `emit` does, apart from the event name 82 | var emit = seajs.emit = function(name, data) { 83 | var list = events[name] 84 | 85 | if (list) { 86 | // Copy callback lists to prevent modification 87 | list = list.slice() 88 | 89 | // Execute event callbacks, use index because it's the faster. 90 | for(var i = 0, len = list.length; i < len; i++) { 91 | list[i](data) 92 | } 93 | } 94 | 95 | return seajs 96 | } 97 | 98 | /** 99 | * util-path.js - The utilities for operating path such as id, uri 100 | */ 101 | 102 | var DIRNAME_RE = /[^?#]*\// 103 | 104 | var DOT_RE = /\/\.\//g 105 | var DOUBLE_DOT_RE = /\/[^/]+\/\.\.\// 106 | var MULTI_SLASH_RE = /([^:/])\/+\//g 107 | 108 | // Extract the directory portion of a path 109 | // dirname("a/b/c.js?t=123#xx/zz") ==> "a/b/" 110 | // ref: http://jsperf.com/regex-vs-split/2 111 | function dirname(path) { 112 | return path.match(DIRNAME_RE)[0] 113 | } 114 | 115 | // Canonicalize a path 116 | // realpath("http://test.com/a//./b/../c") ==> "http://test.com/a/c" 117 | function realpath(path) { 118 | // /a/b/./c/./d ==> /a/b/c/d 119 | path = path.replace(DOT_RE, "/") 120 | 121 | /* 122 | @author wh1100717 123 | a//b/c ==> a/b/c 124 | a///b/////c ==> a/b/c 125 | DOUBLE_DOT_RE matches a/b/c//../d path correctly only if replace // with / first 126 | */ 127 | path = path.replace(MULTI_SLASH_RE, "$1/") 128 | 129 | // a/b/c/../../d ==> a/b/../d ==> a/d 130 | while (path.match(DOUBLE_DOT_RE)) { 131 | path = path.replace(DOUBLE_DOT_RE, "/") 132 | } 133 | 134 | return path 135 | } 136 | 137 | // Normalize an id 138 | // normalize("path/to/a") ==> "path/to/a.js" 139 | // NOTICE: substring is faster than negative slice and RegExp 140 | function normalize(path) { 141 | var last = path.length - 1 142 | var lastC = path.charCodeAt(last) 143 | 144 | // If the uri ends with `#`, just return it without '#' 145 | if (lastC === 35 /* "#" */) { 146 | return path.substring(0, last) 147 | } 148 | 149 | return (path.substring(last - 2) === ".js" || 150 | path.indexOf("?") > 0 || 151 | lastC === 47 /* "/" */) ? path : path + ".js" 152 | } 153 | 154 | 155 | var PATHS_RE = /^([^/:]+)(\/.+)$/ 156 | var VARS_RE = /{([^{]+)}/g 157 | 158 | function parseAlias(id) { 159 | var alias = data.alias 160 | return alias && isString(alias[id]) ? alias[id] : id 161 | } 162 | 163 | function parsePaths(id) { 164 | var paths = data.paths 165 | var m 166 | 167 | if (paths && (m = id.match(PATHS_RE)) && isString(paths[m[1]])) { 168 | id = paths[m[1]] + m[2] 169 | } 170 | 171 | return id 172 | } 173 | 174 | function parseVars(id) { 175 | var vars = data.vars 176 | 177 | if (vars && id.indexOf("{") > -1) { 178 | id = id.replace(VARS_RE, function(m, key) { 179 | return isString(vars[key]) ? vars[key] : m 180 | }) 181 | } 182 | 183 | return id 184 | } 185 | 186 | function parseMap(uri) { 187 | var map = data.map 188 | var ret = uri 189 | 190 | if (map) { 191 | for (var i = 0, len = map.length; i < len; i++) { 192 | var rule = map[i] 193 | 194 | ret = isFunction(rule) ? 195 | (rule(uri) || uri) : 196 | uri.replace(rule[0], rule[1]) 197 | 198 | // Only apply the first matched rule 199 | if (ret !== uri) break 200 | } 201 | } 202 | 203 | return ret 204 | } 205 | 206 | 207 | var ABSOLUTE_RE = /^\/\/.|:\// 208 | var ROOT_DIR_RE = /^.*?\/\/.*?\// 209 | 210 | function addBase(id, refUri) { 211 | var ret 212 | var first = id.charCodeAt(0) 213 | 214 | // Absolute 215 | if (ABSOLUTE_RE.test(id)) { 216 | ret = id 217 | } 218 | // Relative 219 | else if (first === 46 /* "." */) { 220 | ret = (refUri ? dirname(refUri) : data.cwd) + id 221 | } 222 | // Root 223 | else if (first === 47 /* "/" */) { 224 | var m = data.cwd.match(ROOT_DIR_RE) 225 | ret = m ? m[0] + id.substring(1) : id 226 | } 227 | // Top-level 228 | else { 229 | ret = data.base + id 230 | } 231 | 232 | // Add default protocol when uri begins with "//" 233 | if (ret.indexOf("//") === 0) { 234 | ret = location.protocol + ret 235 | } 236 | 237 | return realpath(ret) 238 | } 239 | 240 | function id2Uri(id, refUri) { 241 | if (!id) return "" 242 | 243 | id = parseAlias(id) 244 | id = parsePaths(id) 245 | id = parseAlias(id) 246 | id = parseVars(id) 247 | id = parseAlias(id) 248 | id = normalize(id) 249 | id = parseAlias(id) 250 | 251 | var uri = addBase(id, refUri) 252 | uri = parseAlias(uri) 253 | uri = parseMap(uri) 254 | 255 | return uri 256 | } 257 | 258 | // For Developers 259 | seajs.resolve = id2Uri; 260 | 261 | // Check environment 262 | var isWebWorker = typeof window === 'undefined' && typeof importScripts !== 'undefined' && isFunction(importScripts); 263 | 264 | // Ignore about:xxx and blob:xxx 265 | var IGNORE_LOCATION_RE = /^(about|blob):/; 266 | var loaderDir; 267 | // Sea.js's full path 268 | var loaderPath; 269 | // Location is read-only from web worker, should be ok though 270 | var cwd = (!location.href || IGNORE_LOCATION_RE.test(location.href)) ? '' : dirname(location.href); 271 | 272 | if (isWebWorker) { 273 | // Web worker doesn't create DOM object when loading scripts 274 | // Get sea.js's path by stack trace. 275 | var stack; 276 | try { 277 | var up = new Error(); 278 | throw up; 279 | } catch (e) { 280 | // IE won't set Error.stack until thrown 281 | stack = e.stack.split('\n'); 282 | } 283 | // First line is 'Error' 284 | stack.shift(); 285 | 286 | var m; 287 | // Try match `url:row:col` from stack trace line. Known formats: 288 | // Chrome: ' at http://localhost:8000/script/sea-worker-debug.js:294:25' 289 | // FireFox: '@http://localhost:8000/script/sea-worker-debug.js:1082:1' 290 | // IE11: ' at Anonymous function (http://localhost:8000/script/sea-worker-debug.js:295:5)' 291 | // Don't care about older browsers since web worker is an HTML5 feature 292 | var TRACE_RE = /.*?((?:http|https|file)(?::\/{2}[\w]+)(?:[\/|\.]?)(?:[^\s"]*)).*?/i 293 | // Try match `url` (Note: in IE there will be a tailing ')') 294 | var URL_RE = /(.*?):\d+:\d+\)?$/; 295 | // Find url of from stack trace. 296 | // Cannot simply read the first one because sometimes we will get: 297 | // Error 298 | // at Error (native) <- Here's your problem 299 | // at http://localhost:8000/_site/dist/sea.js:2:4334 <- What we want 300 | // at http://localhost:8000/_site/dist/sea.js:2:8386 301 | // at http://localhost:8000/_site/tests/specs/web-worker/worker.js:3:1 302 | while (stack.length > 0) { 303 | var top = stack.shift(); 304 | m = TRACE_RE.exec(top); 305 | if (m != null) { 306 | break; 307 | } 308 | } 309 | var url; 310 | if (m != null) { 311 | // Remove line number and column number 312 | // No need to check, can't be wrong at this point 313 | var url = URL_RE.exec(m[1])[1]; 314 | } 315 | // Set 316 | loaderPath = url 317 | // Set loaderDir 318 | loaderDir = dirname(url || cwd); 319 | // This happens with inline worker. 320 | // When entrance script's location.href is a blob url, 321 | // cwd will not be available. 322 | // Fall back to loaderDir. 323 | if (cwd === '') { 324 | cwd = loaderDir; 325 | } 326 | } 327 | else { 328 | var doc = document 329 | var scripts = doc.scripts 330 | 331 | // Recommend to add `seajsnode` id for the `sea.js` script element 332 | var loaderScript = doc.getElementById("seajsnode") || 333 | scripts[scripts.length - 1] 334 | 335 | function getScriptAbsoluteSrc(node) { 336 | return node.hasAttribute ? // non-IE6/7 337 | node.src : 338 | // see http://msdn.microsoft.com/en-us/library/ms536429(VS.85).aspx 339 | node.getAttribute("src", 4) 340 | } 341 | loaderPath = getScriptAbsoluteSrc(loaderScript) 342 | // When `sea.js` is inline, set loaderDir to current working directory 343 | loaderDir = dirname(loaderPath || cwd) 344 | } 345 | 346 | /** 347 | * util-request.js - The utilities for requesting script and style files 348 | * ref: tests/research/load-js-css/test.html 349 | */ 350 | if (isWebWorker) { 351 | function requestFromWebWorker(url, callback, charset) { 352 | // Load with importScripts 353 | var error; 354 | try { 355 | importScripts(url); 356 | } catch (e) { 357 | error = e; 358 | } 359 | callback(error); 360 | } 361 | // For Developers 362 | seajs.request = requestFromWebWorker; 363 | } 364 | else { 365 | var doc = document 366 | var head = doc.head || doc.getElementsByTagName("head")[0] || doc.documentElement 367 | var baseElement = head.getElementsByTagName("base")[0] 368 | 369 | var currentlyAddingScript 370 | 371 | function request(url, callback, charset) { 372 | var node = doc.createElement("script") 373 | 374 | if (charset) { 375 | var cs = isFunction(charset) ? charset(url) : charset 376 | if (cs) { 377 | node.charset = cs 378 | } 379 | } 380 | 381 | addOnload(node, callback, url) 382 | 383 | node.async = true 384 | node.src = url 385 | 386 | // For some cache cases in IE 6-8, the script executes IMMEDIATELY after 387 | // the end of the insert execution, so use `currentlyAddingScript` to 388 | // hold current node, for deriving url in `define` call 389 | currentlyAddingScript = node 390 | 391 | // ref: #185 & http://dev.jquery.com/ticket/2709 392 | baseElement ? 393 | head.insertBefore(node, baseElement) : 394 | head.appendChild(node) 395 | 396 | currentlyAddingScript = null 397 | } 398 | 399 | function addOnload(node, callback, url) { 400 | var supportOnload = "onload" in node 401 | 402 | if (supportOnload) { 403 | node.onload = onload 404 | node.onerror = function() { 405 | emit("error", { uri: url, node: node }) 406 | onload(true) 407 | } 408 | } 409 | else { 410 | node.onreadystatechange = function() { 411 | if (/loaded|complete/.test(node.readyState)) { 412 | onload() 413 | } 414 | } 415 | } 416 | 417 | function onload(error) { 418 | // Ensure only run once and handle memory leak in IE 419 | node.onload = node.onerror = node.onreadystatechange = null 420 | 421 | // Remove the script to reduce memory leak 422 | if (!data.debug) { 423 | head.removeChild(node) 424 | } 425 | 426 | // Dereference the node 427 | node = null 428 | 429 | callback(error) 430 | } 431 | } 432 | 433 | // For Developers 434 | seajs.request = request 435 | 436 | } 437 | var interactiveScript 438 | 439 | function getCurrentScript() { 440 | if (currentlyAddingScript) { 441 | return currentlyAddingScript 442 | } 443 | 444 | // For IE6-9 browsers, the script onload event may not fire right 445 | // after the script is evaluated. Kris Zyp found that it 446 | // could query the script nodes and the one that is in "interactive" 447 | // mode indicates the current script 448 | // ref: http://goo.gl/JHfFW 449 | if (interactiveScript && interactiveScript.readyState === "interactive") { 450 | return interactiveScript 451 | } 452 | 453 | var scripts = head.getElementsByTagName("script") 454 | 455 | for (var i = scripts.length - 1; i >= 0; i--) { 456 | var script = scripts[i] 457 | if (script.readyState === "interactive") { 458 | interactiveScript = script 459 | return interactiveScript 460 | } 461 | } 462 | } 463 | 464 | /** 465 | * util-deps.js - The parser for dependencies 466 | * ref: tests/research/parse-dependencies/test.html 467 | * ref: https://github.com/seajs/searequire 468 | */ 469 | 470 | function parseDependencies(s) { 471 | if(s.indexOf('require') == -1) { 472 | return [] 473 | } 474 | var index = 0, peek, length = s.length, isReg = 1, modName = 0, parentheseState = 0, parentheseStack = [], res = [] 475 | while(index < length) { 476 | readch() 477 | if(isBlank()) { 478 | } 479 | else if(isQuote()) { 480 | dealQuote() 481 | isReg = 1 482 | } 483 | else if(peek == '/') { 484 | readch() 485 | if(peek == '/') { 486 | index = s.indexOf('\n', index) 487 | if(index == -1) { 488 | index = s.length 489 | } 490 | } 491 | else if(peek == '*') { 492 | index = s.indexOf('*/', index) 493 | if(index == -1) { 494 | index = length 495 | } 496 | else { 497 | index += 2 498 | } 499 | } 500 | else if(isReg) { 501 | dealReg() 502 | isReg = 0 503 | } 504 | else { 505 | index-- 506 | isReg = 1 507 | } 508 | } 509 | else if(isWord()) { 510 | dealWord() 511 | } 512 | else if(isNumber()) { 513 | dealNumber() 514 | } 515 | else if(peek == '(') { 516 | parentheseStack.push(parentheseState) 517 | isReg = 1 518 | } 519 | else if(peek == ')') { 520 | isReg = parentheseStack.pop() 521 | } 522 | else { 523 | isReg = peek != ']' 524 | modName = 0 525 | } 526 | } 527 | return res 528 | function readch() { 529 | peek = s.charAt(index++) 530 | } 531 | function isBlank() { 532 | return /\s/.test(peek) 533 | } 534 | function isQuote() { 535 | return peek == '"' || peek == "'" 536 | } 537 | function dealQuote() { 538 | var start = index 539 | var c = peek 540 | var end = s.indexOf(c, start) 541 | if(end == -1) { 542 | index = length 543 | } 544 | else if(s.charAt(end - 1) != '\\') { 545 | index = end + 1 546 | } 547 | else { 548 | while(index < length) { 549 | readch() 550 | if(peek == '\\') { 551 | index++ 552 | } 553 | else if(peek == c) { 554 | break 555 | } 556 | } 557 | } 558 | if(modName) { 559 | res.push(s.slice(start, index - 1)) 560 | modName = 0 561 | } 562 | } 563 | function dealReg() { 564 | index-- 565 | while(index < length) { 566 | readch() 567 | if(peek == '\\') { 568 | index++ 569 | } 570 | else if(peek == '/') { 571 | break 572 | } 573 | else if(peek == '[') { 574 | while(index < length) { 575 | readch() 576 | if(peek == '\\') { 577 | index++ 578 | } 579 | else if(peek == ']') { 580 | break 581 | } 582 | } 583 | } 584 | } 585 | } 586 | function isWord() { 587 | return /[a-z_$]/i.test(peek) 588 | } 589 | function dealWord() { 590 | var s2 = s.slice(index - 1) 591 | var r = /^[\w$]+/.exec(s2)[0] 592 | parentheseState = { 593 | 'if': 1, 594 | 'for': 1, 595 | 'while': 1, 596 | 'with': 1 597 | }[r] 598 | isReg = { 599 | 'break': 1, 600 | 'case': 1, 601 | 'continue': 1, 602 | 'debugger': 1, 603 | 'delete': 1, 604 | 'do': 1, 605 | 'else': 1, 606 | 'false': 1, 607 | 'if': 1, 608 | 'in': 1, 609 | 'instanceof': 1, 610 | 'return': 1, 611 | 'typeof': 1, 612 | 'void': 1 613 | }[r] 614 | modName = /^require\s*\(\s*(['"]).+?\1\s*\)/.test(s2) 615 | if(modName) { 616 | r = /^require\s*\(\s*['"]/.exec(s2)[0] 617 | index += r.length - 2 618 | } 619 | else { 620 | index += /^[\w$]+(?:\s*\.\s*[\w$]+)*/.exec(s2)[0].length - 1 621 | } 622 | } 623 | function isNumber() { 624 | return /\d/.test(peek) 625 | || peek == '.' && /\d/.test(s.charAt(index)) 626 | } 627 | function dealNumber() { 628 | var s2 = s.slice(index - 1) 629 | var r 630 | if(peek == '.') { 631 | r = /^\.\d+(?:E[+-]?\d*)?\s*/i.exec(s2)[0] 632 | } 633 | else if(/^0x[\da-f]*/i.test(s2)) { 634 | r = /^0x[\da-f]*\s*/i.exec(s2)[0] 635 | } 636 | else { 637 | r = /^\d+\.?\d*(?:E[+-]?\d*)?\s*/i.exec(s2)[0] 638 | } 639 | index += r.length - 1 640 | isReg = 0 641 | } 642 | } 643 | /** 644 | * module.js - The core of module loader 645 | */ 646 | 647 | var cachedMods = seajs.cache = {} 648 | var anonymousMeta 649 | 650 | var fetchingList = {} 651 | var fetchedList = {} 652 | var callbackList = {} 653 | 654 | var STATUS = Module.STATUS = { 655 | // 1 - The `module.uri` is being fetched 656 | FETCHING: 1, 657 | // 2 - The meta data has been saved to cachedMods 658 | SAVED: 2, 659 | // 3 - The `module.dependencies` are being loaded 660 | LOADING: 3, 661 | // 4 - The module are ready to execute 662 | LOADED: 4, 663 | // 5 - The module is being executed 664 | EXECUTING: 5, 665 | // 6 - The `module.exports` is available 666 | EXECUTED: 6, 667 | // 7 - 404 668 | ERROR: 7 669 | } 670 | 671 | 672 | function Module(uri, deps) { 673 | this.uri = uri 674 | this.dependencies = deps || [] 675 | this.deps = {} // Ref the dependence modules 676 | this.status = 0 677 | 678 | this._entry = [] 679 | } 680 | 681 | // Resolve module.dependencies 682 | Module.prototype.resolve = function() { 683 | var mod = this 684 | var ids = mod.dependencies 685 | var uris = [] 686 | 687 | for (var i = 0, len = ids.length; i < len; i++) { 688 | uris[i] = Module.resolve(ids[i], mod.uri) 689 | } 690 | return uris 691 | } 692 | 693 | Module.prototype.pass = function() { 694 | var mod = this 695 | 696 | var len = mod.dependencies.length 697 | 698 | for (var i = 0; i < mod._entry.length; i++) { 699 | var entry = mod._entry[i] 700 | var count = 0 701 | for (var j = 0; j < len; j++) { 702 | var m = mod.deps[mod.dependencies[j]] 703 | // If the module is unload and unused in the entry, pass entry to it 704 | if (m.status < STATUS.LOADED && !entry.history.hasOwnProperty(m.uri)) { 705 | entry.history[m.uri] = true 706 | count++ 707 | m._entry.push(entry) 708 | if(m.status === STATUS.LOADING) { 709 | m.pass() 710 | } 711 | } 712 | } 713 | // If has passed the entry to it's dependencies, modify the entry's count and del it in the module 714 | if (count > 0) { 715 | entry.remain += count - 1 716 | mod._entry.shift() 717 | i-- 718 | } 719 | } 720 | } 721 | 722 | // Load module.dependencies and fire onload when all done 723 | Module.prototype.load = function() { 724 | var mod = this 725 | 726 | // If the module is being loaded, just wait it onload call 727 | if (mod.status >= STATUS.LOADING) { 728 | return 729 | } 730 | 731 | mod.status = STATUS.LOADING 732 | 733 | // Emit `load` event for plugins such as combo plugin 734 | var uris = mod.resolve() 735 | emit("load", uris) 736 | 737 | for (var i = 0, len = uris.length; i < len; i++) { 738 | mod.deps[mod.dependencies[i]] = Module.get(uris[i]) 739 | } 740 | 741 | // Pass entry to it's dependencies 742 | mod.pass() 743 | 744 | // If module has entries not be passed, call onload 745 | if (mod._entry.length) { 746 | mod.onload() 747 | return 748 | } 749 | 750 | // Begin parallel loading 751 | var requestCache = {} 752 | var m 753 | 754 | for (i = 0; i < len; i++) { 755 | m = cachedMods[uris[i]] 756 | 757 | if (m.status < STATUS.FETCHING) { 758 | m.fetch(requestCache) 759 | } 760 | else if (m.status === STATUS.SAVED) { 761 | m.load() 762 | } 763 | } 764 | 765 | // Send all requests at last to avoid cache bug in IE6-9. Issues#808 766 | for (var requestUri in requestCache) { 767 | if (requestCache.hasOwnProperty(requestUri)) { 768 | requestCache[requestUri]() 769 | } 770 | } 771 | } 772 | 773 | // Call this method when module is loaded 774 | Module.prototype.onload = function() { 775 | var mod = this 776 | mod.status = STATUS.LOADED 777 | 778 | // When sometimes cached in IE, exec will occur before onload, make sure len is an number 779 | for (var i = 0, len = (mod._entry || []).length; i < len; i++) { 780 | var entry = mod._entry[i] 781 | if (--entry.remain === 0) { 782 | entry.callback() 783 | } 784 | } 785 | 786 | delete mod._entry 787 | } 788 | 789 | // Call this method when module is 404 790 | Module.prototype.error = function() { 791 | var mod = this 792 | mod.onload() 793 | mod.status = STATUS.ERROR 794 | } 795 | 796 | // Execute a module 797 | Module.prototype.exec = function () { 798 | var mod = this 799 | 800 | // When module is executed, DO NOT execute it again. When module 801 | // is being executed, just return `module.exports` too, for avoiding 802 | // circularly calling 803 | if (mod.status >= STATUS.EXECUTING) { 804 | return mod.exports 805 | } 806 | 807 | mod.status = STATUS.EXECUTING 808 | 809 | if (mod._entry && !mod._entry.length) { 810 | delete mod._entry 811 | } 812 | 813 | //non-cmd module has no property factory and exports 814 | if (!mod.hasOwnProperty('factory')) { 815 | mod.non = true 816 | return 817 | } 818 | 819 | // Create require 820 | var uri = mod.uri 821 | 822 | function require(id) { 823 | var m = mod.deps[id] || Module.get(require.resolve(id)) 824 | if (m.status == STATUS.ERROR) { 825 | throw new Error('module was broken: ' + m.uri); 826 | } 827 | return m.exec() 828 | } 829 | 830 | require.resolve = function(id) { 831 | return Module.resolve(id, uri) 832 | } 833 | 834 | require.async = function(ids, callback) { 835 | Module.use(ids, callback, uri + "_async_" + cid()) 836 | return require 837 | } 838 | 839 | // Exec factory 840 | var factory = mod.factory 841 | 842 | var exports = isFunction(factory) ? 843 | factory(require, mod.exports = {}, mod) : 844 | factory 845 | 846 | if (exports === undefined) { 847 | exports = mod.exports 848 | } 849 | 850 | // Reduce memory leak 851 | delete mod.factory 852 | 853 | mod.exports = exports 854 | mod.status = STATUS.EXECUTED 855 | 856 | // Emit `exec` event 857 | emit("exec", mod) 858 | 859 | return mod.exports 860 | } 861 | 862 | // Fetch a module 863 | Module.prototype.fetch = function(requestCache) { 864 | var mod = this 865 | var uri = mod.uri 866 | 867 | mod.status = STATUS.FETCHING 868 | 869 | // Emit `fetch` event for plugins such as combo plugin 870 | var emitData = { uri: uri } 871 | emit("fetch", emitData) 872 | var requestUri = emitData.requestUri || uri 873 | 874 | // Empty uri or a non-CMD module 875 | if (!requestUri || fetchedList.hasOwnProperty(requestUri)) { 876 | mod.load() 877 | return 878 | } 879 | 880 | if (fetchingList.hasOwnProperty(requestUri)) { 881 | callbackList[requestUri].push(mod) 882 | return 883 | } 884 | 885 | fetchingList[requestUri] = true 886 | callbackList[requestUri] = [mod] 887 | 888 | // Emit `request` event for plugins such as text plugin 889 | emit("request", emitData = { 890 | uri: uri, 891 | requestUri: requestUri, 892 | onRequest: onRequest, 893 | charset: isFunction(data.charset) ? data.charset(requestUri) || 'utf-8' : data.charset 894 | }) 895 | 896 | if (!emitData.requested) { 897 | requestCache ? 898 | requestCache[emitData.requestUri] = sendRequest : 899 | sendRequest() 900 | } 901 | 902 | function sendRequest() { 903 | seajs.request(emitData.requestUri, emitData.onRequest, emitData.charset) 904 | } 905 | 906 | function onRequest(error) { 907 | delete fetchingList[requestUri] 908 | fetchedList[requestUri] = true 909 | 910 | // Save meta data of anonymous module 911 | if (anonymousMeta) { 912 | Module.save(uri, anonymousMeta) 913 | anonymousMeta = null 914 | } 915 | 916 | // Call callbacks 917 | var m, mods = callbackList[requestUri] 918 | delete callbackList[requestUri] 919 | while ((m = mods.shift())) { 920 | // When 404 occurs, the params error will be true 921 | if(error === true) { 922 | m.error() 923 | } 924 | else { 925 | m.load() 926 | } 927 | } 928 | } 929 | } 930 | 931 | // Resolve id to uri 932 | Module.resolve = function(id, refUri) { 933 | // Emit `resolve` event for plugins such as text plugin 934 | var emitData = { id: id, refUri: refUri } 935 | emit("resolve", emitData) 936 | 937 | return emitData.uri || seajs.resolve(emitData.id, refUri) 938 | } 939 | 940 | // Define a module 941 | Module.define = function (id, deps, factory) { 942 | var argsLen = arguments.length 943 | 944 | // define(factory) 945 | if (argsLen === 1) { 946 | factory = id 947 | id = undefined 948 | } 949 | else if (argsLen === 2) { 950 | factory = deps 951 | 952 | // define(deps, factory) 953 | if (isArray(id)) { 954 | deps = id 955 | id = undefined 956 | } 957 | // define(id, factory) 958 | else { 959 | deps = undefined 960 | } 961 | } 962 | 963 | // Parse dependencies according to the module factory code 964 | if (!isArray(deps) && isFunction(factory)) { 965 | deps = typeof parseDependencies === "undefined" ? [] : parseDependencies(factory.toString()) 966 | } 967 | 968 | var meta = { 969 | id: id, 970 | uri: Module.resolve(id), 971 | deps: deps, 972 | factory: factory 973 | } 974 | 975 | // Try to derive uri in IE6-9 for anonymous modules 976 | if (!isWebWorker && !meta.uri && doc.attachEvent && typeof getCurrentScript !== "undefined") { 977 | var script = getCurrentScript() 978 | 979 | if (script) { 980 | meta.uri = script.src 981 | } 982 | 983 | // NOTE: If the id-deriving methods above is failed, then falls back 984 | // to use onload event to get the uri 985 | } 986 | 987 | // Emit `define` event, used in nocache plugin, seajs node version etc 988 | emit("define", meta) 989 | 990 | meta.uri ? Module.save(meta.uri, meta) : 991 | // Save information for "saving" work in the script onload event 992 | anonymousMeta = meta 993 | } 994 | 995 | // Save meta data to cachedMods 996 | Module.save = function(uri, meta) { 997 | var mod = Module.get(uri) 998 | 999 | // Do NOT override already saved modules 1000 | if (mod.status < STATUS.SAVED) { 1001 | mod.id = meta.id || uri 1002 | mod.dependencies = meta.deps || [] 1003 | mod.factory = meta.factory 1004 | mod.status = STATUS.SAVED 1005 | 1006 | emit("save", mod) 1007 | } 1008 | } 1009 | 1010 | // Get an existed module or create a new one 1011 | Module.get = function(uri, deps) { 1012 | return cachedMods[uri] || (cachedMods[uri] = new Module(uri, deps)) 1013 | } 1014 | 1015 | // Use function is equal to load a anonymous module 1016 | Module.use = function (ids, callback, uri) { 1017 | var mod = Module.get(uri, isArray(ids) ? ids : [ids]) 1018 | 1019 | mod._entry.push(mod) 1020 | mod.history = {} 1021 | mod.remain = 1 1022 | 1023 | mod.callback = function() { 1024 | var exports = [] 1025 | var uris = mod.resolve() 1026 | 1027 | for (var i = 0, len = uris.length; i < len; i++) { 1028 | exports[i] = cachedMods[uris[i]].exec() 1029 | } 1030 | 1031 | if (callback) { 1032 | callback.apply(global, exports) 1033 | } 1034 | 1035 | delete mod.callback 1036 | delete mod.history 1037 | delete mod.remain 1038 | delete mod._entry 1039 | } 1040 | 1041 | mod.load() 1042 | } 1043 | 1044 | 1045 | // Public API 1046 | 1047 | seajs.use = function(ids, callback) { 1048 | Module.use(ids, callback, data.cwd + "_use_" + cid()) 1049 | return seajs 1050 | } 1051 | 1052 | Module.define.cmd = {} 1053 | global.define = Module.define 1054 | 1055 | 1056 | // For Developers 1057 | 1058 | seajs.Module = Module 1059 | data.fetchedList = fetchedList 1060 | data.cid = cid 1061 | 1062 | seajs.require = function(id) { 1063 | var mod = Module.get(Module.resolve(id)) 1064 | if (mod.status < STATUS.EXECUTING) { 1065 | mod.onload() 1066 | mod.exec() 1067 | } 1068 | return mod.exports 1069 | } 1070 | 1071 | /** 1072 | * config.js - The configuration for the loader 1073 | */ 1074 | 1075 | // The root path to use for id2uri parsing 1076 | data.base = loaderDir 1077 | 1078 | // The loader directory 1079 | data.dir = loaderDir 1080 | 1081 | // The loader's full path 1082 | data.loader = loaderPath 1083 | 1084 | // The current working directory 1085 | data.cwd = cwd 1086 | 1087 | // The charset for requesting files 1088 | data.charset = "utf-8" 1089 | 1090 | // data.alias - An object containing shorthands of module id 1091 | // data.paths - An object containing path shorthands in module id 1092 | // data.vars - The {xxx} variables in module id 1093 | // data.map - An array containing rules to map module uri 1094 | // data.debug - Debug mode. The default value is false 1095 | 1096 | seajs.config = function(configData) { 1097 | 1098 | for (var key in configData) { 1099 | var curr = configData[key] 1100 | var prev = data[key] 1101 | 1102 | // Merge object config such as alias, vars 1103 | if (prev && isObject(prev)) { 1104 | for (var k in curr) { 1105 | prev[k] = curr[k] 1106 | } 1107 | } 1108 | else { 1109 | // Concat array config such as map 1110 | if (isArray(prev)) { 1111 | curr = prev.concat(curr) 1112 | } 1113 | // Make sure that `data.base` is an absolute path 1114 | else if (key === "base") { 1115 | // Make sure end with "/" 1116 | if (curr.slice(-1) !== "/") { 1117 | curr += "/" 1118 | } 1119 | curr = addBase(curr) 1120 | } 1121 | 1122 | // Set config 1123 | data[key] = curr 1124 | } 1125 | } 1126 | 1127 | emit("config", configData) 1128 | return seajs 1129 | } 1130 | 1131 | })(this); 1132 | --------------------------------------------------------------------------------