写一个获取元素 xpath 的 chrome 插件
需求
哈哈哈,本人还是很暖的,开会的时候大家一起聊天,聊到了测试是怎么做测试的。
然后测试给我们演示了一下,每次编写测试用例,都要通过 chrome 获
取元素的 xpath,很麻烦。
我就多嘴问了一句,为什么不自己弄一个自动获取 xpath 然后读成想要格式的插件呢?
测试:我不会,没研究过。
老板:那你来帮他实现一个吧。***,你把需求理顺了放进 tapd 。
我:反手给我自己一个大嘴巴子!
梳理
好在之前对 chrome 插件也略有所闻,嘿嘿。
先想想需求,鼠标点击一个元素的时候,自动读取该元素的 xpath,放到
另一个页面,然后提示:auto saved
ok,开搞。
目录结构
对于 chrome 插件开发者而言,chrome 做了最大的努力使得插件的开发简单而高效。
固定了项目的结构,开发者可以自由的将精力和时间放置在真正的代码和逻辑层面。
比如我的项目结构,就非常简单。
├── background.html
├── background.js
├── icon.png
├── manifest.json
└── xpath.js
大概说一下:
- manifest.json 是必须的,记录这个插件相关的信息和配置
- background.html 常驻页面,生命周期最长,随浏览器打开而打开,随浏览器关闭而关闭,所以把需要一直运行的、启动就运行的、全局的代码放在background里面
- icon 图标,插件的图标
- xpath 自己的逻辑
内容很多很长,这里不细说了,详细了解请点击
代码
// xpath.js
(function (doc) {
var xh = {}
xh.elementsShareFamily = function (primaryEl, siblingEl) {
var p = primaryEl, s = siblingEl;
return (p.tagName === s.tagName &&
(!p.id || p.id === s.id));
};
xh.getElementIndex = function (el) {
var index = 1;
var sib;
for (sib = el.previousSibling; sib; sib = sib.previousSibling) {
if (sib.nodeType === Node.ELEMENT_NODE && xh.elementsShareFamily(el, sib)) {
index++;
}
}
if (index > 1) {
return index;
}
for (sib = el.nextSibling; sib; sib = sib.nextSibling) {
if (sib.nodeType === Node.ELEMENT_NODE && xh.elementsShareFamily(el, sib)) {
return 1;
}
}
return 0;
};
xh.makeQueryForElement = function (el) {
var query = '';
for (; el && el.nodeType === Node.ELEMENT_NODE; el = el.parentNode) {
var component = el.tagName.toLowerCase();
var index = xh.getElementIndex(el);
if (index >= 1) {
component += '[' + index + ']';
}
query = '/' + component + query;
}
return query;
};
doc.addEventListener('dblclick', (e) => {
var target = e.target,
data = xh.makeQueryForElement(target) + '\r\n';
chrome.extension.sendRequest({ data }, function (response) {
alert(response.farewell);
});
})
})(document)
// background.js
chrome.extension.onRequest.addListener(
function (request, sender, sendResponse) {
// var content = document.getElementById('app').innerText
document.getElementById('app').innerText += request.data
sendResponse({ farewell: "auto saved" });
});
chrome.browserAction.onClicked.addListener(
function () {
if (chrome.runtime.openOptionsPage) {
chrome.runtime.openOptionsPage();
} else {
window.open(chrome.runtime.getURL('background.html'));
}
}
);
// bacground.html
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="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>
<div id=app></div>
<script src="background.js"></script>
</body>
</html>
{
"name": "xpath2.0",
"description": "Get the current element xpath",
"version": "1.0",
"permissions": [
"activeTab","tabs",
"http://*/*",
"https://*/*"
],
"browser_action": {
"default_title": "Get the current element xpath.",
"default_icon": "icon.png"
},
"background": {
"scripts": [
"background.js"
]
},
"options_page": "background.html",
"content_scripts": [
{
"matches": [
"http://*/*",
"https://*/*"
],
"js": [
"xpath.js"
]
}
],
"manifest_version": 2
}