教程:加载 js-confetti

学习如何使用 Nuxt Scripts 模块加载 js-confetti 脚本。

介绍

在本教程中,您将学习如何使用 Nuxt Scripts 模块加载 js-confetti 脚本。

您将了解以下内容:

  • 什么是 useScriptNpm 注册脚本。
  • 如何使用它来加载 js-confetti 脚本。
  • 为加载的脚本添加类型。
  • 使用代理函数调用脚本。

关于 useScriptNpm 的背景

要加载脚本,我们将使用 useScriptNpm

这是一个注册脚本,是建立在 useScript 组合式函数之上的受支持第三方集成,允许您从 NPM 加载脚本。

在使用 NPM 文件时,通常会将它们作为 node_module 依赖项包含在 package.json 文件中。然而,优化这些脚本的加载可能很困难,通常需要从单独的代码块动态导入模块,并且只在需要时加载。它还会降低构建速度,因为模块需要被转译。

useScriptNpm 注册脚本抽象了此过程,允许您用一行代码加载那些被导出为可立即调用函数的脚本。

在许多情况下,将脚本作为 package.json 文件中的依赖项可能仍更合理,但对于不常用或对应用不关键的脚本,这可以是一个很好的替代方案。

最开始我们可以将使用该脚本视为 useHead 组合式函数的替代。您可以在以下代码示例中看到抽象层的比较。

useScriptNpm({
  packageName: 'js-confetti',
  file: 'dist/js-confetti.browser.js',
  version: '0.12.0',
})

加载脚本

在您的某个组件中,您将需要加载该脚本。您可以通过使用 useScriptNpm 注册脚本来实现。

app.vue
<script setup lang="ts">
useScriptNpm({
  packageName: 'js-confetti',
  file: 'dist/js-confetti.browser.js',
  version: '0.12.0',
})
</script>

如果检查浏览器请求,您应该会看到脚本被加载。

解析第三方脚本 API

脚本加载完成后,您可以在组件中使用它。为此,我们需要告诉底层 API 如何使用该脚本,为此可以利用 use 函数。

该函数只会在客户端调用,用于解析第三方脚本。

app.vue
<script setup lang="ts">
useScriptNpm({
  packageName: 'js-confetti',
  file: 'dist/js-confetti.browser.js',
  version: '0.12.0',
  scriptOptions: {
    // 告诉 useScript 如何解析第三方脚本
    use() {
      return { JSConfetti: window.JSConfetti }
    },
  },
})
</script>

使用第三方脚本 API

既然我们有了解析第三方脚本 API 的方法,就可以开始使用它了。

js-confetti 库要求每次使用时都要实例化一个 JSConfetti 类的新实例,最兼容的处理方式是显式等待脚本加载完成。

但是,如果您喜欢更便捷的 API,也可以使用代理函数。需要注意的是,当在页面之间切换时,这种方式会失效,因为需要在页面间调用 new window.JSConfetti()

<script setup lang="ts">
const { onLoaded } = useScriptNpm({
  packageName: 'js-confetti',
  file: 'dist/js-confetti.browser.js',
  version: '0.12.0',
  scriptOptions: {
    use() {
      return { JSConfetti: window.JSConfetti }
    },
  },
})
onLoaded(({ JSConfetti }) => {
  // 使用真实的 API 实例
  const confetti = new JSConfetti()
  confetti.addConfetti({ emojis: ['🌈', '⚡️', '💥', '', '💫', '🌸'] })
})
</script>

恭喜!脚本加载后您应该能看到一些表情符号。

不过,您会注意到类型有问题。addConfetti 函数没有类型定义,因此没有智能感知或类型检查。

添加类型

您可以使用 useScriptNpm 组合式函数的泛型为脚本添加类型,并向全局 window 对象添加类型声明。

app.vue
<script setup lang="ts">
export interface JSConfettiApi {
  JSConfetti: { 
    new (): {
      addConfetti: (options?: { emojis: string[] }) => void
    } 
  }
}

declare global {
  interface Window extends JSConfettiApi {}
}

const { onLoaded } = useScriptNpm<JSConfettiApi>({
  packageName: 'js-confetti',
  file: 'dist/js-confetti.browser.js',
  version: '0.12.0',
  scriptOptions: {
    use() {
      return { JSConfetti: window.JSConfetti }
    },
  },
})
onMounted(() => {
  onLoaded(({ JSConfetti }) => {
    const confetti = new JSConfetti()
    // 完全有类型支持!
    confetti.addConfetti({ emojis: ['🌈', '⚡️', '💥', '', '💫', '🌸'] })
  })
})
</script>

额外内容:基于触发条件的脚本加载

您可以使用 trigger 选项延迟加载脚本。如果想在某个事件或某个时间点后加载脚本,这非常有用。

请参考脚本触发器指南了解所有可用选项。

使用 Ref

最简单的方法是使用一个 ref —— 当该 ref 变为真值时,脚本会加载。

app.vue
<script setup lang="ts">
const shouldLoad = ref(false)
const { onLoaded } = useScriptNpm({
  // ..
  scriptOptions: {
    trigger: shouldLoad
  }
})
onLoaded(({ JSConfetti }) => {
  const confetti = new JSConfetti()
  confetti.addConfetti({ emojis: ['🎉', '🎊', ''] })
})
</script>

<template>
  <button @click="shouldLoad = true">
    点击加载彩带
  </button>
</template>
您也可以使用计算属性 ref 或 getter 函数:trigger: computed(() => someCondition.value)trigger: () => shouldLoad.value

使用元素事件

您还可以使用 useScriptTriggerElement 组合函数,基于元素交互触发加载。

app.vue
<script setup lang="ts">
const mouseOverEl = ref<HTMLElement>()
const { onLoaded } = useScriptNpm({
  // ..
  scriptOptions: {
    trigger: useScriptTriggerElement({ trigger: 'mouseover', el: mouseOverEl })
  }
})
// ..
onMounted(() => {
  onLoaded(({ JSConfetti }) => {
    const confetti = new JSConfetti()
    confetti.addConfetti({ emojis: ['L', 'O', 'A', 'D', 'E', 'D'] })
  })
})
</script>

<template>
  <div ref="mouseOverEl">
    <h1>鼠标悬停在这里加载彩带</h1>
  </div>
</template>

额外内容:打包脚本

由于脚本来自 NPM 并且有版本控制,我们可以将它安全地与应用一起打包。这样可以减少 DNS 请求数量,提升应用性能。

要打包脚本,可以使用 bundle 选项。

app.vue
<script setup lang="ts">
const script = useScriptNpm({
  // ...
  scriptOptions: {
    bundle: true
  }
})
// ..
</script>

您应该能看到脚本是从您的应用服务器加载的。

结论

在本教程中,您学习了如何使用 useScriptNpm 注册脚本加载 js-confetti 脚本。

想了解更多您所接触到的具体概念,请查看关键概念文档。