笔者驽钝,最近由于工作关系才去学习了Angular,发现在合适的项目下使用Angular开发真是非常畅快!MVC框架需要一些学习成本才能上手,再加上Angular采用现在通行的约定优于配置(convention over configuration)理念,框架本身做了很多封装,所以实现起来需要开发人员对框架足够的熟悉。
Angular一个典型的使用场景就是单页应用,那么如何在一个单页面中改变URL,请与笔者一同学习。
Angular中使用内置的$location服务来监听、操作URL,包括如下功能:
相对于BOM原生的window.location,使用$location更利于测试用例的编写(通过$location来注入假数据),提供的接口也更友好(官方一直强调是jQuery-style getters and setters,我的理解就是支持链式写法),与URL实现了双向绑定,内部集成了HTML5的History API,所以建议使用$location服务。
如果想实现类似history.replaceState()的功能,可以使用replace方法,代码如下。本方法只会实现一次replace历史记录的功能。
$location.path('/someNewPath'); $location.replace(); // or you can chain these as: $location.path('/someNewPath').replace();
$location处于Angular的生命周期内,单个周期内的改变会统一在周期结束时生效,所以不必担心每次改变了$location,URL都会立刻变化。
注意:$location无法使整个页面重新加载。如果改变URL后希望重新加载页面,请使用$window.location.href。
配置$location服务,需要用$locationProvider设置参数:
html5Mode(mode): {boolean|Object}
hashPrefix(prefix): {string} Hashbang风格的URL中#号前面的前缀,习惯上用"!",虽然默认是""(没有!的#怎么能叫shebang呢。。)
$locationProvider.html5Mode(true).hashPrefix('!');
$locationProvider用于配置应用中Deep Linking的存储方式,就提供了上述两个配置接口。
$location服务支持配置两种URL格式:Hashbang模式(默认)和HTML5模式。两种模式下的API都是通用的。如下图
所谓的Hashbang就是在URL里会看到#,所有的路由变化都是在hash里面控制的,具体到URL长这样:https://docs.angularjs.org/#!/guide/introduction?search=test
如果我们用原生的window.location打印,会发现变化的部分其实都是在hash里,略eggache。
好处是各个浏览器都兼容,坏处是URL长相奇特,SEO也不友好。
所以Angular提供了HTML5模式。使用了HTML5的History API来控制URL的变化,不再有啰嗦的#。浏览器的兼容性可参考这里。鉴于兼容性和Angular内部的封装,建议采用本模式。
Angular内部做了向下兼容,采用本模式后,在低版本的浏览器仍会用Hashbang来降级处理,两种模式的URL也能自动实现相互转换,无需开发者关注。不过,以下三种情况,Angular不会做转换:
记得设置页面的根目录。
如果你的应用挂在根目录(https://myapp.com/),则设置为:
...
如果挂在子目录(https://myapp.com/subapp/),则设置为:
...
不设置会导致Angular无法正确处理相对链接和回退到hashbang模式。
服务端也要做相应的配置!
因为是单页应用,所以其他链接请求到服务器时,根本找不到对应的html,就会忧伤的返回404。所以需要将所有到应用根路径下的请求都重定向到某个页面(比如index.html)。这样浏览器里先由index.html启动应用,Angular发现URL变化了再定位到真正请求的路由上。