angular-ui-router 的 1.0.3以上版本的$state.href 返回null问题
程序员文章站
2022-04-03 22:26:28
...
因为有个需求是点击控件弹出新页面,而在controller中使用$state.go是在原页面打开。
所以需要先使用$state.href 获取连接,再使用
在新页面打开。
最近升级angular-ui-router 到最新版本1.0.15后
$state.href 返回为null,经过检测,发行1.0.3版本和以后的版本把
UrlMatcher.prototype.format
这个函数改了。
新版本的代码
StateService.prototype.href = function (stateOrName, params, options) {
var defaultHrefOpts = {
lossy: true,
inherit: true,
absolute: false,
relative: this.$current,
};
options = defaults(options, defaultHrefOpts);
params = params || {};
var state = this.router.stateRegistry.matcher.find(stateOrName, options.relative);
if (!isDefined(state))
return null;
if (options.inherit)
params = this.params.$inherit(params, this.$current, state);
var nav = (state && options.lossy) ? state.navigable : state;
if (!nav || nav.url === undefined || nav.url === null) {
return null;
}
return this.router.urlRouter.href(nav.url, params, {
absolute: options.absolute,
});
};
调用UrlRouter.href
UrlRouter.prototype.href = function (urlMatcher, params, options) {
var url = urlMatcher.format(params);
if (url == null)
return null;
options = options || { absolute: false };
var cfg = this._router.urlService.config;
var isHtml5 = cfg.html5Mode();
if (!isHtml5 && url !== null) {
url = '#' + cfg.hashPrefix() + url;
}
url = appendBasePath(url, isHtml5, options.absolute, cfg.baseHref());
if (!options.absolute || !url) {
return url;
}
var slash = (!isHtml5 && url ? '/' : '');
var cfgPort = cfg.port();
var port = (cfgPort === 80 || cfgPort === 443 ? '' : ':' + cfgPort);
return [cfg.protocol(), '://', cfg.host(), port, slash, url].join('');
};
var url = urlMatcher.format(params);
这行代码调用
UrlMatcher.prototype.format = function (values$$1) {
if (values$$1 === void 0) { values$$1 = {}; }
// Build the full path of UrlMatchers (including all parent UrlMatchers)
var urlMatchers = this._cache.path;
// Extract all the static segments and Params (processed as ParamDetails)
// into an ordered array
var pathSegmentsAndParams = urlMatchers.map(UrlMatcher.pathSegmentsAndParams)
.reduce(unnestR, [])
.map(function (x) { return isString(x) ? x : getDetails(x); });
// Extract the query params into a separate array
var queryParams = urlMatchers.map(UrlMatcher.queryParams)
.reduce(unnestR, [])
.map(getDetails);
var isInvalid = function (param) { return param.isValid === false; };
if (pathSegmentsAndParams.concat(queryParams).filter(isInvalid).length) {
return null;
}
/**
* Given a Param, applies the parameter value, then returns detailed information about it
*/
function getDetails(param) {
// Normalize to typed value
var value = param.value(values$$1[param.id]);
var isValid = param.validates(value);
var isDefaultValue = param.isDefaultValue(value);
// Check if we're in squash mode for the parameter
var squash = isDefaultValue ? param.squash : false;
// Allow the Parameter's Type to encode the value
var encoded = param.type.encode(value);
return { param: param, value: value, isValid: isValid, isDefaultValue: isDefaultValue, squash: squash, encoded: encoded };
}
// Build up the path-portion from the list of static segments and parameters
var pathString = pathSegmentsAndParams.reduce(function (acc, x) {
// The element is a static segment (a raw string); just append it
if (isString(x))
return acc + x;
// Otherwise, it's a ParamDetails.
var squash = x.squash, encoded = x.encoded, param = x.param;
// If squash is === true, try to remove a slash from the path
if (squash === true)
return (acc.match(/\/$/)) ? acc.slice(0, -1) : acc;
// If squash is a string, use the string for the param value
if (isString(squash))
return acc + squash;
if (squash !== false)
return acc; // ?
if (encoded == null)
return acc;
// If this parameter value is an array, encode the value using encodeDashes
if (isArray(encoded))
return acc + map(encoded, UrlMatcher.encodeDashes).join('-');
// If the parameter type is "raw", then do not encodeURIComponent
if (param.raw)
return acc + encoded;
// Encode the value
return acc + encodeURIComponent(encoded);
}, '');
// Build the query string by applying parameter values (array or regular)
// then mapping to key=value, then flattening and joining using "&"
var queryString = queryParams.map(function (paramDetails) {
var param = paramDetails.param, squash = paramDetails.squash, encoded = paramDetails.encoded, isDefaultValue = paramDetails.isDefaultValue;
if (encoded == null || (isDefaultValue && squash !== false))
return;
if (!isArray(encoded))
encoded = [encoded];
if (encoded.length === 0)
return;
if (!param.raw)
encoded = map(encoded, encodeURIComponent);
return encoded.map(function (val$$1) { return param.id + "=" + val$$1; });
}).filter(identity).reduce(unnestR, []).join('&');
// Concat the pathstring with the queryString (if exists) and the hashString (if exists)
return pathString + (queryString ? "?" + queryString : '') + (values$$1['#'] ? '#' + values$$1['#'] : '');
};
var isInvalid = function (param) { return param.isValid === false; };
创建了一个过滤器,过滤所有参数是否是null
if (pathSegmentsAndParams.concat(queryParams).filter(isInvalid).length) {
return null;
}
当参数中有null时或者缺少参数时,就返回null
这个问题同样也影响到了ui-sref方法,造成ui-sref失败无法转化为href="#/…
但是在旧版本是逐个for循环,逐个的添加url字符串,遇到为null的参数会跳过。
贴上旧版本对照
UrlMatcher.prototype.format = function (values) {
values = values || {};
var segments = this.segments, params = this.parameters(), paramset = this.params;
if (!this.validates(values)) return null;
var i, search = false, nPath = segments.length - 1, nTotal = params.length, result = segments[0];
function encodeDashes(str) { // Replace dashes with encoded "\-"
return encodeURIComponent(str).replace(/-/g, function(c) { return '%5C%' + c.charCodeAt(0).toString(16).toUpperCase(); });
}
for (i = 0; i < nTotal; i++) {
var isPathParam = i < nPath;
var name = params[i], param = paramset[name], value = param.value(values[name]);
var isDefaultValue = param.isOptional && param.type.equals(param.value(), value);
var squash = isDefaultValue ? param.squash : false;
var encoded = param.type.encode(value);
if (isPathParam) {
var nextSegment = segments[i + 1];
if (squash === false) {
if (encoded != null) {
if (isArray(encoded)) {
result += map(encoded, encodeDashes).join("-");
} else {
result += encodeURIComponent(encoded);
}
}
result += nextSegment;
} else if (squash === true) {
var capture = result.match(/\/$/) ? /\/?(.*)/ : /(.*)/;
result += nextSegment.match(capture)[1];
} else if (isString(squash)) {
result += squash + nextSegment;
}
} else {
if (encoded == null || (isDefaultValue && squash !== false)) continue;
if (!isArray(encoded)) encoded = [ encoded ];
encoded = map(encoded, encodeURIComponent).join('&' + name + '=');
result += (search ? '&' : '?') + (name + '=' + encoded);
search = true;
}
}
return result;
};
最简单的办法就是注释这行
if (pathSegmentsAndParams.concat(queryParams).filter(isInvalid).length) {
return null;
}
然后,就可以获取url了。希望在新版本中能解决这个bug
上一篇: js封装转换时间格式
下一篇: js转换时间格式