写一个获取元素xpath的chrome插件

如题所述

第1个回答  2024-09-04
需求来源

上次开每周例会的时候,大家一起嗨皮的聊天,聊到了测试是怎么做测试的。

然后测试就给我们演示了一下,每次编写测试用例,都要通过chrome获取元素的xpath,很麻烦。

我就多嘴问了一句,为什么不自己弄一个自动获取xpath然后读成想要格式的浏览器插件呢?

测试:我不会,没研究过。老板:那你来帮他实现一个吧。***,你把需求理顺了放进tapd。我:。。。

好在之前对chrome插件也略有所闻,嘿嘿。

需求梳理

通过沟通和需求的梳理,简单总结了一下要实现的逻辑:

鼠标双击一个元素的时候,自动读取该元素的xpath

然后将读取的结果放到另一个页面中展示,以方便用户直接选取复制

成功以后提示用户“autosaved”

为什么要实现chrome插件呢?

因为chrome插件支持几乎所有的webkit内核的浏览器,例如360、搜狗、QQ等,使用起来非常方便

另外,对于chrome插件开发者而言,chrome做了最大的努力使得插件的开发简单而高效。

ok,开搞。

目录结构

chrome插件的项目结构十分简单,一个插件目录结构可以包含以下几个文件夹,使目录看起来非常像一个网站目录

├──html├──js├──img├──manifest.json└──style

因此开发者可以自由的将精力和时间放置在真正的代码和逻辑层面,而不必关注额外的事情

但是插件目录没有严格的标准,即便你只有一个manifest.json也是可以的,因为只有这个文件使必须的,其他都是可选择的,比如我要开发的插件十分简单,因此项目结构也做的非常简单。

├──background.html├──background.js├──icon.png├──manifest.json└──xpath.js

大概说一下:

manifest.json是必须的文件,必须放在根目录下,用来记录这个插件相关的信息和配置

background.html常驻页面,生命周期最长,随浏览器打开而打开,随浏览器关闭而关闭,所以把需要一直运行的、启动就运行的、全局的代码放在background里面

background.js常驻页面的js逻辑

icon插件安装到chrome后在浏览器右上角显示的插件图标

xpath.js插件要实现的需求具体的逻辑代码

manifest.json简介

请注意,manifest.json是插件的入口文件,因此它是必须的文件,这个文件内配置了许多参数

其中有些必须参数如下:

"manifest_version":2,//manifest文件的版本,推荐值是2或者3"name":"myplus",//插件的名称"version":"1.0.0",//插件的版本

推荐的参数:

"default_locale":"zh_CN",//默认语言"description":"我的第一个扩展插件",//插件的描述"icons":{"16":"img/icon.png","48":"img/icon.png","128":"img/icon.png"},//图标"permissions":[//声明插件所需要的权限"contextMenus",//右键菜单"tabs",//标签"notifications",//通知"webRequest",//web请求"webRequestBlocking","storage",//插件本地存储"http://*/*",//可以通过executeScript或者insertCSS访问的网站"https://*/*"//可以通过executeScript或者insertCSS访问的网站"cookies",//cookie信息]

其他的参数,我挑选了一些放在这里

"background":{//常驻的后台JS或后台页面//第一种方式"page":"background.html"//通过指定html文件//第二种方式"scripts":[//通过指定的js文件,PS:如果指定了这种方式,会自动生成一个html"scripts/background.js",]},//browser_action和page_action只能添加一个"browser_action":{//浏览器级别行为,所有页面均生效"default_icon":"images/16x16.png",//图标的图片"default_title":"myplus",//鼠标移到图标显示的文字"default_popup":"html/popup.html"//单击图标后弹窗页面},"page_action":{//页面级别的行为,只在特定页面下生效"default_icon":{"24":"images/custom/24x24.png","38":"images/custom/38x38.png"},"default_popup":"html/popup.html","default_title":"myplus"},"content_scripts":[//定义对页面内容进行操作的脚本{"js":["js/insert.js"],//多个文件会按顺序加载"css":["css/insert.css"],//同上"matches":["<all_urls>"],//匹配所有地址"run_at":"document_start"//可选的值还有为"document_end",默认为"document_idle"}],"devtools_page":"devtools.html"//devtools页面入口,只能是HTML文件

manifest参数内容很多很长,而且版本2和3还有些不同,所以这里我就不细说了,详细了解请点击

background.html

这个页面用于展示xpath的结果,所有的xpath结果都会以换行的方式展示在#app这个div中

<!doctypehtml><html><head><metacharset="UTF-8"><metaname="viewport"content="width=device-width,initial-scale=1.0"><title>Document</title><style>#app{margin:0;padding:0;font-size:12px;background-color:#fff;color:silver;padding:10px;}</style></head><body><divid=app></div><scriptsrc="background.js"></script></body></html>

下面开始进入正题了

代码获取元素的xpath

首先,我们要完成获取元素的xpath的逻辑,这部分是我们插件最主要的逻辑,放在xpath.js中。

那么什么是元素的xpath呢?我们打开浏览器的开发者模式,选中一个元素,鼠标右击,会弹出一个对话框如下:

这里我们能找到一个正常的xpath是这样的:

//*[@id="juejin-web-editor"]/div[2]/div/header/div[2]/button

或者一个全路径的xpath是这样的:

/html/body/div/div[2]/div/header/div[1]

所以xpath本质上就是遍历某个元素的父节点和兄弟节点,然后拼成节点层级的路径,这个元素在兄弟节点中的位置,用[n]来表示

所以我们先来写一个查找元素在兄弟元素位置中的函数,这个函数返回元素在兄弟中的位置n,注意的n只的是相同的标签,比如:

<headerclass="headereditor-header"><divclass="left-box"></div><inputclass="title-input"><divclass="right-box"></div></header>

在上面这段代码中

.left-box的xpath是/header/div[1]

.title-input的xpath是/header/input

.right-box的xpath是/header/div[2]

所以我们得出获取n的方法:

functionelementsShareFamily(pre,sib){//判断是否是相同的tagnamereturn(pre.tagName===sib.tagName&&(!pre.id||pre.id===sib.id));}functiongetElementIndex(el){varsib,index=1;//默认为1for(sib=el.previousSibling;sib;sib=sib.previousSibling){//前面有兄弟元素且tagname相同if(sib.nodeType===Node.ELEMENT_NODE&&elementsShareFamily(el,sib)){index++;}}if(index>1){returnindex;}for(sib=el.nextSibling;sib;sib=sib.nextSibling){//后面有兄弟元素且tagname相同if(sib.nodeType===Node.ELEMENT_NODE&&elementsShareFamily(el,sib)){return1}}return0;}

我们已经成功拿到了n,下面要获取元素的祖先元素以及祖先元素的n:

functionmakeQueryForElement(el){varquery='';for(;el&&el.nodeType===Node.ELEMENT_NODE;el=el.parentNode){varcomponent=el.tagName.toLowerCase();varindex=getElementIndex(el);if(index>=1){component+='['+index+']';}query='/'+component+query;}returnquery;};将xpath传递给background

上面的query就是/header/div[1]这种形式的xpath,到这里我们已经实现了获取元素的xpath,接下来要做的就是把结果传递到background.html中,并在当前页面给用户一个提示autosaved

这里跨页面通信,我们使用的是谷歌拓展的一个API,叫做extension,这个API有用于发送和接收信息的方法:

chrome.extension.sendRequest(obj,callBack)

chrome.extension.onRequest.addListener(function)

我们获取了完整的xpath后,用sendRequest方法将它发送给background.js

├──html├──js├──img├──manifest.json└──style0接受xpath数据并显示在页面

发送以后,我们需要在background.js中接受这个数据

├──html├──js├──img├──manifest.json└──style1

到这里我们的主要逻辑就写完了,然后来补充下manifest.json

manifest.json

在manifest.json写好必须的数据就可以了

├──html├──js├──img├──manifest.json└──style2打包和发布

写好的插件可以直接按照文件夹的形式拖动到chrome://extensions/下

安装以后就会在扩展管理中列出来

如果想发布的话,需要到https://chrome.google.com/webstore/developer/dashboard/上,访问这里需要登录谷歌账号

然后缴纳5美元的注册费

成功注册为开发者之后,就可以上传打包后的.zip文件包了

上传之后可以在“开发者信息中心”查看,我就不多赘述了。

作者:晴天同学

logo设计

创造品牌价值

¥500元起

APP开发

量身定制,源码交付

¥2000元起

商标注册

一个好品牌从商标开始

¥1480元起

公司注册

注册公司全程代办

¥0元起

    官方电话官方服务
      官方网站八戒财税知识产权八戒服务商企业需求数字市场

相关了解……

你可能感兴趣的内容

大家正在搜

本站内容来自于网友发表,不代表本站立场,仅表示其个人看法,不对其真实性、正确性、有效性作任何的担保
相关事宜请发邮件给我们
© 非常风气网