【问题标题】:How to use getElementsByClassName function in order to get the "send" button in Gmail compose page?如何使用 getElementsByClassName 函数来获取 Gmail 撰写页面中的“发送”按钮?
【发布时间】:2012-12-25 17:10:21
【问题描述】:

我正在使用 JavaScript 为 Chrome 浏览器编写 Gmail 扩展程序。 我正在尝试使用此代码从Compose 页面获取send 按钮元素:

SendButton  = document.getElementById('js_frame').contentDocument.getElementsByClassName('T-I J-J5-Ji Bq nS T-I-KE L3')[0];

但后来我不断收到一条消息说typeof SendButton is undefined

我该如何解决这个问题?

【问题讨论】:

  • 试试contentWindow.document 而不是contentDocument
  • 不幸的是 - 不工作......
  • @Teemu frameElement.contentWindow 是内容脚本中的 undefined。此外,所有现代浏览器(和 IE8+)都支持 contentDocument 属性。
  • @RobW 感谢您的信息,我想我也可以学会使用contentDocument :)。

标签: javascript google-chrome google-chrome-extension gmail


【解决方案1】:

您正在查看错误的文档。

Gmail 的 #js_frame 是一个不可见的框架,它负责非 UI 的东西(它的主体只包含 <script> 标签,仅供参考)。在您的 previous question 中,我已经展示了如何获得正确的参考:

  • document.getElementById('canvas_frame').contentDocument 如果存在
  • document 如果#canvas_frame 不存在,但js_frame 存在。 js_frame` 用于排除 Gmail 域中的非 Gmail 页面,例如帮助页面。

所以,你在得到doc2(见previous answer)后,需要查询那个文档上的元素:

// Paste declaration of doc2 from https://stackoverflow.com/a/14032326/938089
// And to get the button when available
if (doc2) {
    sendButton = doc2.getElementsByClassName('T-I J-J5-Ji Bq nS T-I-KE L3')[0];
}

【讨论】:

  • Gmail 会更改每个用户的类别,我认为每个撰写的电子邮件都会更改。例如,我的发送按钮是T-I J-J5-Ji aoO T-I-atl L3
  • @jjperezaguinaga 不,它没有:类名是硬编码的。我的答案中的选择器适用于旧撰写中的发送按钮(无论其悬停/焦点状态如何),您的选择器用于新撰写中的那个。
  • 我明白了,至少T-I J-J5-Ji 似乎与旧版本匹配。然后,您将如何为向后兼容的版本编写代码?我不喜欢您的回答,但如果开发人员偶然发现您的代码,他/她是否能够理解您想要实现的目标?
  • @jjperezaguinaga 在 Gmail 扩展程序的上下文中,是什么让名称 sendButton 难以理解?
  • 虽然变量名是合适的,但代码很难帮助未来的开发人员了解您想要实现的目标。如果它被缩小并且 var 名称被替换怎么办?代码应该是描述性的......如果非开发人员无法理解您要做什么,那么您可能会以某种方式对其进行改进。
【解决方案2】:

您不能依赖发送按钮的 class 或 id 属性,因为它们会在每次创建撰写字段时发生变化,甚至可能会因每个用户而变化。那么我们对按钮了解多少呢?

  • innerHTML 是“发送”(见脚注)
  • 它有一个值为“button”的角色属性
  • 它位于“撰写新邮件”容器中,该容器还具有其他标签,例如“发件人”、“收件人”(参见脚注 2)

有了这些信息,我们可以在原生 Javascript 中使用一个不错的 Xpath 查询来检索我们的按钮。

var xpath = '//div[@role="button" and text()="Send"]'
var query = document.evaluate(xpath, document, null, XPathResult.ORDERED_NODE_ITERATOR_TYPE, null);
var button = query.iterateNext();

如果您将库用作 jQuery,请随时将其与 css 选择器 [role="button"] 和上一个答案中提供的过滤器功能一起使用。

这可以通过将表信息附加为父级来改进,但这应该足够了(您可以在Developer Mozilla Introduction to Xpath 中阅读更多相关信息)。希望答案能提供良好的性能。

更新: 似乎 Gmail 确实在某些方面坚持使用某些类(T-I J-J5-Ji 之类的类似乎在新旧版本之间共享)。但是,我不会使用它,如果其他开发人员偶然发现该类并且您仅通过该类获得按钮,那么他或她将无法理解您所获得的内容,特别是如果没有 cmets 和一个糟糕的变量名被使用了。

实际检索答案的解决方案使用类似于 div > div > div > div > table div 的 CSS 查询选择器;出于同样的原因,我也不会使用它。另外,它让我想起了一个糟糕的描述Regular Expression。您不仅是为自己编写代码,也是为自己可能对项目一无所知的未来编写代码。


脚注:或相当于用户的语言。我不确定是否所有用户都有英文版的 Gmail,但我不会做出这样的假设。如果我是你,我会创建一个字典,其中包含“发送”的最常见关键字的语言环境,并通过其中的大多数迭代评估。您可以迭代的语言数量可能仅限于语言 Gmail support

脚注 2:实际上,当您按下“撰写”时,它会添加标签“发件人”和“收件人”,但如果您不立即填写它们,它们就会消失,只显示一些带有 innerHTML 的 div “收件人”和“主题”

【讨论】:

  • 您建议的类名不够足够独特。这些是用于设置按钮样式的通用类名。此外,您的选择器仅适用于英文版的 Gmail。故意忽视非英语用户是一个坏举动。
  • 你在说什么类名?我根本没有使用课程,因为我不确定 Gmail 是否会在此基础上改变它。正如我在脚注中所说:`如果我是你,我会创建一个字典,其中包含“发送”的最常见关键字的语言环境,并遍历其中的大多数。应该不超过10`
  • 你为什么忽略下一个文本? ...“但是,我不会使用它”。我在回答中写的第一件事是“您不能依赖发送按钮的类或 id 属性”。在查看了其他解决方案并与我自己的 Gmail 数据进行比较后,我得出了这个结论,其中类别不同。同意语言,但我们现在正在假设该应用程序是国际化的还是仅适用于说英语的人。
  • “似乎 Gmail 确实在某些事情上坚持使用某些类(如 T-I J-J5-Ji 之类的类......”表明该类名称可用于选择正确的按钮。您的建议是每次添加/支持新语言时都需要更新应用程序(此外,Gmail 支持 56 种语言(截至撰写时),那么为什么将您的应用程序限制为仅 10 种语言?)。
  • 我同意将字典限制为 10 似乎很愚蠢。在考虑世界上使用最多的语言时,这个数字似乎是正确的,让我更新一下。哦,我对课程的评论是在分析了其他答案以及我们之前在 cmets 中的讨论之后;我补充说,以确保当 OP 读取其他答案和 cmets 时,他可以在接近他/她的解决方案时获得所有信息。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-02-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多