Angularjs 使用ng include保留传统的锚行为

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] ... [网页内容] 大字标题 [更多内容] 那很好。现在我在某处介绍一个模

我不是在构建一个单页应用程序,而是在某些地方使用AngularJS的“传统”站点。我遇到了以下问题(使用1.3.0-beta.6):

标准工作锚链:

<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>