1. 路由啟動 $locationProvider.html5Mode(true); 通過pushstatex修改url
app.js
define([
'angular',
"App/Ctrl/controllers",
"App/Directive/directive",
"angularRoute"
], function (angular,controllers,directives,appDirec) {
var app=angular.module('myApp', ["ngRoute",controllers.name,directives.name])
templete="/front/propertyEntrust/view/templete"
/* /limitSell/add?propertyId=33 */
app.config(['$routeProvider',"$locationProvider", function ($routeProvider,$locationProvider) {
$locationProvider.html5Mode(true);
$routeProvider.when('/detail/:Id', { //詳情頁面
templateUrl: templete+'/detail.html'
});
$routeProvider.when('/rent/add/:propertyId', { //一般出租
templateUrl: templete+'/rent.html'
});
$routeProvider.otherwise({redirectTo: '/rent'});
}]);
return app
});
2. 設置前端路由開始的字段 即服務器路由的最后的字段
<base href="/fy/propertyEntrustApply/index/">
小注:angular在此處使用html5的base標簽來做baseurl的配置,而不是提供API 配置baseurl 非常巧妙,充分利用了html5 base標簽的特性。 debug 所有$0.href 發現都自動加上了了“/client.app/index”.
這樣在模板 或者.routeprovider 配置路由的時候就不需要在另外拼裝上baseurl了。節省了很多對url邏輯的處理。 但是 如果是script加載腳本 相對路徑的話 可能會與base的配置沖突,我的項目使用requirejs一類的包加載器解決問題
3,后端配置重定向 nodejs為例
app.get('/fy/propertyEntrustApply/index/*', function (req, res) {
res.render("a", {});
});
如上所示 http://localhost:3000/fy/propertyEntrustApply/index/rent/add/21
/fy/propertyEntrustApply/index/ 為服務器路由 指向a.ejs
之后/rent/add/21 就是前端路由了
源碼小解:
對路由監聽路由其實是監聽rootscope, loaction.path()的修改會自動更新rootscope,所以對location.path()的作用其實類似backbone的navigate(), 邏輯是手動走了路由隨后更改url的值,而不是相反。
其次 angular對視圖內的所有超鏈接做了事件代理
$rootElement.on('click', function(event) {
// TODO(vojta): rewrite link when opening in new tab/window (in legacy browser)
// currently we open nice url link and redirect then
if (event.ctrlKey || event.metaKey || event.which == 2) return;
var elm = jqLite(event.target);
// traverse the DOM up to find first A tag
while (lowercase(elm[0].nodeName) !== 'a') {
// ignore rewriting if no A tag (reached root element, or no parent - removed from document)
if (elm[0] === $rootElement[0] || !(elm = elm.parent())[0]) return;
}
var absHref = elm.prop('href');
if (isObject(absHref) && absHref.toString() === '[object SVGAnimatedString]') {
// SVGAnimatedString.animVal should be identical to SVGAnimatedString.baseVal, unless during
// an animation.
absHref = urlResolve(absHref.animVal).href;
}
var rewrittenUrl = $location.$$rewrite(absHref);
if (absHref && !elm.attr('target') && rewrittenUrl && !event.isDefaultPrevented()) {
event.preventDefault();
if (rewrittenUrl != $browser.url()) {
// update location manually
$location.$$parse(rewrittenUrl);
$rootScope.$apply();
// hack to work around FF6 bug 684208 when scenario runner clicks on links
window.angular['ff-684208-preventDefault'] = true;
}
}
});
可以看到, 點擊超鏈接的默認行為被禁止,如果超鏈接是負責路由跳轉的時候,獲得路由的url, 手動執行$rootScope.$apply();
注意$().prop 與$().attr()的區別 主要在$().attr() 拿的是$0.href, $().prop拿的是$0.getAttribute("href") , 此處需要去除 base路徑的拼裝,只拿前端路由。所以使用$().prop
$rootScope.$watch(function $locationWatch() {
var oldUrl = $browser.url();
var currentReplace = $location.$$replace;
if (!changeCounter || oldUrl != $location.absUrl()) {
changeCounter++;
$rootScope.$evalAsync(function() {
if ($rootScope.$broadcast('$locationChangeStart', $location.absUrl(), oldUrl).
defaultPrevented) {
$location.$$parse(oldUrl);
} else {
$browser.url($location.absUrl(), currentReplace);
afterLocationChange(oldUrl);
}
});
}
$location.$$replace = false;
return changeCounter;
});
angular 會watch rootscope,當rootscope更新的時候 $browser.url() H5模式啟用的條件下 調用pushstate 修改瀏覽器 url的值,最后afterLocationChange(oldUrl),廣播 $locationChangeSuccess 事件。
然后在 angular-rout.js ngroute模塊中會監聽$locationChangeSuccess 事件,執行路由模塊的邏輯。
$rootScope.$on('$locationChangeSuccess', updateRoute);
