简体   繁体   English

Vue 3 自定义指令

[英]Vue 3 custom directive

I have tooltip custom directive.我有工具提示自定义指令。 Is working as I expected, only when I use beforeUpdate hooks, not working on update hooks.仅在我使用 beforeUpdate 挂钩时按预期工作,而不是在更新挂钩上工作。 The problem is that is creating multiple element when I hovering on h1 where I'm using mouseover and mouseleve.问题是,当我将鼠标悬停在使用 mouseover 和 mouseleve 的 h1 上时,会创建多个元素。

There is some way that it will not create multiple elements?有什么方法不会创建多个元素?

As I'm beginner on custom directive I'll appreciate any of your help.由于我是自定义指令的初学者,我将不胜感激您的任何帮助。

<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工具提示.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 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>

By adding the following code, it fixed the issue通过添加以下代码,它解决了问题

const hasTooltipClass = el.querySelector(".tooltip") as HTMLDivElement

   if (!hasTooltipClass) {
      tooltipDiv.classList.add("tooltip")
      tooltipDiv.innerHTML = value
      el.appendChild(tooltipDiv)
    }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM