使用CSS构建自定义工具提示指令
#javascript #css #vue #tutorials

the previous post中,我们探索了如何在VUE中构建可访问的工具提示组件。但是,为简单的工具提示创建元素可能是过分的。因此,在帖子中,我们将使用自定义指令和CSS探索另一种使用工具提示增强组件的方法。

目录


什么是VUE指令?

vue组件是应用程序的完全独立实体,但指令更像是装饰性和较轻的代码块,我们可以将其附加到元素上,以增强其在浏览器上的功能和外观。它使我们可以直接在相关的DOM元素中添加副作用或额外的修改。 VUE指令的一些常见示例是v-ifv-for等,我们在任何VUE应用程序中广泛使用。

除了内置指令外,VUE还为我们提供了用于创建自定义指令的指令API。我们可以将自定义指令定义为适当的生命周期挂钩的对象或允许我们与为组件创建的DOM元素实例进行交互的函数。

由于我们的工具提示主要是要使用类和CSS,并且不太可能在组件更新和MONT之间进行更改,因此我们将使用功能方法。让我们开始吧?

先决条件

您需要拥有一个工作的VUE应用程序(请参阅the official guide for setting up a new Vue project with Vite)和对CSS的基本了解,然后我们可以继续创建我们的Tooltip指令。

创建工具提示指令

为了制作自定义指令,我们首先在应用程序源文件夹中创建一个新的/directives/tooltip.js文件,其中包含以下代码:

export function TooltipDirective(el, binding) {
}

TooltipDirective函数接受两个参数-DOM元素实例el和一个binding对象,该对象包含在组件上使用时传递给指令和其他修饰符的值。对于我们的工具提示,我们希望binding.value是具有以下属性的对象:

type TooltipOptions{
  text: string;
  position: 'top' | 'bottom' | 'left' | 'right';
}

我们可以使用binding.value在类和data-tooltip属性的帮助下设置工具提示文本和位置。我们还在目标元素上添加另一个类-with-tooltip-,如下:

export function TooltipDirective(el, binding) {
    el.setAttribute('data-tooltip', binding.value.text);
    el.classList.add('with-tooltip');

    const position = binding.value.position;
    el.classList.add(`tooltip--${position}`);
}

安装(和更新)组件后,VUE将触发此功能,并添加带有工具提示内容的新属性data-tooltip,并在生成的DOM元素上添加两个其他类-with-tooltiptooltip--[position],可以使用。但是,在我们使用工具提示之前,我们需要在应用程序中注册我们的指令。我们将在下一部分中执行此操作。

在应用程序中注册和使用工具提示

main.js中,我们需要使用app.directive方法导入TooltipDirective并将其注册为app实例,如下:

import { createApp } from 'vue'
import App from './App.vue'
import { TooltipDirective } from './directives/TooltipDirective'

const app = createApp(App)

app.directive('tooltip', TooltipDirective )

app.mount('#app')

vue将使用v-前缀创建相关指令。现在,我们可以在任何元素中使用我们的工具提示指令,名称为v-tooltip如下:

<button v-tooltip="{ text: 'I am the top tooltip', position: 'top' }">Top</button>

在浏览器中,我们将看到具有以下HTML的button元素:

<button data-tooltip="Im the top tooltip" class="with-tooltip tooltip--top">Top</button>

但是,悬停或关注元素时不会显示任何工具提示。我们需要在我们的工具提示类中添加一些CSS,我们将下一步进行。

用CSS添加工具提示效果

我们在应用程序中添加了一个新的assets/tooltip.css文件,并将其导入到我们的main.js文件中,以将其包含在我们的应用程序中:

/**main.js */
import './assets/tooltip.css';

tooltip.css文件中,我们添加以下CSS规则以样式的工具提示:

.with-tooltip {
    position: relative;
}

.with-tooltip::before {
    content: attr(data-tooltip);
    opacity: 0;
    position: absolute;
    transition: opacity 2s;
    color: #ffffff;
    text-align: center;
    padding: 5px;
    border-radius: 2px;
    min-width: 120px;
    background: #5e5d5d;
    pointer-events: none;
    z-index: 1;
}

.with-tooltip::after {
    transition: opacity 2s;
    opacity: 0;
    content: "";
    border-width: 5px;
    border-style: solid;
    border-color: #5e5d5d transparent transparent transparent;
    position: absolute;
    z-index: 1;
    pointer-events: none;
}

在这里,我们将目标元素的位置设置为relative,以使工具提示的定位与之对齐。对于工具提示,我们使用::before伪元素显示工具提示文本和::after伪元素以显示工具提示箭头。我们还设置了一些CSS属性以确保工具提示的外观,例如以下内容:

  • opacity: 0到两个元素都默认隐藏它们,
  • z-index: 1确保工具提示始终处于其他元素之上,
  • pointer-events: none要确保浏览器不会捕获任何事件,包括悬停并专注于::before::after元素。
  • content: attr(data-tooltip)使用attr()::before中的工具提示文本设置为data-tooltip属性的值。
  • content: ""清空::after元素。

当用户徘徊或关注目标元素时,我们还将opacity: 1设置为两个元素,如下:

.with-tooltip:hover::before, 
.with-tooltip:hover::after, 
.with-tooltip:focus::before, 
.with-tooltip:focus::after {
    opacity: 1;
}

最后,我们将使用::before::after tooltip--toptooltip--bottomtooltip--lefttooltip--right::before::after伪元素来设置工具提示和箭头的位置,具体取决于工具提示的位置。 >


.tooltip--top::before {
    inset-block-end: 120%;
    inset-inline-start: 50%;
    margin-inline-start: -60px;
}

.tooltip--bottom::before {
    inset-block-start: 120%;
    inset-inline-start: 50%;
    margin-inline-start: -60px;
}

.tooltip--left::before {
    inset-block-end: 0%;
    inset-inline-end: 120%;
    min-height: 100%;
}

.tooltip--right::before {
    inset-block-end: 0%;
    inset-inline-start: 120%;
    min-height: 100%;
}

.tooltip--left::after {
    inset-block-start: 25%;
    inset-inline-start: -20%;
    border-color: transparent transparent transparent #5e5d5d;
}

.tooltip--right::after {
    inset-block-start: 25%;
    inset-inline-end: -20%;
    border-color: transparent #5e5d5d transparent transparent;
}

.tooltip--top::after {
    inset-block-start: -20%;
    inset-inline-start: 40%;
    border-color: #5e5d5d transparent transparent  transparent;
}

.tooltip--bottom::after {
    inset-block-end: -20%;
    inset-inline-start: 40%;
    border-color: transparent transparent #5e5d5d transparent;
}

注意,我们使用inset-blockinset-inline css逻辑属性将工具提示和箭头与目标元素对齐。请参阅previous tutorial,以了解有关逻辑属性以及我们如何创建箭头提示的更多信息。

我们的按钮元素在悬停或专注于它时将具有一个工具提示,如下面的屏幕截图所示:

Tooltip displays on hovering

足够直接。现在,我们可以通过更改传递给指令的值的position属性来解决工具提示的位置。但是,每次我们使用该指令时,都可以编写position属性是很乏味的。为了使其更加清洁,更有条理,我们可以使用指令修饰符,我们将看到下一步的方法。

使用指令修饰符作为位置

我们可以将位置定义为指令的修饰符,用语法v-tooltip.[position]表示,就像以下示例:

    <button v-tooltip.top="'I am the top tooltip'">Top</button>

vue将将修饰符转换为binding.modifiers对象,每个属性是修饰符的名称,其值为true。在上面的示例中,modifiers对象将为{ top: true }

在我们的TooltipDirective.js中,我们可以实现一个函数以基于binding.modifiers对象返回合适的位置类,如下:

function getPositionClass(modifiers) {
    if (modifiers.top) {
        return 'top';
    } else if (modifiers.bottom) {
        return 'bottom';
    } else if (modifiers.left) {
        return 'left';
    } else if (modifiers.right) {
        return 'right';
    } 

    return 'top';
}

,我们可以像以下代码中使用getPositionClass() TooltipDirective.js使用:

  el.setAttribute("data-tooltip", binding.value?.text || binding.value);
  el.classList.add("with-tooltip");

  const position = binding.value.position || getPositionClass(binding.modifiers);
  el.classList.add(`tooltip--${position}`);

请注意,我们现在从binding.value.textbinding.value中获得文本值,以使用户可以将文本值作为对象或字符串传递。

就是这样。我们可以使用工具提示指令来支持修饰符,如下示例:

    <button v-tooltip.top="'I am the top tooltip'">Top</button>
    <button v-tooltip.bottom="'I am the bottom tooltip'">Bottom</button>
    <button v-tooltip.right="'I am the right tooltip'">Right</button>
    <button v-tooltip.left="'I am the left tooltip'">Left</button>

结果将与the previous approach of creating a tooltip as a component

一样

Tooltip displays on hovering

可访问性如何?我们的指令免费提供,而无需aria-describedbyrole:tooltip属性,因为工具提示文本在同一元素上。由于我们将其放在::before伪元素上,因此屏幕读取器将能够按以下顺序读取:工具提示文本,目标元素文本和目标元素的角色。这不是很棒吗?


概括

自定义指令是在使用组件时,可以在低级别创建可重复使用的附加组件的重要功能。另外,通过使用适当的CSS元素选择器,我们可以添加额外的UI功能,例如元素的文本工具提示,代码较少。

但是,使用工具提示组件方法可以成为更复杂的方案的优势,在这种情况下,您想显示一个不仅仅是文本的工具提示,例如段落或带有一些额外样式的图像。在这种情况下,我建议将这两种方法,简单工具提示的指令和更复杂的工具组件组合起来。

ð如果您想赶上我有时候,请在Twitter上关注我| Facebook

ð通过我的新书Learning Vue了解Vue。早期版本现在可以使用!

喜欢这篇文章还是发现它有帮助?分享ðð¼ð