优雅地在Nuxt3中运行浏览器端js脚本:是什么,为什么和怎么做

1年前
1年前
2.1k字
加载中
文章概述 Powered by Google Gemini Beta
Nuxt3 中运行浏览器端脚本变得更加复杂,需要采用特定方法。可以使用 Vue Hook(onMounted)在 DOM 创建后执行脚本,以避免在服务端渲染期间出现错误。对于需要在服务器渲染时避免执行的浏览器端库,可以使用插件将库绑定到 Vue 全局变量中,从而仅在浏览器端加载。

现在在Nuxt3里面运行一个浏览器脚本比Nuxtjs(Nuxt2)里面累多了,而且还挺隐蔽的,再加上Nuxt3发布才几个月啊怎么都没人去写这种教程还得我一个一个翻所以特意写了这篇文章

是什么

浏览器端js脚本指只能在浏览器端运行的JavaScript脚本,里面涉及了DOM操作和浏览器环境仅有的一些类和对象,而在服务器端渲染时是没有这些对象的。

为什么

浏览器端js涉及DOM操作,而在SSR渲染阶段时,不会出现DocumentWindow等浏览器端才会出现对象,所以浏览器端脚本只能在浏览器端执行,如果在服务端执行会出现错误,比如说:

<script setup>
const a = document.getElementById("someid")
a.innerHTML = 'Hello!'
</script>
<template>
 <div id="someid">Hi!</div>
</template>

就会直接报错:

怎么做

如何让浏览器脚本可以在浏览器正确执行而避过服务端渲染呢?

1. Vue Hook

Vue的Hook(Mounted)是在DOM创建后执行的,所以我们可以把代码改成:

<script setup>
// 在这里加入了 onMounted Hook Function 可以保证它在浏览器端执行
// 在nuxt3中 不需要引入onMounted等 nuxt3自动帮你引入了
onMounted(() => {
 const a = document.getElementById("someid")
 a.innerHTML = 'Hello!'
})
</script>
<template>
 <div id="someid">Hi!</div>
</template>

2. Plugins绑定Vue全局变量调用

面对import方式引入浏览器端js库的时候,Hook就无能为力了。Hook虽然能执行,但是在文件里引入的时候就会出错。这样的情况只能用plugins侧载到Vue全局变量端进行调用,比如说chiblog的valine评论实现:

/plugins/loadValine.client.ts

import valine from 'valine'
export default defineNuxtPlugin(nuxtApp => {
 nuxtApp.vueApp.config.globalProperties.$valine = valine
 // nuxtApp.vueApp是Vue实例,Vue3后全局变量挂载到了 Vue.globalProperties 中
})

/components/CommentSys/Valine.vue

<script setup>
const $valine = useNuxtApp().vueApp.config.globalProperties.$valine

const props = defineProps({
 appid: String,
 appkey: String,
 path: String,
 avatar: String
})

onMounted(() => {
 new $valine({
 appId: props.appid,
 appKey: props.appkey,
 path: props.path,
 el: '#valine-comment',
 avatar: props.avatars
 })
})

</script>
<template>
 <div id="valine-comment">
 </div>
</template>

但如果代码是这么实现的话会出现错误(服务器渲染时会渲染import入的内容):

<script setup>
import Valine from 'valine'

const props = defineProps({
 appid: String,
 appkey: String,
 path: String,
 avatar: String
})

onMounted(() => {
 new Valine({
 appId: props.appid,
 appKey: props.appkey,
 path: props.path,
 el: '#valine-comment',
 avatar: props.avatars
 })
})

</script>
<template>
 <div id="valine-comment">
 </div>
</template>

然后浏览器端js库的问题也解决啦~

技术向VueNuxtJavaScriptESMSSRNuxt3

Comments
  • Latest
  • Oldest
  • Hottest
Powered by Waline v3.0.0-alpha.1