1. 路由启动 $locationProvider.html5Mode(true); 经过pushstatex修改urljavascript
app.jshtml
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”.html5
这样在模板 或者.routeprovider 配置路由的时候就不须要在另外拼装上baseurl了。节省了不少对url逻辑的处理。 可是 若是是script加载脚本 相对路径的话 可能会与base的配置冲突,个人项目使用requirejs一类的包加载器解决问题java
3,后端配置重定向 nodejs为例node
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 就是前端路由了服务器
源码小解:app
对路由监听路由实际上是监听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);