Angular 在 HTML 属性中使用内联 JavaScript 不是“坏习惯”吗?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/14793692/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-26 22:35:24  来源:igfitidea点击:

Angular's use of Inline JavaScript in HTML attributes is not "bad practice"?

javascriptangularjs

提问by AndrewHenderson

As I read through the Angular tutorials, I really like a lot of it, but isn't "ng-click" the equivalent of an inline onClick? My understanding was that the JavaScript community had determined inline JavaScript event handlers in your HTML was "bad practice."

当我通读 Angular 教程时,我真的很喜欢其中的很多,但是“ng-click”不就等同于内联 onClick 吗?我的理解是 JavaScript 社区认为 HTML 中的内联 JavaScript 事件处理程序是“不好的做法”。

<img ng-src="{{img}}" ng-click="setImage(img)">

It would be great to know why this is no longer considered "incorrect" when using Angular.

很高兴知道为什么在使用 Angular 时这不再被认为是“不正确的”。

Source: http://docs.angularjs.org/tutorial/step_10

来源:http: //docs.angularjs.org/tutorial/step_10

回答by Michelle Tilley

Really, it all comes down to the fact that your view code has to be hooked into your application logic somehow. Best practices for AngularJS generally state that you should write your own models--objects that represent your business domain--and attach them to the scope. Imagine some code like this:

真的,这一切都归结为您的视图代码必须以某种方式连接到您的应用程序逻辑的事实。AngularJS 的最佳实践通常规定您应该编写自己的模型——代表您的业务领域的对象——并将它们附加到范围。想象一些这样的代码:

<img ng-src="{{img}}" ng-click="myProfile.setMainImage(img)">
myApp.controller("ProfileController", function($scope, myProfile) {
  $scope.myProfile = myProfile;
});

The view says "when this image is clicked, it will call setMainImage() on myProfile." The business logic is inside myProfile, where it can be tested, etc. The view is just a hook.

该视图显示“单击此图像时,它将调用 myProfile 上的 setMainImage()。” 业务逻辑在里面myProfile,在那里可以测试等等。视图只是一个钩子。

In a more "traditional" or "vanilla" jQuery setup, you'd have to write something like the following:

在更“传统”或“普通”的 jQuery 设置中,您必须编写如下内容:

$("#someId img").on('click', function() {
  var img = $(this).attr('src');
  myProfile.setMainImage(img); // where does myProfile come from here?
                               // how does it update the view?
});

Of course, the JavaScript community has determined that writing large applications in this fashion isn't really tenable, in part because of the disconnect between the views and the model objects (as indicated by the comments in the code snippet), which is why we have frameworks like Angular in the first place.

当然,JavaScript 社区已经确定以这种方式编写大型应用程序并不能真正站得住脚,部分原因是视图和模型对象之间的脱节(如代码片段中的注释所示),这就是为什么我们首先拥有像 Angular 这样的框架。

So, we know this native jQuery code is not ideal, but we're still not sure about the whole ngClickthing. Let's compare it to another very popular JavaScript framework that provides an MV* architecture, Backbone. In a recent RailsCasts episode on AngularJS, someone asked a very similar question:

所以,我们知道这个原生 jQuery 代码并不理想,但我们仍然不确定整个ngClick事情。让我们将其与提供 MV* 架构的另一个非常流行的 JavaScript 框架 Backbone 进行比较。在最近关于 AngularJS 的 RailsCasts 一集中,有人问了一个非常相似的问题

Is it just me, or AngularJS looks so a bad idea? Ryan, don't get me wrong, the episode was great, but I'm not convinced by the framework.

All that ng-show, ng-repeat, ng-classare looking like the old Java's JSF, and similar frameworks. It also enforces obtrusive JS with ng-submitand ng-click.

So my point is: your view will easily become cluttered and totally dependent on it. The advantage of other frameworks like Backbone, is to have a separation of concerns between the presentation and the behavior (less or no dependencies), and a structured client side application (MVVM).

是我一个人,还是 AngularJS 看起来很糟糕?Ryan,别误会我的意思,这一集很棒,但我不相信这个框架。

所有这一切ng-showng-repeatng-class正在寻找像老Java的JSF,以及类似的框架。它还使用ng-submit和强制执行突兀的 JS ng-click

所以我的观点是:你的观点很容易变得混乱并完全依赖它。其他框架(如 Backbone)的优点是在表示和行为(较少或没有依赖性)以及结构化客户端应用程序 (MVVM) 之间分离关注点。

My responseis applicable here as well:

我的回答也适用于此:

In a framework like Backbone, you'd have something like the following code (taken from the Backbone website, minus a few lines):

var DocumentView = Backbone.View.extend({

  events: {
    "dblclick"                : "open",
    "click .icon.doc"         : "select",
    "contextmenu .icon.doc"   : "showMenu",
    "click .show_notes"       : "toggleNotes",
    "click .title .lock"      : "editAccessLevel",
    "mouseover .title .date"  : "showTooltip"
  },

  open: function() {
    window.open(this.model.get("viewer_url"));
  },

  select: function() {
    this.model.set({selected: true});
  },

});

In this object which is a view, you are setting up event handlers on various elements. These event handlers call functions on the view object, which delegate to models. You also set up callbacks on various model events (such as change) which in turn call functions on the view object to update the view accordingly.

In Angular, the DOM is your view. When using ng-click, ng-submit, etc., you are setting up event handlers on these elements, which call functions that should delegate to model objects. When using ng-show, ng-repeat, etc. you are setting up callbacks on model events that change the view.

The fact that AngularJS sets up these [hooks and] callbacks behind the scenes for you is irrelevant; the only difference between this and something like Backbone is that Angular lets you write your view declaratively--you describe what your view is--rather than imperatively--describing what your view does.

So, in the end, <a ng-click="model.set({selected: true})">really adds no more dependencies than

events: {
  'click a': 'select'
},

select: function() {
  this.model.set({selected: true});
}

...but it sure is a hell of a lot less code. ;)

在像 Backbone 这样的框架中,您将拥有类似于以下代码的内容(取自 Backbone 网站,减去几行):

var DocumentView = Backbone.View.extend({

  events: {
    "dblclick"                : "open",
    "click .icon.doc"         : "select",
    "contextmenu .icon.doc"   : "showMenu",
    "click .show_notes"       : "toggleNotes",
    "click .title .lock"      : "editAccessLevel",
    "mouseover .title .date"  : "showTooltip"
  },

  open: function() {
    window.open(this.model.get("viewer_url"));
  },

  select: function() {
    this.model.set({selected: true});
  },

});

在这个作为视图的对象,您正在为各种元素设置事件处理程序。这些事件处理程序调用视图对象上的函数,这些函数委托给模型。您还可以在各种模型事件(例如change)上设置回调,这些事件又会调用视图对象上的函数以相应地更新视图。

在 Angular 中,DOM 就是你的视图。使用ng-clickng-submit等时,您将在这些元素上设置事件处理程序,这些事件处理程序调用应委托给模型对象的函数。使用ng-showng-repeat等时,您正在对更改视图的模型事件设置回调。

AngularJS 在幕后为您设置这些 [钩子和] 回调的事实无关紧要;这与 Backbone 之类的唯一区别在于,Angular 允许您以声明方式编写视图——你描述你的视图什么——而不是命令式——描述你的视图什么。

所以,最后,<a ng-click="model.set({selected: true})">真正添加的依赖不是比

events: {
  'click a': 'select'
},

select: function() {
  this.model.set({selected: true});
}

...但它确实少了很多代码。;)

(Note: really, the Angular version should be <a ng-click="select()">, and the selectmethod on the scope would be like the selectmethod in the view in the Backbone example.)

(注意:实际上,Angular 版本应该是<a ng-click="select()">,并且select作用域上的方法将类似于selectBackbone 示例中视图中的方法。)

Now, perhaps a legitimateconcern is that you don't like the event hooks in your markup. Personally, I greatly prefer the declarative nature of Angular's views, where your markup describes what the view isand you have two way binding between events (whether they be user generated or simply changes in the model) and your views--I find I write far less boilerplate code to hook up events (especially changes in the view driven by changes in the models), and I think it's easier to reason about the view in general.

现在,也许一个合理的担忧是您不喜欢标记中的事件挂钩。就我个人而言,我非常喜欢 Angular 视图的声明性本质,其中您的标记描述了视图是什么,并且您在事件(无论它们是用户生成的还是模型中的简单更改)和您的视图之间有两种方式绑定——我发现我写用于连接事件的样板代码要少得多(尤其是由模型更改驱动的视图更改),而且我认为通常更容易对视图进行推理。