Angularjs 使用ng include保留传统的锚行为
我不是在构建一个单页应用程序,而是在某些地方使用AngularJS的“传统”站点。我遇到了以下问题(使用1.3.0-beta.6): 标准工作锚链:Angularjs 使用ng include保留传统的锚行为,angularjs,Angularjs,我不是在构建一个单页应用程序,而是在某些地方使用AngularJS的“传统”站点。我遇到了以下问题(使用1.3.0-beta.6): 标准工作锚链: <a href="#foo">Link text</a> ... [page content] <a id="foo"></a> <h1>Headline</h1> [more content] ... [网页内容] 大字标题 [更多内容] 那很好。现在我在某处介绍一个模
<a href="#foo">Link text</a>
... [page content]
<a id="foo"></a>
<h1>Headline</h1>
[more content]
... [网页内容]
大字标题
[更多内容]
那很好。现在我在某处介绍一个模板:
<script type="text/ng-template" id="test-include.html">
<p>This text is in a separate partial and inlcuded via ng-include.</p>
</script>
本文是一个单独的部分,通过ng include包含
可通过以下方式调用:
<div ng-include="'test-include.html'"></div>
局部连接已正确包含,但锚链不再工作。单击“链接文本”现在将显示的URL更改为/#/foo
,而不是/#foo
,页面位置不变
我的理解是,使用ng include
隐式地告诉Angular我想要使用routes系统并覆盖浏览器的本机锚链接行为。我看到了一些建议,建议将我的html锚链接更改为。/#foo
,但由于其他原因,我不能这样做
我不打算使用routes系统-我只想使用
ng include
,而不会影响浏览器行为。这可能吗?原因是angular重写了标准HTML标记的行为,其中包括
或简单地使用双哈希作为:
<a href='##foo'>Link text</a>
演示:
我的理解是,使用ng include隐式地告诉我们
我想使用routes系统并覆盖浏览器的
本机锚链接行为。我看到了一些建议
这是通过将我的html锚链接更改为#/#foo实现的,但我不能这样做
因为其他原因
路由系统是在一个单独的模块ngRoute
中定义的,因此,如果您没有自己注入它——我很确定您没有注入它——它根本无法访问
这里的问题有些不同
ng include
取决于:$http
,$templateCache
,$anchorScroll
,$animate
,$sce
。因此,请使用ng include
启动所有这些服务
最自然的调查对象是$anchorScroll
。的代码似乎没有任何危害,但服务依赖于$window
,$location
,$rootScope
。$location
的第616行显示:
baseHref = $browser.baseHref(), // if base[href] is undefined, it defaults to ''
因此,基本上,如果以前没有设置,则基本href设置为'
现在看看:
至于使用命名锚点,比如
你基本上是在声明所有与它相关的链接,
包括命名锚。没有一个相对链接是相对于的
当前请求URI不再存在(如果没有
标签)
如何缓解这个问题?
我今天没有太多时间,所以我自己无法测试它,但我会尝试检查的第一个选项是连接到事件,如果新url是#xxxxxx
类型,只需防止默认行为并使用$anchorScroll
本地方法滚动即可
更新
我认为这段代码应该完成以下工作:
$scope.$on("$locationChangeStart", function (event, next, current) {
var el, elId;
if (next.indexOf("#")>-1) {
elId = next.split("#")[1];
el = document.getElementById(elId);
if(el){
// el.scrollIntoView(); do not think we need it
window.location.hash = "#" + elId;
event.preventDefault();
}
}
});
不必将角度应用程序应用于整个页面,您可以将应用程序仅隔离到要执行ng include
的位置。这将允许应用程序范围外的链接保留其正常功能,同时允许根据需要处理应用程序内的链接
请参见本节:
plunkr显示应用程序外部正常运行的链接,以及应用程序内部使用覆盖a
指令恢复正常功能的链接。HTML5模式允许保留“标准”URL(而不是“hashbang”[没有bang!]URL)
您可以在应用程序中运行整个页面,但我认为值得演示如何在任何情况下将angular与页面的某些部分隔离。这是最好的解决方案,适用于angular的最新版本:
派对迟到了很多,但我发现添加一个简单的target=“\u self”可以解决问题
<a href="#anchor" target="_self">Link</a>
来自OP的
说明,如果没有使用
ng include,滚动是有效的,因此您的第一个假设似乎是不正确的。此外,OP确实想/不能使用href
玩任何把戏,因此第二个选项可能也不起作用。artur,正确。我确实有一个使用codefformer建议的技术的工作演示,但不幸的是重构所有内部链接不是一个选项(不是b/c,这是太多的工作,但因为我们将内联受信任的外部方提供的应用程序,我们不能要求他们以特殊方式编写所有锚,他们无法提前测试,等等)。我们真的在寻找一种非侵入性的方法来实现这一点。但是,感谢codef0rmer.arturgrzesiak,感谢您纠正我的错误,因为我的假设是错误的,但是@shacker您可以在自定义指令的帮助下更新它(见上面的更新)。这个答案几乎有效-导航正确,但显示的URL随后更改为/####foo-我如何使其显示为正常的/#foo?谢谢。该指令解决方案非常适合我的IE8客户端。谢谢!您定义了
吗?artur,我已经基本按照本文所示工作,但现在浏览器中的URL没有“没有反映更改。我尝试在导航后将$location.path()和$location.url()设置为新位置,但没有骰子。有什么想法吗?@shacker您可以直接从回调参数访问下一条和当前路线。查看更新的答案。(但我没有测试它)哦,dynamite-这很好,但有一个小小的例外:显示的URL指向/#/foo而不是/#foo。有什么方法可以纠正吗?非常感谢!例如,即使我将$location.hash(elId)更改为$location.hash(“/#bar”),显示的URL也不会受到影响。IOTW$location.h
baseHref = $browser.baseHref(), // if base[href] is undefined, it defaults to ''
$scope.$on("$locationChangeStart", function (event, next, current) {
var el, elId;
if (next.indexOf("#")>-1) {
elId = next.split("#")[1];
el = document.getElementById(elId);
if(el){
// el.scrollIntoView(); do not think we need it
window.location.hash = "#" + elId;
event.preventDefault();
}
}
});
<a href="#anchor" target="_self">Link</a>