diff --git a/packages/inula-router/src/history/baseHistory.ts b/packages/inula-router/src/history/baseHistory.ts
index 87451567..0b1bffa0 100644
--- a/packages/inula-router/src/history/baseHistory.ts
+++ b/packages/inula-router/src/history/baseHistory.ts
@@ -66,7 +66,9 @@ export function getBaseHistory(
Object.assign(historyProps, nextState);
}
historyProps.length = browserHistory.length;
- const args = { location: historyProps.location, action: historyProps.action };
+ // 避免location饮用相同时setState不触发
+ const location = Object.assign({}, historyProps.location);
+ const args = { location: location, action: historyProps.action };
transitionManager.notifyListeners(args);
};
}
diff --git a/packages/inula-router/src/history/hashHistory.ts b/packages/inula-router/src/history/hashHistory.ts
index 6deb725e..8ce51b0a 100644
--- a/packages/inula-router/src/history/hashHistory.ts
+++ b/packages/inula-router/src/history/hashHistory.ts
@@ -57,6 +57,13 @@ export function createHashHistory(option: HashHistoryOptio
const pathDecoder = addHeadSlash;
const pathEncoder = hashType === 'slash' ? addHeadSlash : stripHeadSlash;
+ const startLocation = getHashContent(window.location.href);
+ const encodeLocation = pathEncoder(startLocation);
+ // 初始化hash格式不合法时会重定向
+ if (startLocation !== encodeLocation) {
+ window.location.replace(stripHash(window.location.href) + '#' + encodeLocation);
+ }
+
function getLocation() {
let hashPath = pathDecoder(getHashContent(window.location.hash));
if (basename) {
diff --git a/packages/inula-router/src/router/matcher/__tests__/parser.test.ts b/packages/inula-router/src/router/matcher/__tests__/parser.test.ts
index 91493cf6..e2a779d7 100644
--- a/packages/inula-router/src/router/matcher/__tests__/parser.test.ts
+++ b/packages/inula-router/src/router/matcher/__tests__/parser.test.ts
@@ -121,7 +121,13 @@ describe('parser test', () => {
it('url without end slash match wildcard', function () {
const parser = createPathParser('/about/', { strictMode: false });
const matched = parser.parse('/about');
- expect(matched).toBeNull();
+ expect(matched).toStrictEqual({
+ path: '/about/',
+ url: '/about',
+ score: [10],
+ isExact: true,
+ param: {},
+ });
});
it('url without end slash match wildcard (strictMode)', function () {
@@ -259,7 +265,7 @@ describe('parser test', () => {
});
it('dynamic param with complex regexp pattern', () => {
- const parser = createPathParser('/detail/:action([\\da-z]+)', { exact: true });
+ const parser = createPathParser('/detail/:action([\\da-z]+)', { exact: true, caseSensitive: true });
const res = parser.parse('/detail/a123');
expect(res).toEqual({
isExact: true,
diff --git a/packages/inula-router/src/router/matcher/parser.ts b/packages/inula-router/src/router/matcher/parser.ts
index 9ea88fa7..1ddbbb5c 100644
--- a/packages/inula-router/src/router/matcher/parser.ts
+++ b/packages/inula-router/src/router/matcher/parser.ts
@@ -97,12 +97,14 @@ export function createPathParser
(pathname: string, option: ParserOp const token = tokens[tokenIdx]; const nextToken = tokens[tokenIdx + 1]; switch (token.type) { - case TokenType.Delimiter: - { - const hasOptional = lookToNextDelimiter(tokenIdx + 1); - pattern += `/${hasOptional ? '?' : ''}`; - } + case TokenType.Delimiter: { + // 该分隔符后有可选参数则该分割符在匹配时是可选的 + const hasOptional = lookToNextDelimiter(tokenIdx + 1); + // 该分割符为最后一个且strictMode===false时,该分隔符在匹配时是可选的 + const isSlashOptional = nextToken === undefined && !strictMode; + pattern += `/${hasOptional || isSlashOptional ? '?' : ''}`; break; + } case TokenType.Static: pattern += token.value.replace(REGEX_CHARS_RE, '\\$&'); if (nextToken && nextToken.type === TokenType.Pattern) { @@ -112,32 +114,31 @@ export function createPathParser
(pathname: string, option: ParserOp } scores.push(MatchScore.static); break; - case TokenType.Param: - { - // 动态参数支持形如/:param、/:param*、/:param?、/:param(\\d+)的形式 - let paramRegexp = ''; - if (nextToken) { - switch (nextToken.type) { - case TokenType.LBracket: - // 跳过当前Token和左括号 - tokenIdx += 2; - while (tokens[tokenIdx].type !== TokenType.RBracket) { - paramRegexp += tokens[tokenIdx].value; - tokenIdx++; - } - paramRegexp = `(${paramRegexp})`; - break; - case TokenType.Pattern: + case TokenType.Param: { + // 动态参数支持形如/:param、/:param*、/:param?、/:param(\\d+)的形式 + let paramRegexp = ''; + if (nextToken) { + switch (nextToken.type) { + case TokenType.LBracket: + // 跳过当前Token和左括号 + tokenIdx += 2; + while (tokens[tokenIdx].type !== TokenType.RBracket) { + paramRegexp += tokens[tokenIdx].value; tokenIdx++; - paramRegexp += `(${nextToken.value === '*' ? '.*' : BASE_PARAM_PATTERN})${nextToken.value}`; - break; - } + } + paramRegexp = `(${paramRegexp})`; + break; + case TokenType.Pattern: + tokenIdx++; + paramRegexp += `(${nextToken.value === '*' ? '.*' : BASE_PARAM_PATTERN})${nextToken.value}`; + break; } - pattern += paramRegexp ? `(?:${paramRegexp})` : `(${BASE_PARAM_PATTERN})`; - keys.push(token.value); - scores.push(MatchScore.param); } + pattern += paramRegexp ? `(?:${paramRegexp})` : `(${BASE_PARAM_PATTERN})`; + keys.push(token.value); + scores.push(MatchScore.param); break; + } case TokenType.WildCard: keys.push(token.value); pattern += `((?:${BASE_PARAM_PATTERN})${onlyHasWildCard ? '?' : ''}(?:/(?:${BASE_PARAM_PATTERN}))*)`; @@ -215,16 +216,15 @@ export function createPathParser
(pathname: string, option: ParserOp } path += params[token.value]; break; - case TokenType.WildCard: - { - const wildCard = params['*']; - if (wildCard instanceof Array) { - path += wildCard.join('/'); - } else { - path += wildCard; - } + case TokenType.WildCard: { + const wildCard = params['*']; + if (wildCard instanceof Array) { + path += wildCard.join('/'); + } else { + path += wildCard; } break; + } case TokenType.Delimiter: path += token.value; break; diff --git a/packages/inula/__tests__/DomTest/Attribute.test.js b/packages/inula/__tests__/DomTest/Attribute.test.js index 27e5becb..a216bc5b 100644 --- a/packages/inula/__tests__/DomTest/Attribute.test.js +++ b/packages/inula/__tests__/DomTest/Attribute.test.js @@ -95,4 +95,16 @@ describe('Dom Attribute', () => { Inula.render(
, container); }).not.toThrow(); }); + + it('dangerouslySetInnerHTML和children同时设置,只渲染children', () => { + Inula.act(() => { + Inula.render( +