angular.element vs document.getElementById 或带有旋转(忙碌)控制的 jQuery 选择器

Posted

技术标签:

【中文标题】angular.element vs document.getElementById 或带有旋转(忙碌)控制的 jQuery 选择器【英文标题】:angular.element vs document.getElementById or jQuery selector with spin (busy) control 【发布时间】:2013-06-18 06:57:22 【问题描述】:

我正在使用 Spin 控件的“Angularised”版本,如下所述:http://blog.xvitcoder.com/adding-a-weel-progress-indicator-to-your-angularjs-application/

我不喜欢所示解决方案的一件事是在服务中使用 jQuery,该服务有效地将旋转控件附加到 DOM 元素。我更喜欢使用角度构造来访问元素。我还想避免“硬编码”微调器需要在服务中附加到的元素的 id,而是使用在服务(单例)中设置 id 的指令,以便服务的其他用户或服务本身不需要知道这一点。

我正在为 angular.element 给我们的东西与 document.getElementById 在同一元素 id 上给我们的东西苦苦挣扎。 例如。这有效:

  var target = document.getElementById('appBusyIndicator');

这些都不行:

  var target = angular.element('#appBusyIndicator');
  var target = angular.element('appBusyIndicator');

我显然在做一些应该相当明显的错误!有人可以帮忙吗?

假设我可以实现上述工作,我在尝试替换 jQuery 对元素的访问时遇到了类似的问题: 例如$(target).fadeIn('fast'); 工作 angular.element('#appBusyIndicator').fadeIn('fast')angular.element('appBusyIndicator').fadeIn('fast') 没有

有人能指出一个很好的文档示例,它阐明了 Angular“元素”与 DOM 元素的使用吗? Angular 显然用自己的属性、方法等“包装”了元素,但通常很难获得原始值。例如,如果我有一个<input type='number'> 字段,并且我想访问当用户键入“--”(不带引号)时在 ui 中可见的原始内容,我什么也得不到,大概是因为“type=number”意味着Angular 拒绝输入,即使它在 UI 中可见,我想看到它,以便我可以测试它并清除它。

任何指针/答案表示赞赏。

谢谢。

【问题讨论】:

angular.element 是 jQlite 对象或 jQuery 对象(如果您正在加载 jQuery)。 【参考方案1】:

如果您还没有阅读 angular element 文档,您应该阅读,这样您就可以了解 jqLit​​e 支持什么以及不支持什么 -jqlite 是 angular 内置的 jquery 的子集。

那些选择器无法单独使用 jqLit​​e,因为不支持按 id 的 选择器

  var target = angular.element('#appBusyIndicator');
  var target = angular.element('appBusyIndicator');

所以,要么:

您单独使用 jqLit​​e,比 jquery 更受限制,但在大多数情况下已经足够了。 或者您在您的应用程序中包含完整的 jQuery 库,并在您真正需要 jquery 的地方像普通 jquery 一样使用它。

编辑:请注意,应在 angularJS 之前加载 jQuery,以便优先于 jqLit​​e:

真正的 jQuery 总是优先于 jqLit​​e,只要它是 在 DOMContentLoaded 事件触发之前加载。

Edit2:我之前错过了问题的第二部分:

<input type="number"> 的问题,我认为这不是角度问题,而是 native html5 数字元素的预期行为。

即使您尝试使用 jquery 的 .val() 或原始的 .value 属性检索它,它也不会返回非数字值。

【讨论】:

我们有完整的 jQuery 库 - 否则我上面解释的 $ 场景将无法工作。我的问题是为什么 $ 有效但 angular.element 无效 - 即使完整的 jQuery 可用。 你是在 angular.js 之前还是之后包含 jQuery?它应该包含在 before 角度。 id do 的选择器可与 jQuery 一起使用:jsbin.com/ohumiy/1/edit 他们正在另一个指令中工作(即 angular.element 以通过 id 访问某些内容)。问题似乎是该控件通过将自身附加到该元素来工作的方式,尽管我不明白为什么相同的 jQuery 等效项应该直接工作。直接使用 jQuery 我的指令有一个结束标记 - 自结束标记不起作用(没有错误只是一个空白屏幕)这让我怀疑控件。 在我的第二点上,还有类似 view$value 的东西,它可以用来检索元素的内容,但是在输入 type=number 的情况下,用户输入了“--”这个是空的。我希望元素上的 $rawInputValue 之类的属性可以在 Angular 介入之前查看内容,因为“--”仍在 UI 中,即使我无法在指令中以编程方式访问它。【参考方案2】:

可以这样工作:

var myElement = angular.element( document.querySelector( '#some-id' ) );

您将Document.querySelector() native javascript 调用包装到angular.element() 调用中。因此,您始终可以在 jqLit​​ejQuery 对象中获取元素,具体取决于 jQuery 是否可用/已加载。

Official documentation for angular.element:

如果 jQuery 可用,则angular.elementjQuery 函数的别名。如果 jQuery 不可用,angular.element 将委托给 AngularjQuery 的内置子集,称为“jQuery lite”或 jqLit​​e

Angular 中的所有元素引用总是用 jQueryjqLite 包装(例如指令编译或链接函数中的元素参数)。它们绝不是原始的DOM 引用。

如果您想知道为什么要使用document.querySelector(),请阅读this answer。

【讨论】:

有什么理由更喜欢 document.querySelector('#...') 而不是简单地使用 document.getElementById()? 您也可以在角度元素上执行此操作:var elDivParent = angular.element(elem[0].querySelector('#an-id'));,elem 是一个角度元素。这样您就可以在元素内部进行搜索。对单元测试很有用。 @Kato 更多信息在this answer。希望对您有所帮助。 使用 Google Maps API,这很有效:var autocomplete = new google.maps.places.Autocomplete( $document[0].querySelector('#address'), types: ['geocode'], componentRestrictions: country: 'us' );。感谢@kaiser 的提示。出于某种原因,maps api 抱怨我在使用angular.element(document.querySelector('#address')) 时传递的第一个参数不是输入,但一切都很好,结果很好。【参考方案3】:

我认为这不是使用 Angular 的正确方法。如果框架方法不存在,请不要创建它!这意味着框架(这里是 angular)不能以这种方式工作。

使用 Angular 你不应该像这样操作 DOM(jquery 方式),而应该使用 angular helper,比如

<div ng-show="isLoading" class="loader"></div>

或者创建您自己的指令(您自己的 DOM 组件)以便完全控制它。

顺便说一句,您可以在这里看到http://caniuse.com/#search=queryselector querySelector 得到很好的支持,因此可以安全使用。

【讨论】:

你说得对。 90% 以上的情况我认为我需要手动操作 DOM,我最终重构了代码以消除这种需要,最终代码更加简洁。【参考方案4】:

改进凯撒的回答:

var myEl = $document.find('#some-id');

别忘了在你的指令中注入$document

【讨论】:

如element.find:find() - Limited to lookups by tag name 的角度文档中所述,它不适用于 id。你还有一个额外的结束)【参考方案5】:

这对我很有效。

angular.forEach(element.find('div'), function(node)

  if(node.id == 'someid')
    //do something
  
  if(node.className == 'someclass')
    //do something
  
);

【讨论】:

元素未定义? angular.element.find 不是我在没有 JQuery 的情况下尝试你的功能。 请不要这样做。使用其他示例之一。这根本不使用哈希表查找优化。【参考方案6】:

您应该在控制器中注入 $document,并使用它来代替原始文档对象。

var myElement = angular.element($document[0].querySelector('#MyID'))

如果您不需要 jquery 样式元素包装,$document[0].querySelector('#MyID') 将为您提供 DOM 对象。

【讨论】:

你也可以直接引用window.document,而不是使用Angulars的$document服务开销。 当然可以,如果你不担心在你的单元测试中模拟 $document 我不清楚:我收到此警告:您应该使用 $document 服务而不是默认文档对象,但这是什么意思?关于它的任何文档?谢谢! @realnot 您可以从您的 javascript 中的任何位置访问 HTML DOM 文档对象。 w3schools.com/jsref/dom_obj_document.asp【参考方案7】:

也许我来得太晚了,但这会奏效:

var target = angular.element(appBusyIndicator);

注意,这里没有appBusyIndicator,是普通的ID值。

幕后发生的事情:(假设它应用在一个 div 上) (取自 angular.js 行号:2769 起...)

/////////////////////////////////////////////
function JQLite(element)      //element = div#appBusyIndicator
  if (element instanceof JQLite) 
    return element;
  

  var argIsString;

  if (isString(element)) 
    element = trim(element);
    argIsString = true;
  
  if (!(this instanceof JQLite)) 
    if (argIsString && element.charAt(0) != '<') 
      throw jqLiteMinErr('nosel', 'Looking up elements via selectors is not supported by jqLite! See: http://docs.angularjs.org/api/angular.element');
    
    return new JQLite(element);
  

如果页面上没有jQuery,默认使用jqLit​​e。该参数在内部被理解为一个 id 并返回相应的 jQuery 对象。

【讨论】:

我现在已经用 Angular 1.5.8 尝试过这个。普通 ID 返回空结果。 angular.element("#myId") 效果很好。 也许你的页面上有 jQuery?【参考方案8】:
var target = document.getElementById('appBusyIndicator');

等于

var target = $document[0].getElementById('appBusyIndicator');

【讨论】:

最好还是用第二个例子来保证你的依赖是显式的并且可以被mock吧? 应该是,但我想在 Angular 2+ 中,我们只是更多地依赖于打字稿功能。再也不用担心这些事情了:)【参考方案9】:

你可以使用$document访问元素($document需要注入)

var target = $document('#appBusyIndicator');
var target = $document('appBusyIndicator');

或使用角度元素,指定的元素可以访问为:

var targets = angular.element(document).find('div'); //array of all div
var targets = angular.element(document).find('p');
var target = angular.element(document).find('#appBusyIndicator');

【讨论】:

find() - 仅限于按标签名称查找 angular.element(document).find('.someClass');工作得很好。【参考方案10】:

如果有人使用 gulp,如果我们使用 document.getElementById() 会显示错误,并建议使用 $document.getElementById() 但它不起作用。

使用 -

$document[0].getElementById('id')

【讨论】:

为什么这里是角度注入数组?

以上是关于angular.element vs document.getElementById 或带有旋转(忙碌)控制的 jQuery 选择器的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Vue 中使用 angular.element()

如何使用 angular.element 而不是 jQuery?

Angular Element

使用 Angular 材质按钮时更新 Angular Element Ref 损坏

angular.element方法汇总

angular.element方法汇总