I have developed a custom tooltip directive that is functioning correctly when using the beforeUpdate hooks, but not working with update hooks. The issue arises when multiple elements are created upon hovering over the h1 element, which triggers mouseover and mouseleave events.
Is there a way to prevent the creation of multiple elements in this scenario?
Being a beginner in custom directives, I would greatly appreciate any help or guidance you can provide.
<div class="tooltip"><h1>Hello world from html</h1></div>
<div class="tooltip"><h1>Hello world from html</h1></div>
<div class="tooltip"><h1>Hello world from html</h1></div>
<div class="tooltip"><h1>Hello world from html</h1></div>
tooltip.ts
const updateTooltip = (el: HTMLElement, value: DirectiveBinding["value"], modifiers: DirectiveBinding["modifiers"], arg: DirectiveBinding["arg"], vnode: VNode): void => {
if (!value.text) {
el.classList.remove("tooltip-parent")
}
if (value.text) {
tooltipDiv.classList.add("tooltip")
tooltipDiv.innerHTML = value.text
el.appendChild(tooltipDiv)
}
if (value.displayArrow) {
el.style.setProperty(Tooltip.arrowDisplay, "inline")
argTooltip?.style.setProperty(Tooltip.arrowDisplay, "inline")
}
tooltipPlacement(value, el, argTooltip, argTooltipDiv)
}
export const tooltip = {
mounted: (el: HTMLElement, { value, modifiers, arg }: DirectiveBinding): void => {
if (typeof value === "object" && value.text) {
el.classList.add("tooltip-parent")
}
if (typeof value === "string" && value) {
el.classList.add("tooltip-parent")
}
updateTooltip(el, value, modifiers, arg)
},
beforeUpdate: (el: HTMLElement, { value, modifiers, arg }: DirectiveBinding): void => {
updateTooltip(el, value, modifiers, arg)
},
}
tooltipPlacement.ts
export const tooltipPlacement = (value: DirectiveBinding["value"], el: HTMLElement, argTooltip: HTMLElement, argTooltipDiv: HTMLDivElement) => {
if (value.theme) {
for (const [key, val] of Object.entries(value.theme) as [string, any][]) {
switch (key) {
case "hide":
watch(
() => val,
() => {
if (val) {
argTooltip?.style.setProperty(Tooltip.opacity, "0")
argTooltip?.style.setProperty(Tooltip.visibility, "hidden")
/**** arrow ****/
argTooltip?.style.setProperty(Tooltip.arrowOpacity, "0")
argTooltip?.style.setProperty(Tooltip.arrowVisibility, "hidden")
}
if (!val) {
console.log("show")
argTooltip?.style.setProperty(Tooltip.opacity, "1")
argTooltip?.style.setProperty(Tooltip.visibility, "visible")
/**** arrow ****/
argTooltip?.style.setProperty(Tooltip.arrowOpacity, "1")
argTooltip?.style.setProperty(Tooltip.arrowVisibility, "visible")
}
},
{ immediate: true },
)
break
default:
break
}
}
}
}
Template
<template>
<div>
<div class="p-6 centered flex-col space-y-6">
{{ !!hideTooltip }}
<h1>Tooltip</h1>
<br />
<p v-tooltip:actions.arrow="tooltipContent(html, tooltipTheme, true)" class="border w-40 h-20 text-center">hello world</p>
</div>
<div class="p-6 centered flex-col space-y-6">
<h1 class="h-20" @mouseover="hideTooltip = false" @mouseleave="hideTooltip = true">Actions</h1>
<br />
<p class="h-60 border px-4 actions">Test of args tooltip</p>
<button class="mt-10 p-6" @click="hideTooltip = !hideTooltip">{{ hideTooltip ? "Show Tooltip" : "Hide" }}</button>
</div>
</div>
</template>
Script
<script lang="ts" setup>
import { tooltipContent, ThemeOptions } from "../directives/tooltip"
import { ref, computed } from "vue"
const hideTooltip = ref(true)
const html = ref("<h1>Hello world from html</h1>")
const tooltipTheme = computed((): ThemeOptions => {
return {
placement: "leftTop",
argTxt: html.value,
hide: !!hideTooltip.value,
maxWidth: "300px",
}
})
</script>