具有 tippy.js 的 Alpine 自定义工具提示指令暗模式

Alpine custom tooltip directive darkmode with tippy.js

我正在尝试实现 tippy.js 工具提示并根据本地存储值 darkMode 将主题更改为 AlpineJs custom directive.

下面的代码或多或少适用于最新位,如果我切换暗模式开关,这会更改 darkMode 的本地 localStorage 项目值,我需要刷新页面才能获得新的值。

如何在更改时获取值 (JSON.parse(localStorage.getItem('darkMode')))?

app.js

document.addEventListener('alpine:init', () => {
    Alpine.directive('tooltip', (el, {expression, modifiers}) => {
        tippy(el, {
            content: expression,
            placement: modifiers[0] ?? 'auto',
            theme: JSON.parse(localStorage.getItem('darkMode')) ?'blue':'light-border'
        })
    })
})

工具提示按钮

<button type="button" x-tooltip.left="I'm a tooltip">Hover me</button>

暗模式

<body class="font-sans antialiased h-full"
      x-data="{'darkMode': false}"
      x-init="
        darkMode = JSON.parse(localStorage.getItem('darkMode'));
        $watch('darkMode', value => localStorage.setItem('darkMode', JSON.stringify(value)))"
      x-cloak
>
<!-- some html -->
</body>

切换按钮

<input id="toggle" type="checkbox"  :value="darkMode" @change="darkMode = !darkMode"/>

如您所见,Tippy.js 实例和 localStorage 不是反应性的。创建 Tippy.js 实例后,如果我们想更改 属性,我们需要在每个元素上使用 _tippy property。为了让它更容易一点,我修改了工具提示指令以添加一个自定义 class tooltips,我们用它来循环每个 Tippy.js 实例。

document.addEventListener('alpine:init', () => {
  Alpine.directive('tooltip', (el, { expression, modifiers }) => {
    tippy(el, {
      content: expression,
      placement: modifiers[0] ?? 'auto',
      theme: JSON.parse(localStorage.getItem('darkMode')) ? 'blue' : 'light-border'
    })
    el.classList.add('tooltips')
  })
})

并且在 $watch 魔法中,我们使用 tooltips class 找到所有 Tippy.js 实例并在它们上设置新主题。

<body class="font-sans antialiased h-full"
      x-data="{'darkMode': false}"
      x-init="
        darkMode = JSON.parse(localStorage.getItem('darkMode'));
        $watch('darkMode', value => {
            localStorage.setItem('darkMode', JSON.stringify(value))
            Array.from(document.querySelectorAll('.tooltips')).forEach(
              el => el._tippy.setProps({ theme: value ? 'blue' : 'light-border' }))
        })"
      x-cloak
>
<!-- some html -->
</body>