从 Angular 中删除 hashchange 事件,或防止 Angular 重写锚链接
Remove hashchange event from Angular, or prevent Angular from rewriting anchor links
我们有一个使用 Angular 的项目,但仅用于它的 UI binding/AJAX 方面,不用于任何类型的路由或 SPA 功能。
我们希望能够在我们选择的 CMS 中撰写的文章中使用锚点 links (#section-2
),以及使用来自其他网站的锚点 links页面 (/my-page#section-C
),但 Angular 将这些重写为 #/section-2
,这破坏了 CMS 设置的锚点 link。
无法扩充 CMS 来修改锚 link 的处理方式。
是否可以:
从 Angular 中删除 hashchange
事件绑定?我看到这个事件附加在源文件 src/ng/browser.js
中,它处理一些路由和 link 重写,但它在闭包内部所以不能直接访问(我们是 linking 到 Angular 从 CDN 所以不可能修改 Angular 源,而且我们不想维护我们自己的 "custom" Angular来源).
设置一个选项或调用一个配置方法,最终禁用 Angular 的整个路由方面并防止它重写任何类型的 link? (或者,有没有办法不包含 Angular 的这一部分,但仍然保留 controller/UI binding/AJAX 的功能?)
注意我已经试过了:
$locationProvider.html5Mode(true)
然而,它会导致站点上的所有其他 link 无法运行,因为所有 link 都通过 Angular 进行处理。因此,如果我 link 到主页 (<a href="/">Home</a>
) 并单击带有 html5mode
的 link,link 什么都不做。
我相信你想要$anchorScroll. See this related answer: How to handle anchor hash linking in AngularJS
这是一个如何工作的例子。哈希仅被视为 id 的一部分:
app.controller('TestCtrl', function($location, $anchorScroll) {
var vm = this;
vm.scrollTo = function(id) {
$location.hash(id);
$anchorScroll();
}
});
<a ng-click="vm.scrollTo('#foo')">Foo</a>
<div id="#foo">Here you are</div>
见plunker demonstrating $anchorScroll
有了路由,你可以把link改成:
<a href="#/test##foo">Test/Foo</a>
并将其添加到 运行 配置中:
$rootScope.$on('$routeChangeSuccess', function(newRoute, oldRoute) {
if($location.hash()) {
$anchorScroll();
}
});
见plunker demonstrating scrolling with routing and $anchorScroll
作为一种解决方法(当然不是最佳实践),我最终修改了 Angular 源代码以删除 URL 重写。
我做了一些更改,但我相信导致锚链接再次工作的是在 Angular 来源的 location.js
的第 844 行添加了 return;
语句:
https://github.com/angular/angular.js/blob/master/src/ng/location.js#L844
这绕过了大部分 URL 重写功能。
我还完全删除了 browser.js
的第 262-264 行,这删除了 Angular 对 hashchange
事件的挂钩:
https://github.com/angular/angular.js/blob/master/src/ng/browser.js#L262-264
这似乎没有影响 Angular 的任何绑定功能,但确实导致锚链接再次开始工作。
但是为什么不用ng-route呢?它会完全解决你的问题。使用 Ng 路由你可以实现以下(这就是你想要的)。
<a href="http://www.example.com/base/#section-A"> Section A</a>
<a href="http://www.example.com/base/my-page#section-C">Another page</a>
<a href="/other-base/another?search">external</a>
这是 app.js 片段
app.config(function($locationProvider) {
$locationProvider.html5Mode(true).hashPrefix('!');
})
Html link重写
当您使用 HTML5 历史记录 API 模式时,您将不需要特殊的 hashbang links。您所要做的就是指定常规 URL link,例如:<a href="/some?foo=bar">link</a>
当用户点击此 link,
在旧版浏览器中,URL 更改为 /index.html#!/some?foo=bar
在现代浏览器中,URL 变为 /some?foo=bar
像下面这样的情况,link不会被重写;相反,浏览器将执行完整的页面重新加载到原始 link.
包含目标元素的链接
示例:<a href="/ext/link?a=b" target="_self">link</a>
转到不同域的绝对 link
示例:<a href="http://angularjs.org/">link</a>
以“/”开头的指向不同基本路径的链接
示例:<a href="/not-my-base/link">link</a>
相对links
务必检查所有相关的 links、图像、脚本等。Angular 要求您在主 html 的头部指定 url 基文件 (<base href="/my-base/index.html">
),除非在传递给 $locationProvider.html5Mode() 的 html5Mode 定义对象中将 html5Mode.requireBase 设置为 false。这样,即使文档的初始 url 不同,相对 urls 也将始终解析为该基础 url。
有一个例外:仅包含散列片段的链接(例如 <a href="#target">
)只会更改 $location.hash() 而不会修改 url。这对于滚动到同一页面上的锚点很有用,而无需知道用户当前在哪个页面上。
服务器端
使用此模式需要在服务器端进行 URL 重写,基本上您必须将所有 link 重写为应用程序的入口点(例如 index.html)。对于这种情况,需要标记也很重要,因为它允许 Angular 区分 url 的部分,即应用程序基础和应由应用程序处理的路径。
在设置$locationProvider.html5Mode(true)后,您是否也在文档的<head>
中设置了一个<base>
?
<html>
<head>
<base href="/">
</head>
</html>
看看here:
“有两件事需要完成。
- 正在配置 $locationProvider
- 设置相对链接的基础
或here
我在将 angular 与 wordpress 一起使用时遇到了类似的问题,并找到了一个非常简单的修复方法。您所要做的就是删除控制器中的所有 $location 注入。当您注入 $location 服务时(无论您是否使用它),它都会劫持 # 行为。
这意味着您必须仔细检查所有控制器、指令等,并确保 $location 服务没有被注入到任何地方。
HTH
Angular 的 $locationProvider.html5Mode function with it's rewriteLinks
设置正是您要找的。它会将 angular 置于 $location 仍可用于读取和写入浏览器的 url 的模式,但它永远不会尝试劫持 link 点击并触发 angular的SPA路由。
例如:
$locationProvider.html5Mode({
enabled: true,
requireBase: false,
rewriteLinks: false
});
我们有一个使用 Angular 的项目,但仅用于它的 UI binding/AJAX 方面,不用于任何类型的路由或 SPA 功能。
我们希望能够在我们选择的 CMS 中撰写的文章中使用锚点 links (#section-2
),以及使用来自其他网站的锚点 links页面 (/my-page#section-C
),但 Angular 将这些重写为 #/section-2
,这破坏了 CMS 设置的锚点 link。
无法扩充 CMS 来修改锚 link 的处理方式。
是否可以:
从 Angular 中删除
hashchange
事件绑定?我看到这个事件附加在源文件src/ng/browser.js
中,它处理一些路由和 link 重写,但它在闭包内部所以不能直接访问(我们是 linking 到 Angular 从 CDN 所以不可能修改 Angular 源,而且我们不想维护我们自己的 "custom" Angular来源).设置一个选项或调用一个配置方法,最终禁用 Angular 的整个路由方面并防止它重写任何类型的 link? (或者,有没有办法不包含 Angular 的这一部分,但仍然保留 controller/UI binding/AJAX 的功能?)
注意我已经试过了:
$locationProvider.html5Mode(true)
然而,它会导致站点上的所有其他 link 无法运行,因为所有 link 都通过 Angular 进行处理。因此,如果我 link 到主页 (<a href="/">Home</a>
) 并单击带有 html5mode
的 link,link 什么都不做。
我相信你想要$anchorScroll. See this related answer: How to handle anchor hash linking in AngularJS
这是一个如何工作的例子。哈希仅被视为 id 的一部分:
app.controller('TestCtrl', function($location, $anchorScroll) {
var vm = this;
vm.scrollTo = function(id) {
$location.hash(id);
$anchorScroll();
}
});
<a ng-click="vm.scrollTo('#foo')">Foo</a>
<div id="#foo">Here you are</div>
见plunker demonstrating $anchorScroll
有了路由,你可以把link改成:
<a href="#/test##foo">Test/Foo</a>
并将其添加到 运行 配置中:
$rootScope.$on('$routeChangeSuccess', function(newRoute, oldRoute) {
if($location.hash()) {
$anchorScroll();
}
});
见plunker demonstrating scrolling with routing and $anchorScroll
作为一种解决方法(当然不是最佳实践),我最终修改了 Angular 源代码以删除 URL 重写。
我做了一些更改,但我相信导致锚链接再次工作的是在 Angular 来源的 location.js
的第 844 行添加了 return;
语句:
https://github.com/angular/angular.js/blob/master/src/ng/location.js#L844
这绕过了大部分 URL 重写功能。
我还完全删除了 browser.js
的第 262-264 行,这删除了 Angular 对 hashchange
事件的挂钩:
https://github.com/angular/angular.js/blob/master/src/ng/browser.js#L262-264
这似乎没有影响 Angular 的任何绑定功能,但确实导致锚链接再次开始工作。
但是为什么不用ng-route呢?它会完全解决你的问题。使用 Ng 路由你可以实现以下(这就是你想要的)。
<a href="http://www.example.com/base/#section-A"> Section A</a>
<a href="http://www.example.com/base/my-page#section-C">Another page</a>
<a href="/other-base/another?search">external</a>
这是 app.js 片段
app.config(function($locationProvider) {
$locationProvider.html5Mode(true).hashPrefix('!');
})
Html link重写
当您使用 HTML5 历史记录 API 模式时,您将不需要特殊的 hashbang links。您所要做的就是指定常规 URL link,例如:<a href="/some?foo=bar">link</a>
当用户点击此 link,
在旧版浏览器中,URL 更改为 /index.html#!/some?foo=bar
在现代浏览器中,URL 变为 /some?foo=bar
像下面这样的情况,link不会被重写;相反,浏览器将执行完整的页面重新加载到原始 link.
包含目标元素的链接
示例:<a href="/ext/link?a=b" target="_self">link</a>
转到不同域的绝对 link
示例:<a href="http://angularjs.org/">link</a>
以“/”开头的指向不同基本路径的链接
示例:<a href="/not-my-base/link">link</a>
相对links
务必检查所有相关的 links、图像、脚本等。Angular 要求您在主 html 的头部指定 url 基文件 (<base href="/my-base/index.html">
),除非在传递给 $locationProvider.html5Mode() 的 html5Mode 定义对象中将 html5Mode.requireBase 设置为 false。这样,即使文档的初始 url 不同,相对 urls 也将始终解析为该基础 url。
有一个例外:仅包含散列片段的链接(例如 <a href="#target">
)只会更改 $location.hash() 而不会修改 url。这对于滚动到同一页面上的锚点很有用,而无需知道用户当前在哪个页面上。
服务器端
使用此模式需要在服务器端进行 URL 重写,基本上您必须将所有 link 重写为应用程序的入口点(例如 index.html)。对于这种情况,需要标记也很重要,因为它允许 Angular 区分 url 的部分,即应用程序基础和应由应用程序处理的路径。
在设置$locationProvider.html5Mode(true)后,您是否也在文档的<head>
中设置了一个<base>
?
<html>
<head>
<base href="/">
</head>
</html>
看看here:
“有两件事需要完成。
- 正在配置 $locationProvider
- 设置相对链接的基础
或here
我在将 angular 与 wordpress 一起使用时遇到了类似的问题,并找到了一个非常简单的修复方法。您所要做的就是删除控制器中的所有 $location 注入。当您注入 $location 服务时(无论您是否使用它),它都会劫持 # 行为。
这意味着您必须仔细检查所有控制器、指令等,并确保 $location 服务没有被注入到任何地方。
HTH
Angular 的 $locationProvider.html5Mode function with it's rewriteLinks
设置正是您要找的。它会将 angular 置于 $location 仍可用于读取和写入浏览器的 url 的模式,但它永远不会尝试劫持 link 点击并触发 angular的SPA路由。
例如:
$locationProvider.html5Mode({
enabled: true,
requireBase: false,
rewriteLinks: false
});