从前面我们已验证配置自动化是可行的,接下来就实现元素选择,当然有了配置化,我们也是可以通过浏览器F12的调试工具去把元素xpath复制出来(ps:反正又不是不能用),但是这不是我们最终目的。
其实圈选效果如下:(通过鼠标选择元素)
其实看上去效果如F12调试模式一样:
都是移动鼠标去选取元素的位置。
实现
有上图可以把圈选功能的实现拆分以下几个步骤,
1、 监听鼠标移动
2、获取鼠标移到的元素
3、获取元素的位置、大小、边距等
4、绘制一个选择遮罩层
5、计算xpath(配置元素时,需要)
只要把这几个步骤实现,那么一个简单的圈选功能就ok了。
步骤1
监听鼠标移动,
body.addEventListener('mousemove', (e) => {
// 圈选逻辑
_onMove(e)
}, {
capture: true,
passive: true,
});
步骤2
/** 获取 鼠标移动 圈选 目标节点元素 */
function getTouchMouseTargetElement(e) {
if (e instanceof TouchEvent && e.touches) {
const changedTouch = e.changedTouches[0];
return document.elementFromPoint(changedTouch.clientX, changedTouch.clientY);
}
return e.target;
}
步骤3
/** 获取元素 内边距、外边距、宽高等元素数据 */
function getElementInfo(ele) {
const result = {};
const requiredValue = [
'border-top-width',
'border-right-width',
'border-bottom-width',
'border-left-width',
'margin-top',
'margin-right',
'margin-bottom',
'margin-left',
'padding-top',
'padding-right',
'padding-bottom',
'padding-left',
'z-index',
];
const computedStyle = getComputedStyle(ele);
requiredValue.forEach((item) => {
result[item] = parseFloat(computedStyle.getPropertyValue(item)) || 0;
});
const info = ele.getBoundingClientRect();
// FIXME: 简单兼容svg元素offsetWidth, offsetHeight 为空的场景
// TODO: 需要判断Svg元素的box-sizing,来决定其width,height是否需要减去padding, border
const width =
ele.offsetWidth === undefined
? info.width
: ele.offsetWidth -
result['border-left-width'] -
result['border-right-width'] -
result['padding-left'] -
result['padding-right'];
const height =
ele.offsetHeight === undefined
? info.height
: ele.offsetHeight -
result['border-top-width'] -
result['border-bottom-width'] -
result['padding-top'] -
result['padding-bottom'];
mixin(result, {
width,
height,
});
mixin(result, findPos(ele));
return result;
}
步骤4
绘制一个选择遮罩层。
/** 创建圈选蒙层 */
function addOverlay() { .... }
步骤5
function getXpath(ele, allId = false) {....}
最后
这个就是实现基于js实现圈选元素的大概思路。有兴趣的可以查看源码,常规的圈选功能可以,接下来就可以放在谷歌插件的上了,完成谷歌插件圈选元素,并设置配置参数。嘿嘿。