138 lines
2.4 KiB
JavaScript
138 lines
2.4 KiB
JavaScript
import {
|
|
ref,
|
|
computed,
|
|
watch,
|
|
onMounted,
|
|
onBeforeUnmount,
|
|
unref
|
|
} from "vue";
|
|
|
|
|
|
export function useHighlight(target, options = {}) {
|
|
const rect = ref(null);
|
|
const padding = options.padding ?? 8;
|
|
|
|
let resizeObserver = null;
|
|
|
|
function resolveTarget() {
|
|
const value = unref(target);
|
|
|
|
if (!value)
|
|
return null;
|
|
|
|
if (typeof value === "function")
|
|
return value();
|
|
|
|
if (typeof value === "string")
|
|
return document.querySelector(value);
|
|
|
|
return value;
|
|
}
|
|
|
|
|
|
function update() {
|
|
const element = resolveTarget();
|
|
|
|
if (!element) {
|
|
rect.value = null;
|
|
return;
|
|
}
|
|
|
|
const box = element.getBoundingClientRect();
|
|
|
|
rect.value = {
|
|
top: box.top - padding,
|
|
left: box.left - padding,
|
|
width: box.width + padding * 2,
|
|
height: box.height + padding * 2,
|
|
bottom:
|
|
box.bottom + padding,
|
|
right:
|
|
box.right + padding
|
|
};
|
|
|
|
}
|
|
|
|
function observe() {
|
|
const element = resolveTarget();
|
|
|
|
if (!element)
|
|
return;
|
|
|
|
resizeObserver?.disconnect();
|
|
resizeObserver = new ResizeObserver(() => {
|
|
update();
|
|
});
|
|
|
|
resizeObserver.observe(element);
|
|
}
|
|
|
|
|
|
const style = computed(() => {
|
|
|
|
if (!rect.value)
|
|
return {};
|
|
|
|
return {
|
|
top:
|
|
`${rect.value.top}px`,
|
|
left:
|
|
`${rect.value.left}px`,
|
|
width:
|
|
`${rect.value.width}px`,
|
|
height:
|
|
`${rect.value.height}px`
|
|
};
|
|
});
|
|
|
|
watch(
|
|
() => unref(target),
|
|
() => {
|
|
update();
|
|
observe();
|
|
},
|
|
{
|
|
immediate: true
|
|
}
|
|
);
|
|
|
|
onMounted(() => {
|
|
window.addEventListener(
|
|
"resize",
|
|
update
|
|
);
|
|
|
|
window.addEventListener(
|
|
"scroll",
|
|
update,
|
|
true
|
|
);
|
|
|
|
update();
|
|
observe();
|
|
});
|
|
|
|
onBeforeUnmount(() => {
|
|
resizeObserver?.disconnect();
|
|
|
|
window.removeEventListener(
|
|
"resize",
|
|
update
|
|
);
|
|
|
|
window.removeEventListener(
|
|
"scroll",
|
|
update,
|
|
true
|
|
);
|
|
});
|
|
|
|
|
|
|
|
return {
|
|
rect,
|
|
style,
|
|
update
|
|
};
|
|
|
|
} |