【问题标题】:Prevent calling parent when nested ui-sref嵌套ui-sref时防止调用父级
【发布时间】:2014-04-07 01:15:31
【问题描述】:

假设我有嵌套的 DOM,每个都有 ui-sref 用于不同的 angular-ui-router 状态。我想点击 outer 只提醒外部,点击 inner 只提醒内部。目前如果我点击inner,它会同时提醒外部和内部状态。

HTML:

<!DOCTYPE html>
<html ng-app="plunker">

  <head>
    <meta charset="utf-8" />
    <title>AngularJS Plunker</title>
    <script>document.write('<base href="' + document.location + '" />');</script>
    <link rel="stylesheet" href="style.css" />
    <script data-require="angular.js@1.2.x" src="http://code.angularjs.org/1.2.13/angular.js" data-semver="1.2.13"></script>
    <script data-require="ui-router@0.2.8" data-semver="0.2.8" src="http://angular-ui.github.io/ui-router/release/angular-ui-router.js"></script>
    <script src="app.js"></script>
  </head>

  <body ng-controller="MainCtrl">
    <a ui-sref="outer" style="width:300px;height:300px;background:yellow;">
      Outer
            <span ui-sref="inner" style="width:100px;height:100px;background:red;">Inner</span>
    </a>
  </body>

</html>

Javascript:

var app = angular.module('plunker', ['ui.router']);

'use strict';

app.config(['$stateProvider', '$urlRouterProvider', '$locationProvider', function($stateProvider, $urlRouterProvider, $locationProvider) {

  $stateProvider
    .state("outer", {
      url: "/outer",
      resolve: {
        test: function() {
          alert("Triggered state outer");
          return true;
        }
      }
    })
    .state("inner", {
      url: "/inner",
      resolve: {
        test: function() {
          alert("Triggered state inner");
          return true;
        }
      }
    });

}]);


app.controller('MainCtrl', function($scope) {
});

链接:http://plnkr.co/edit/yzgUAA3lLwkF9svzczl3?p=preview

问题

  1. 如何防止inner触发outer状态?

  2. 我是否应该为内部 DOM 实现某种 stopImmediatePropagation,这样它就不会触发父 DOM 的 ui-sref

  3. 还有其他选择吗?也许手动使用$state.go

更新 1:

由于需要,我无法更改 HTML。这只是一个简化版本,因为在我的代码中,外部元素非常大,包含其他元素。

【问题讨论】:

    标签: javascript html angularjs angular-ui-router


    【解决方案1】:

    问题不在于您的 javascript 代码,而在于您的 html

      <a ui-sref="outer" style="width:300px;height:300px;background:yellow;">
          Outer
                <span ui-sref="inner" style="width:100px;height:100px;background:red;">Inner</span>
        </a>
    

    当您点击标签内的任意位置时,将调用外部状态。

    你的

    内部

    位于标签内,因此这个 html 元素绑定到 ui-sref="inner" 和 ui-sref="outer"

    下面的代码应该可以解决你的问题

    <a ui-sref="outer" style="width:300px;height:300px;background:yellow;">
          Outer
    
        </a>
    
    <span ui-sref="inner" style="width:100px;height:100px;background:red;">Inner</span>
    

    【讨论】:

    • 请看我的update 1。我知道更改 HTML 来解决这个问题,但这不是我的范围。
    【解决方案2】:

    我是否应该为内部 DOM 实现某种 stopImmediatePropagation,这样它就不会触发父 DOM 的 ui-sref

    是的,没错。

    或者,您可以重新排列您的 HTML,以便不存在父/子关系。

    【讨论】:

      【解决方案3】:

      在你的内部 stateprovider 添加事件停止传播/事件阻止默认值:

        $stateProvider.state("outer", {
            url: "/outer",
            resolve: {
             test: function() {
            alert("Triggered state outer");
            return true;
          }
        }
      }).state("inner", {
           url: "/inner",
           resolve: {
           test: function() {
      
            alert("Triggered state inner");
            //$event.stopPropagation();
            $event.preventDefault();
            return true;
          }
        }
      })
      

      更新 1: 我尝试了 plunker 演示并且 $event 可用。根据角度文档也适用于
      事件对象可用作 $event。 DEMOAngular doc

      更新 2: 如果您先按外部 div,上述方法有效,但我同意这不是 rt 解决方案。所以这是另一个有效的解决方案。检查范围的 statechangestart 并将最后一个状态名称保存在 var 中并检查其内部 then 事件是否 preventdefault;

      app.controller('MainCtrl', function($scope) {
         $scope.name = 'World';
         var laststate = "";
         $scope.$on('$stateChangeStart',
           function(event, toState, toParams, fromState, fromParams) {
                     //alert(laststate);
            if (laststate == "inner") {
               event.preventDefault();
             }
            laststate = toState.name;
          });
        });
      

      DEMO Plunker

      【讨论】:

      • 我点击了Inner,它提醒了Inner a和outer,因此不符合要求
      • 这个“hack”有效,但并不理想,因为我可能有inner1inner1000。因此,解决方案必须足够通用,以处理大量不同的 DOM 和其他 DOM 中的状态,并拥有自己的状态。
      【解决方案4】:

      这行得通

      <a ui-sref="outer" style="width:300px;height:300px;background:yellow;">
        Outer
              <span ui-sref="inner" style="width:100px;height:100px;background:red;" ng-click="$event.stopPropagation()">Inner</span>
      </a>
      

      我不知道你可以在与ui-sref 相同的元素中添加ng-click="$event.stopPropagation()"

      【讨论】:

      • 它有效,但我似乎正在重新加载整个页面,这可能不是所需的行为......当然不适合我。
      • ui-sref 更新 a 标签的 href 项,对点击事件没有影响。就像使用 jQuery 你可以$('a').attr('href', 'http://example.com').on('click', (e) =&gt; {/*something*/})
      【解决方案5】:

      使用这个...

       <a ui-sref="outer" style="width:300px;height:300px;background:yellow;">
       Outer
           <span ui-sref="inner" style="width:100px;height:100px;background:red;"
           ng-click="$event.stopPropagation()">Inner</span>
      </a>
      

      【讨论】:

      • 大卫你的功夫很厉害。
      • 我有一个类似的情况,但我不得不调用一个函数而不是内部链接。仅使用 $event.stopPropagation() 仍然会导致导航。添加 $event.preventDefault() 解决了这个问题。我的灵感来自stackoverflow.com/a/25636705/2487876
      • 确实非常强大。向你致敬!
      • 我喜欢这个解决方案的简单性。它非常适合制作原型和简单的物品。最好有一个专门的属性,比如上面的stopEvent
      • 大卫,你在原力的道路上很强大。
      【解决方案6】:

      为了一个完全不同的目的,我有一个 stopEvent 指令等待用于嵌套的 ui-sref 目的。

      <a ui-sref="outer">
        Outer
        <span ui-sref="inner" stop-event>Inner</span>
      </a>
      

      这是指令

      app.directive('stopEvent', function () {
        return {
          restrict: 'A',
          link: function (scope, element, attr) {
            element.bind('click', function (e) {
              e.stopPropagation();
            });
          }
        };
      });
      

      【讨论】:

        猜你喜欢
        • 2017-06-18
        • 1970-01-01
        • 2019-07-14
        • 2013-01-12
        • 1970-01-01
        • 2014-04-08
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多