当前位置: 首页 > 面试题库 >

在angularJS中处理DOM:最佳做法?

满言
2023-03-14
问题内容

我们正在使用构建大型Web应用程序AngularJS。在不同情况下,我们经常使用自定义指令。当涉及到DOM操作,绑定事件等…发生时,我们在自定义指令的link函数中定义了操作DOM的函数,但是我们从控制器调用了它(我们在$scope因此它可以被给定的控制器访问)。我认为这样做的角度方法是为每个函数定义一个单独的自定义指令,并直接从模板中使用它,但是在我们的情况下,我不知道这样做会很方便很多自定义指令,所以BAD要做我们正在做的事情(定义在指令中操作DOM并从控制器调用它的函数),甚至具有一定意义,或者就像我们在控制器中操作DOM一样?对我们来说,这是一种关注点分离,我们从不定义仅在指令中操作控制器中DOM的函数,但从控制器中调用它似乎并不正确,是吗?

一个示例,显示我们的自定义指令的外观:

angular.module('exp', []).directive('customdirectiveExp', ['', function(){
// Runs during compile
return {
    name: 'customDirectiveExp',
    controller: "ControllerExp",
    controllerAs: "ctrl",
    templateUrl: 'templateExp',
    link: function($scope, iElm, iAttrs, controller) {

        /* These function will be called from the ControllerExp when it needs so.
         Function can do any things like manipulating the DOM, addin
         event listner ...
        */
        scope.manipulateDom1 = function(){
            // DOM manipualtion
        };

        scope.manipulateDom2 = function(){
            // DOM manipualtion
        };

        scope.manipulateDom3 = function(){
            // DOM manipualtion
        };

    }
};
}]);

问题答案:

我认为“不要从控制器操作DOM”的口号是从过去开始的,那时指令主要/仅使用链接功能(或指令控制器只是与其他指令相互通信的一种方式)。

当前建议的最佳实践是使用“组件”(可以通过指令实现),其中基本上所有指令逻辑都保留在控制器中。(例如,请注意,在Angular
2中没有链接功能,每个组件/指令基本上都是一个类/控制器(加上一些元数据)。)

在这种情况下,我认为从 指令的* 控制器中操作 指令 模板中的DOM完全可以。 *

这个想法是让模板/ HTML保持声明性。比较以下片段:

<!--
  `SomeController` reaches out in the DOM and
  makes changes to `myComponent`'s template --- BAD
-->
<div ng-controller="SomeController">
  ...
  <my-component></my-component>
  ...
</div>

<div ng-controller="SomeController">
  ...
  <!--
    `myComponent`'s controller makes changes to
    `myComponent`'s template --- OK
  -->
  <my-component></my-component>
  ...
</div>

在第一个(坏的)示例中,myComponent将具有不同的行为/外观,具体取决于它在DOM中出现的位置(例如,它在SomeController?下)。更重要的是,很难找出其他(无关)部分可能会更改其myComponent行为/外观。

在第二个(好的)示例中,myComponent的行为和外观在整个应用程序中将是一致的,并且很容易找出其含义:我只需要查看指令的定义(一个位置)。

但是有一些警告:

  1. 您不想将DOM操作代码与其他逻辑混合使用。(这将使您的代码难以维护且难以测试)。

  2. 通常,当所有子项都位于适当位置时(编译+链接),您想在链接后阶段中操作DOM。在控制器实例化期间运行DOM操作代码将意味着尚未处理模板内容。

  3. 通常,当您未在指令的上下文中实例化控制器时,您不希望运行DOM操作,因为这意味着您始终需要已编译的模板才能测试控制器。这是不希望的,因为即使您只想测试控制器逻辑中与DOM / HTML不相关的其他部分,它也会使单元测试变慢。

所以,我们能做些什么 ?

  • 在专用功能中隔离DOM操作代码。适当时将调用此函数(请参见下文),但是所有DOM交互都将集中在一个位置,这使得查看起来更加容易。

  • 将该函数公开为控制器方法,然后从指令的链接函数调用它(而不是在控制器初始化期间)。这样可以确保DOM处于所需状态(如果需要),并且还可以将“独立”控制器实例与DOM操作分离。

我们得到的是:

  • 如果将控制器实例化为指令的编译/链接的一部分,则将按预期方式调用该方法并操纵DOM。

  • 在单元测试中,如果不需要DOM操作逻辑,则可以直接实例化控制器并测试其业务逻辑(独立于任何DOM或编译)。

  • 您可以更好地控制DOM操作的发生时间(在单元测试中)。例如,您可以直接实例化控制器,但仍要传递$element,进行您可能要进行的任何声明,然后手动调用DOM操作方法并声明元素已正确转换。$element无需添加真实的DOM,更容易传递诸如添加事件侦听器之类的模拟内容。

这种方法的缺点(公开方法,并从链接函数调用它)是多余的样板。如果您使用的是Angular
1.5.x,则可以通过使用指令控制器生命周期挂钩(例如$onInit$postLink)来节省样板,而无需具有链接功能,只是为了握住控制器并在其上调用方法。(附加功能:将1.5.x组件语法与生命周期挂钩一起使用,将更易于迁移到Angular2。)

例子:

v1.5.x之前

.directive('myButton', function myButtonDirective() {
  // DDO
  return {
    template: '<button ng-click="$ctrl.onClick()></button>',
    scope: {}
    bindToController: {
      label: '@'
    }
    controllerAs: '$ctrl',
    controller: function MyButtonController($element) {
      // Variables - Private
      var self = this;

      // Functions - Public
      self._setupElement = _setupElement;
      self.onClick = onClick;

      // Functions - Definitions
      function _setupElement() {
        $element.text(self.label);
      }

      function onClick() {
        alert('*click*');
      }
    },
    link: function myButtonPostLink(scope, elem, attrs, ctrl) {
      ctrl._setupElement();
    }
  };
})

在v1.5.x之后

.component('myButton', {
  template: '<button ng-click="$ctrl.onClick()></button>',
  bindings: {
    label: '@'
  }
  controller: function MyButtonController($element) {
    // Variables - Private
    var self = this;

    // Functions - Public
    self.$postLink = $postLink;
    self.onClick = onClick;

    // Functions - Definitions
    function $postLink() {
      $element.text(self.label);
    }

    function onClick() {
      alert('*click*');
    }
  }
})


 类似资料:
  • 问题内容: 当我使用jQuery执行DOM操作(添加新HTML)时,AngularJS不会自动检测新HTML中的变量并将其替换为它们的值。例如: 这是一个简单的例子,但在元素更改HTML(此功能被称为后),输出它仍然不是什么 行 应该在上下文/范围的意思。 问题答案: 您必须注入(http://docs.angularjs.org/api/ng.$compile)并使用它,以便对新html 有所了

  • 问题内容: 我必须在php中解析大型XML文件,其中之一是6.5 MB,它们甚至可能更大。如我所读,SimpleXML扩展将整个文件加载到一个对象中,这可能不是很有效。以您的经验,最好的方法是什么? 问题答案: 对于大文件,您将要使用SAX解析器而不是DOM解析器。 使用DOM解析器,它将读取整个文件并将其加载到内存中的对象树中。使用SAX解析器,它将顺序读取文件并调用用户定义的回调函数来处理数据

  • 问题内容: 我正在寻找一种显示3列内容的方法。我找到了一种显示环绕列的方法,但是我不希望在此页面上显示。我正在寻找一种说法 3次,并在彼此之间显示3列。我最好的例子是The Verge(http://www.theverge.com/)。做这个的最好方式是什么? 问题答案: 我建议您使用或CSS。 CSS是更灵活的首选。一个例子是: 使用float:left会使3列相互粘连,并从居中的div“内容

  • 问题内容: 在我一直在构建的应用程序中,我们相当依赖于SharedPreferences,这使我思考了访问SharedPreferences时的最佳实践。例如,许多人说通过此调用可以访问它: 但是,这似乎很危险。如果您有依赖于SharedPreferences的大型应用程序,则可能会有密钥重复,尤其是在使用某些也依赖SharedPreferences的第三方库的情况下。在我看来,更好的使用方法是:

  • 问题内容: 当前,正在讨论具有单个sql连接体系结构的优缺点。 为了详细说明我们正在讨论的是,在应用程序创建时打开一个sql连接,在应用程序关闭或错误关闭该sql连接时。根本不创建另一个连接,而只使用那个与数据库进行通信。 我们想知道社区的想法。 问题答案: 一旦您在不确定的时间内不再需要连接,请立即将其关闭。这样,连接将返回到连接池(如果启用了连接池),并且可以被其他人(重新使用)。 (连接是昂

  • 问题内容: 我正在尝试编写一个小型节点应用程序,该应用程序将搜索并解析文件系统上的大量文件。为了加快搜索速度,我们尝试使用某种类型的map reduce。该计划将是以下简化方案: Web请求带有搜索查询 启动3个进程,每个进程分配1000个(不同)文件 进程完成后,它将“返回”结果回到主线程 一旦所有进程完成,主线程将通过返回组合结果作为JSON结果来继续 我对此有以下疑问: 这在Node中可行吗