现在在Nuxt3里面运行一个浏览器脚本比Nuxtjs(Nuxt2)里面累多了,而且还挺隐蔽的,再加上Nuxt3发布才几个月啊怎么都没人去写这种教程还得我一个一个翻所以特意写了这篇文章
是什么
浏览器端js脚本指只能在浏览器端运行的JavaScript脚本,里面涉及了DOM操作和浏览器环境仅有的一些类和对象,而在服务器端渲染时是没有这些对象的。
为什么
浏览器端js涉及DOM操作,而在SSR渲染阶段时,不会出现Document
和Window
等浏览器端才会出现对象,所以浏览器端脚本只能在浏览器端执行,如果在服务端执行会出现错误,比如说:
<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库的问题也解决啦~
Preview: