Skip to content

Commit 372a3c6

Browse files
committed
[feat] directory init && finished main function && finished test
- [todo] test coverage
1 parent a40a836 commit 372a3c6

10 files changed

+641
-0
lines changed

.babelrc

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"presets": ["es2015", "stage-2"],
3+
"plugins": ["transform-runtime"],
4+
"comments": false
5+
}

.eslintignore

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
lib/*.js

.eslintrc.js

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
module.exports = {
2+
"parser": "babel-eslint",
3+
"env": {
4+
"browser": true,
5+
"mocha": true,
6+
"node": true
7+
},
8+
parserOptions: {
9+
"ecmaVersion": 8,
10+
},
11+
// https://github.com/feross/standard/blob/master/RULES.md#javascript-standard-style
12+
extends: 'standard',
13+
plugins: [
14+
'class-property'
15+
],
16+
// add your custom rules here
17+
'rules': {
18+
"semi": [ "error", "never" ],
19+
"indent": ["error", 4],
20+
// allow paren-less arrow functions
21+
'arrow-parens': 0,
22+
}
23+
}

.gitignore

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
node_modules/
2+
.idea/
3+
.DS_Store
4+
npm-debug.log

.npmignore

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
node_modules
2+
.*.swp
3+
._*
4+
.DS_Store
5+
.git
6+
.hg
7+
.lock-wscript
8+
CVS
9+
npm-debug.log
10+
.idea
11+
.editorconfig
12+
.eslintrc.js
13+
img

lib/index.js

+181
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,181 @@
1+
'use strict';
2+
3+
Object.defineProperty(exports, "__esModule", {
4+
value: true
5+
});
6+
7+
var _toConsumableArray2 = require('babel-runtime/helpers/toConsumableArray');
8+
9+
var _toConsumableArray3 = _interopRequireDefault(_toConsumableArray2);
10+
11+
var _getIterator2 = require('babel-runtime/core-js/get-iterator');
12+
13+
var _getIterator3 = _interopRequireDefault(_getIterator2);
14+
15+
var _pathToRegexp = require('path-to-regexp');
16+
17+
var _pathToRegexp2 = _interopRequireDefault(_pathToRegexp);
18+
19+
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
20+
21+
function subscribe(history, dispatch) {
22+
for (var _len = arguments.length, rules = Array(_len > 2 ? _len - 2 : 0), _key = 2; _key < _len; _key++) {
23+
rules[_key - 2] = arguments[_key];
24+
}
25+
26+
var lastLocation = void 0;
27+
var currentLocation = void 0;
28+
var _unSubscribe = history.listen(function (newLocation) {
29+
lastLocation = currentLocation;
30+
currentLocation = newLocation;
31+
var _iteratorNormalCompletion = true;
32+
var _didIteratorError = false;
33+
var _iteratorError = undefined;
34+
35+
try {
36+
for (var _iterator = (0, _getIterator3.default)(rules), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
37+
var route = _step.value;
38+
var url = route.url,
39+
_route$queries = route.queries,
40+
queries = _route$queries === undefined ? [] : _route$queries,
41+
actionCreator = route.actionCreator,
42+
_route$everyTime = route.everyTime,
43+
everyTime = _route$everyTime === undefined ? false : _route$everyTime;
44+
45+
var match = (0, _pathToRegexp2.default)(url).exec(currentLocation.pathname);
46+
if (!match) {
47+
continue;
48+
}
49+
var shouldExec = false;
50+
51+
if (everyTime || lastLocation === undefined) {
52+
shouldExec = true;
53+
} else {
54+
var lastMatch = (0, _pathToRegexp2.default)(url).exec(lastLocation.pathname);
55+
if (!lastMatch) {
56+
shouldExec = true;
57+
} else {
58+
shouldExec = _diff(match.slice(1), lastMatch.slice(1), currentLocation.query, lastLocation.query, queries);
59+
}
60+
}
61+
if (shouldExec) {
62+
var queryResult = [];
63+
var _iteratorNormalCompletion2 = true;
64+
var _didIteratorError2 = false;
65+
var _iteratorError2 = undefined;
66+
67+
try {
68+
for (var _iterator2 = (0, _getIterator3.default)(queries), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) {
69+
var query = _step2.value;
70+
71+
queryResult.push(currentLocation.query[query]);
72+
}
73+
} catch (err) {
74+
_didIteratorError2 = true;
75+
_iteratorError2 = err;
76+
} finally {
77+
try {
78+
if (!_iteratorNormalCompletion2 && _iterator2.return) {
79+
_iterator2.return();
80+
}
81+
} finally {
82+
if (_didIteratorError2) {
83+
throw _iteratorError2;
84+
}
85+
}
86+
}
87+
88+
var action = actionCreator && actionCreator.apply(undefined, (0, _toConsumableArray3.default)(match.slice(1)).concat(queryResult));
89+
if (Array.isArray(action)) {
90+
var _iteratorNormalCompletion3 = true;
91+
var _didIteratorError3 = false;
92+
var _iteratorError3 = undefined;
93+
94+
try {
95+
for (var _iterator3 = (0, _getIterator3.default)(action), _step3; !(_iteratorNormalCompletion3 = (_step3 = _iterator3.next()).done); _iteratorNormalCompletion3 = true) {
96+
var i = _step3.value;
97+
98+
dispatch(i);
99+
}
100+
} catch (err) {
101+
_didIteratorError3 = true;
102+
_iteratorError3 = err;
103+
} finally {
104+
try {
105+
if (!_iteratorNormalCompletion3 && _iterator3.return) {
106+
_iterator3.return();
107+
}
108+
} finally {
109+
if (_didIteratorError3) {
110+
throw _iteratorError3;
111+
}
112+
}
113+
}
114+
} else {
115+
dispatch(action);
116+
}
117+
}
118+
}
119+
} catch (err) {
120+
_didIteratorError = true;
121+
_iteratorError = err;
122+
} finally {
123+
try {
124+
if (!_iteratorNormalCompletion && _iterator.return) {
125+
_iterator.return();
126+
}
127+
} finally {
128+
if (_didIteratorError) {
129+
throw _iteratorError;
130+
}
131+
}
132+
}
133+
});
134+
var listen = function listen() {
135+
rules.push.apply(rules, arguments);
136+
return ret;
137+
};
138+
var ret = {
139+
listen: listen,
140+
unListen: _unSubscribe
141+
};
142+
return ret;
143+
}
144+
145+
function _diff(params, lastParams, query, lastQuery, targetQueries) {
146+
var _iteratorNormalCompletion4 = true;
147+
var _didIteratorError4 = false;
148+
var _iteratorError4 = undefined;
149+
150+
try {
151+
for (var _iterator4 = (0, _getIterator3.default)(targetQueries), _step4; !(_iteratorNormalCompletion4 = (_step4 = _iterator4.next()).done); _iteratorNormalCompletion4 = true) {
152+
var queryName = _step4.value;
153+
154+
if (query && query[queryName] !== lastQuery[queryName]) {
155+
return true;
156+
}
157+
}
158+
} catch (err) {
159+
_didIteratorError4 = true;
160+
_iteratorError4 = err;
161+
} finally {
162+
try {
163+
if (!_iteratorNormalCompletion4 && _iterator4.return) {
164+
_iterator4.return();
165+
}
166+
} finally {
167+
if (_didIteratorError4) {
168+
throw _iteratorError4;
169+
}
170+
}
171+
}
172+
173+
for (var i = 0; i < params.length; i++) {
174+
if (params[i] !== lastParams[i]) {
175+
return true;
176+
}
177+
}
178+
return false;
179+
}
180+
181+
exports.default = subscribe;

package.json

+49
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
{
2+
"name": "dva-subscribe",
3+
"version": "0.0.1",
4+
"description": "A helper function to simplify the subscription of history in dva. ",
5+
"main": "index.js",
6+
"scripts": {
7+
"build": "rimraf lib && babel src --out-dir lib",
8+
"test": "mocha test/*.spec.js --compilers js:babel-core/register"
9+
},
10+
"repository": {
11+
"type": "git",
12+
"url": "git+https://github.com/Ma63d/dva-subscribe.git"
13+
},
14+
"keywords": [
15+
"dva",
16+
"history",
17+
"subscription"
18+
],
19+
"author": "Chuck Liu <[email protected], chuckliu.me>",
20+
"license": "MIT",
21+
"bugs": {
22+
"url": "https://github.com/Ma63d/dva-subscribe/issues"
23+
},
24+
"homepage": "https://github.com/Ma63d/dva-subscribe#readme",
25+
"devDependencies": {
26+
"babel-cli": "^6.24.1",
27+
"babel-loader": "^7.1.1",
28+
"babel-plugin-transform-runtime": "^6.23.0",
29+
"babel-preset-es2015": "^6.24.1",
30+
"babel-preset-stage-2": "^6.24.1",
31+
"chai": "^4.1.0",
32+
"chai-spies": "git://github.com/chaijs/chai-spies.git#master",
33+
"eslint": "^4.2.0",
34+
"eslint-config-standard": "^10.2.1",
35+
"eslint-plugin-standard": "^3.0.1",
36+
"history": "^4.6.3",
37+
"jsdom": "^11.1.0",
38+
"mocha": "^3.4.2",
39+
"mocha-jsdom": "^1.1.0",
40+
"rimraf": "^2.6.1"
41+
},
42+
"dependencies": {
43+
"babel-runtime": "^6.23.0",
44+
"path-to-regexp": "^1.7.0"
45+
},
46+
"peerDependencies": {
47+
"dva": "^1.0.0"
48+
}
49+
}

src/index.js

+90
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
/**
2+
* A helper function which can simplify the subscription of history in dva.
3+
* @author Chuck Liu([email protected])
4+
*/
5+
6+
import pathToRegexp from 'path-to-regexp'
7+
8+
/**
9+
* @param {Object} history, react-router history
10+
* @param {Function} dispatch, dva's dispatch
11+
* @param {Object} rules, spread arguments, optional,
12+
* * url 规则对象:
13+
* * 属性 {String} url 用于匹配 pathname 的 url 规则, 如: '/a/:b/:c/x'
14+
* * 属性 {Array} queries 默认为空数组,你关注的 query 内容, 只有当 url 中的 params 和 queries 部分有变动的时候,才会执行 actionCreator,
15+
* 当你想要避免 url 中你不关心的 query 变动导致触发不必要的 action 时,这个参数很有用
16+
* * 属性 {Function} actionCreator 返回需要 dispatch 的 action,或者 actions 数组,
17+
* * 属性 {Boolean} everyTime 默认为 false ,当 pathname 匹配上时,如果跟上次 pathname 一致,只有当 params 和 queries 变动时,才会 dispatch action,但是如果
18+
* 你想关闭这个机制、希望任何时候匹配上时都 dispatch action,那么请设置 everyTime 为 true
19+
*
20+
* @return {Object} 返回对象
21+
* * 返回对象
22+
* * 属性 {function} listen 绑定 url 规则对象,且可以链式调用: subscribe(history, dispatch).listen({...}).listen({...}).listen({...})
23+
* * 属性 {function} unListen 用于解绑 history 的 listen 操作: const {unListen} = subscribe(history, dispatch).listen({...});unListen();
24+
* */
25+
function subscribe (history, dispatch, ...rules) {
26+
let lastLocation
27+
let currentLocation
28+
const _unSubscribe = history.listen((newLocation) => {
29+
lastLocation = currentLocation
30+
currentLocation = newLocation
31+
for (let route of rules) {
32+
const { url, queries = [], actionCreator, everyTime = false } = route
33+
const match = pathToRegexp(url).exec(currentLocation.pathname)
34+
if (!match) {
35+
continue
36+
}
37+
let shouldExec = false
38+
// first time
39+
if (everyTime || lastLocation === undefined) {
40+
shouldExec = true
41+
} else {
42+
let lastMatch = pathToRegexp(url).exec(lastLocation.pathname)
43+
if (!lastMatch) {
44+
shouldExec = true
45+
} else {
46+
shouldExec = _diff(match.slice(1), lastMatch.slice(1), currentLocation.query, lastLocation.query, queries)
47+
}
48+
}
49+
if (shouldExec) {
50+
const queryResult = []
51+
for (let query of queries) {
52+
queryResult.push(currentLocation.query[query])
53+
}
54+
const action = actionCreator && actionCreator(...match.slice(1), ...queryResult)
55+
if (Array.isArray(action)) {
56+
for (let i of action) {
57+
dispatch(i)
58+
}
59+
} else {
60+
dispatch(action)
61+
}
62+
}
63+
}
64+
})
65+
const listen = (...args) => {
66+
rules.push(...args)
67+
return ret
68+
}
69+
const ret = {
70+
listen,
71+
unListen: _unSubscribe
72+
}
73+
return ret
74+
}
75+
76+
function _diff (params, lastParams, query, lastQuery, targetQueries) {
77+
for (let queryName of targetQueries) {
78+
if (query && query[queryName] !== lastQuery[queryName]) {
79+
return true
80+
}
81+
}
82+
for (let i = 0; i < params.length; i++) {
83+
if (params[i] !== lastParams[i]) {
84+
return true
85+
}
86+
}
87+
return false
88+
}
89+
90+
export default subscribe

0 commit comments

Comments
 (0)