如何在Angular Js1.2中防止重定向<a href="#something">? (注意:这是一个标题,不需要回答。)

25

我原来在应用程序中使用的是AngularJs-1.0.7和Bootstrap。最近我从AngularJs-1.0.7迁移到了AngularJs-1.2。我正在使用Bootstrap的手风琴和选项卡。

选项卡的HTML代码包含如下内容:<a href="#id_for_content">

<ul id="myTab" class="nav nav-tabs">
    <li class="active"><a href="#firstTab" data-toggle="tab">Home</a></li>
    <li><a href="#secondTab" data-toggle="tab">Profile</a></li>
</ul>

<div id="myTabContent" class="tab-content">
    <div class="tab-pane fade in active" id="firstTab">
      <p>Content for first tab.</p>
    </div>
    <div class="tab-pane fade" id="secondTab">
      <p>Content For second tab.</p>
    </div>
</div>

在Angular的旧版本中,只有当我们使用锚标签 <a href="#/firstTab"> 时才会发生路由更改。但是AngularJs-1.2重定向到 <a href="#firstTab"> ,它不考虑 #firstTab 之间的 /。因此,在单击选项卡时,它会重定向到 http://web_url/#/firstTab 。如何解决这个问题?


我的解决方案

我找到了一个解决方案。我编写了一个指令来处理a标签。在该指令中检查href属性。如果匹配,则防止其默认行为。请查看以下代码。

app.directive('a', function() {
    return {
        restrict: 'E',
        link: function(scope, elem, attrs) {
            if(attrs.href === '#firstTab'|| attrs.href === '#secondTab'){
                elem.on('click', function(e){
                    e.preventDefault();
                });
            }
        }
   };
}); 

但使用这种方法的问题在于,我必须在这里检查每个选项卡ID或手风琴ID。如果我为它们使用动态ID,则无法在指令中进行检查。

如果您能找到更好的解决方案,请让我们都知道。


如果你使用了一个class指令怎么办?我的意思是,一个名为prevent-default的指令,带有restrict:'C',链接函数与没有if部分相同,那么你可以通过添加类"prevent-default"到任何地方来使用它... 像 <a href="..." class="prevent-default">...</a>,我猜我的解决方案也是一个hacky的解决方案,但比编写所有id要好。如果你希望,我可以修改代码并作为答案发送。 - Umut Benzer
如果/^#/.test(attrs.href),则适用于所有以#开头的链接。 - Adam
5
尝试添加 target="_self",通常会禁用链接的 Angular 路由。 - Chris Nicola
看看这些基于Bootstrap的原生Angular指令:http://angular-ui.github.io/bootstrap/ - dimirc
9个回答

50

只需将此代码添加到您的链接中:

target="_self"

你已经准备好了 ;)


对我没用。<a class="nav-link" href="#" target="_self">首页 <span class="sr-only">(当前)</span></a> - old-monk
你的 href 太泛泛了。尝试像这样使用 href="#something",我猜你已经在元素中有这个锚点了。 - Vassilis Pits

21
尝试使用 data-target="#something" ,这在开发和生产环境中都对我很有效。

哇,太棒了!现在我不必再使用angular-strap或angular-ui来实现模态框了,这样更容易。 - Catfish

11

我只想让您知道,解决这个问题还有另一种方法(无需在控制器中定义函数)。

您可以创建一个指令来阻止默认浏览器行为(实际上是更改URL):

var PreventDefault = function () {

    var linkFn = function (scope, element, attrs) {
        $(element).on("click", function (event){
            event.preventDefault();
        });
    };

    return {
        restrict: 'A',
        link: linkFn
    }
};

然后只需将指令添加到每个负责切换选项卡的a元素中,如下所示:

<ul id="myTab" class="nav nav-tabs">
    <li class="active"><a href="#firstTab" prevent-default data-toggle="tab">Home</a></li>
    <li><a href="#secondTab" prevent-default data-toggle="tab">Profile</a></li>
</ul>

<div id="myTabContent" class="tab-content">
    <div class="tab-pane fade in active" id="firstTab">
      <p>Content for first tab.</p>
    </div>
    <div class="tab-pane fade" id="secondTab">
      <p>Content For second tab.</p>
    </div>
</div>

6

一般来说,您可以通过使用$rootScope在所有作用域的原型上定义函数。在锚点标签上添加ng-click,并将$event传递给$rootScope处理程序。Angular还可以通过ng-click发送原始事件:

<a ng-click="tabclick($event)">

在模块的run块中,您可以在$rootScope上设置一个tabClick函数。

$rootScope.tabclick = function ($event) { $event.preventDefault(); }

这适用于任何范围,无需检查特定元素 ID。
示例代码:http://jsfiddle.net/stto3703/wQe6P/
祝好!

3
我使用了 target="_self" 而不是定义一个函数再去调用它。 - Sajith
1
你也可以使用<a href="#" ng-click="tabclick(); $event.preventDefault();">来避免在每个处理点击事件的函数中传递事件。 - Petr Urban

2

您可以使用ng-click在JS中调用函数。在该函数中,使用事件的preventDefault方法,并使用$locationhash方法更改URL中的哈希标识。


这不是一个好的解决方案。在这里,我需要在所有控制器中定义那个函数。 - Sajith

1
我也一直遇到这个问题,直到偶然发现了这个问题(以及你自己的答案)。事实上,你的解决方案几乎是正确的,只需要稍微修改就可以按照你的意愿工作。
除了你在选项卡中遇到的问题外,我还遇到了下拉链接的问题——当单击时,它们会导航离开当前页面,而不是下拉菜单——实际上,在任何设计为切换某些内容的链接上都存在此问题,即设置了data-toggle属性。
因此,对你的代码进行轻微修改以检查“toggle”属性的存在就可以解决我的问题。
app.directive('a', function() {
    return {
        restrict: 'E',
        link: function(scope, elem, attrs) {
            if(attrs.toggle){
                elem.on('click', function(e){
                    e.preventDefault();
                });
            }
        }
   };
});

希望这可以帮到您!

0

致谢 https://prerender.io/js-seo/angularjs-seo-get-your-site-indexed-and-to-the-top-of-the-search-results/

我的解决方案: - 在app.js中尝试添加"$locationProvider.hashPrefix('!');"

    .config(['$stateProvider', '$urlRouterProvider', '$httpProvider', '$locationProvider',
    function($stateProvider, $urlRouterProvider, $httpProvider, $locationProvider) {
    $stateProvider
    .state('menu', {
        url: '/',
        cache: false,
        abstract: true,
        templateUrl: 'static/www/templates/menu.html'
    })
    .state('menu.main_page', {
    url: 'app/main',
    cache: false,
    views: {
        'menuContent': {
          templateUrl: 'static/www/templates/mainpage.html',
          controller: 'MainCtrl'
        }
    }
    })
    $locationProvider.hashPrefix('!');
    $urlRouterProvider.otherwise(function ($injector, $location) {
        var $state = $injector.get('$state');
        $state.go('menu.mainpage');
    });
   }])
  • 在index.html中尝试添加

    <meta name="fragment" content="!">

就像Marcel上面所说的

.directive('a', function () {
return {
    restrict: 'E',
    link: function (scope, elem, attrs) {
        if (attrs.href && attrs.href.indexOf('#') > -1) {
            elem.on('click', function (e) {
                e.preventDefault();
            });
        }
    }
};
})

就是这样!对我有效!


0

你问题中的解决方案确实可行,但为了避免需要检查每个锚点的id,请更改

if (attrs.href === '#firstTab'|| attrs.href === '#secondTab')

if (attrs.href && attrs.href.indexOf('#') > -1)

指令:

.directive('a', function () {
    return {
        restrict: 'E',
        link: function (scope, elem, attrs) {
            if (attrs.href && attrs.href.indexOf('#') > -1) {
                elem.on('click', function (e) {
                    e.preventDefault();
                });
            }
        }
    };
})  

0
如果之前的答案没有成功,你可以尝试使用$timeout... 在这个例子中,我使用了AngularUI标签页...
vm.removeUserTab = function (user) {
    $timeout(function () {
        vm.activeTab = 0;
        var index = vm.userTabs.indexOf(user);
        vm.userTabs.splice(index, 1);
    });
};

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接