【问题标题】:AngularJS - Some beginner questions on performance and scopeAngularJS - 关于性能和范围的一些初学者问题
【发布时间】:2015-04-09 10:59:36
【问题描述】:

我最近继承了第三方开发人员编写的 Angular 模块。我以前从未使用过 Angular,并且被要求进行一些相当基本的更改,但我正在努力解决几个问题(我保证在此结束时会有一个问题)。

本质上,该模块只是一个多项选择问卷,具有一系列按钮,您可以单击一个按钮来选择答案,而前进/后退按钮则可以在问题之间移动。

目前模块被硬编码为使用 5 个按钮,并且按钮的位置在控制器中设置如下:

// scope here is the scope for the main controller
$scope.answerOptions = [
    { pos: 70 },
    { pos: 215 },
    { pos: 360 },
    { pos: 505 },
    { pos: 650 }
];

pos 就是简单的左偏移,垂直位置是固定的。这是在模板上实现的,如下所示:

<div class="circle" ng-repeat="o in answerOptions"
    option-pos="{{o.pos}}"
    ng-hide="sectionEnd"
    ng-class="selectedOptionStyle($parent.selectedAnswer - 1 == $index)"
    ng-click="selectAnswer($index)">
</div>

然后指令optionPos 是:

.directive('optionPos', function(){
  return function(scope, elm, attrs) {
    attrs.$observe('optionPos', function(x){
      elm.css('left', x - 60 + 'px');
    })
  }
})

我被要求让它与任意数量的按钮一起工作,并在 x 和 y 中定位,并允许自定义答案(目前它只是将单击按钮的数组索引发送回服务器)。我认为这将是一个简单的更改,并且诚然,如果我实现相同的系统,使用插值设置 x 和 y,然后只需将 Y 添加到 optionPos 指令,这将很容易。但是我对这种方法有几个问题:

  • 它不能很好地适应按钮上的属性数量。例如除了 x 和 y 之外,还有一些其他数据我想从 answerOption 对象分配给按钮(例如发送到服务器的答案,以及将来可能的其他事情),我不想必须将每个属性分配为 DOM 元素上的单独属性。
  • 我担心attrs.$observe 是不必要的资源密集型,因为一旦模块加载,该值将永远不会改变,并且 $observe 将(大概?)为该属性添加一个监视。类似地使用插值来设置 DOM 元素上的坐标。
  • 以某种无法定义的方式感觉不对,就像可能有更好的方法来做到这一点一样,我只是没有向 Google 提出正确的问题。

在大量阅读 Angular 的文档和教程之后,我尝试做的事情是这样的:

// this would no longer be hard coded into the controller
// but once it is retrieved, this is what is set in the scope
// scope is still the main controller scope
$scope.answerOptions = [
    { Answer: 1, pos: { X: 180, Y: 120} },
    { Answer: 2, pos: { X: 360, Y: 120} },
    { Answer: 3, pos: { X: 540, Y: 120} }
];

模板:

<div class="circle" ng-repeat="o in answerOptions"
    answer-option="o"
    option-button
    ng-hide="sectionEnd"
    ng-class="selectedOptionStyle($parent.selectedAnswer - 1 == $index)"
    ng-click="selectAnswer(o.Answer)">
</div>

指令:

.directive('optionButton', function(){
     return {
         restrict: 'A',
         scope: {
             answerOption: '='
         },
         link: function(scope, elm, attrs) {
             elm.css('left', scope.answerOption.pos.X - 60 + 'px');
             elm.css('top', scope.answerOption.pos.Y - 60 + 'px');
         }
     }

上述解决方案的问题是我的指令正在创建一个隔离范围,因此所有其他对范围进行函数调用的指令(例如ng-hide)现在都已损坏,我不想重新为本质上非常简单的更改构建整个模块

因此,正如我在长时间闲逛后所承诺的那样 - 问题:

对于任何拥有超过 24 小时 Angular 经验的人来说,我是不是走错路了?我遇到的问题让我感觉像代码味道,但我不确定这是因为原始开发人员以难以维护/扩展的方式编写模块,还是我正在接受完全错误的做法。我遇到的问题似乎源于这样一个事实,即基本上整个应用程序逻辑都设置为主控制器范围内的各种功能。为该控制器设置范围大约需要 800 行 JS,其中许多函数定义了一大堆不同的东西。这是应该构建角度应用程序的方式吗,大部分逻辑都在范围内,然后直接从模板中调用它,例如ng-hide="sectionEnd"?

【问题讨论】:

  • 800 行 JS 用于控制器设置代码是正常的。我完全不是专家的意见,再深入研究文档几天,你会在几个小时内重写它,以满足你的需要,甚至更多。除此之外,如果没有详细的要求,很难判断您的方法。

标签: javascript angularjs


【解决方案1】:

一个怪物控制器不是一个好习惯。页面上的每个控制器都应该有焦点,并且最多应该有 5 个方法(指南)。通过拥有专注的控制器,您可以管理如何让您的应用程序获取其数据。

一旦有了控制器来检索应用程序数据,就应该利用指令将功能封装到可重用指令中。

此外,如果属性及其内插值从不改变,$observe 将不会产生重大成本。

我推荐以下准则:

  1. 实施服务以检索应用程序数据
  2. 控制器应调用服务来检索应用程序数据并将其附加到范围。
  3. 指令应有助于保持控制器的精简,并通过在可重用指令中保持复杂或共享逻辑来提高可维护性。

【讨论】:

  • Re 3,我将指令视为封装表示逻辑的一种方式。它们应该有助于保持控制器的精简,但这不是它们的特定目的。
  • 是的,这是一个副作用,但它说明了可维护性——这是一个有效的观点
  • @DrewR 这证实了我从其他网站看到的情况。这个tutorial on services, controllers and directives 提出了类似的观点(如果其他人通过谷歌遇到这个问题并希望获得关于何时使用服务、控制器和指令的初学者指南,这对我非常有帮助)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-01-28
  • 2014-05-11
  • 1970-01-01
  • 2019-05-16
相关资源
最近更新 更多