前言
上个月写了一篇 【2024年4月】nuxt3 项目模板,让你开发官网得心应手,本人看到后,觉得略显单调,再加点辅料吧。
1. plugins 处理第三方脚本引入
nuxt 项目经常需要像 CSR 项目一样,在 html 引入 第三方脚本,比如如下这样代码。但是 nuxt 没有 html,没地方编写,这应当如何?
html复制代码<!-- Google Tag Manager --> <script> ;(function (w, d, s, l, i) { w[l] = w[l] || [] w[l].push({ ''gtm.start'': new Date().getTime(), event: ''gtm.js'' }) var f = d.getElementsByTagName(s)[0], j = d.createElement(s), dl = l != ''dataLayer'' ? ''&l='' + l : '''' j.async = true j.src = ''https://www.googletagmanager.com/gtm.js?id='' + i + dl f.parentNode.insertBefore(j, f) })(window, document, ''script'', ''dataLayer'', ''GTM-123456'') </script> <!-- End Google Tag Manager --> <!-- 这段代码要求加到H5页面的所有html页面的head标签中,并且尽可能放在顶部位置 --> <!-- Google Tag Manager (noscript) --> <noscript> <iframe src="https://www.googletagmanager.com/ns.html?id=GTM-123456" height="0" width="0" style="display: none; visibility: hidden" ></iframe> </noscript> <!-- End Google Tag Manager (noscript) --> <!-- 这段代码要求加到H5页面的所有html页面的body中 -->
谷歌 对接人员说了,要把上面的代码放到 html 的对应位置,我们要怎么办呢?
可以使用 plugins,直接在 src/plugins 文件夹里面编写 useGtm.client.ts, 其中 client 表示只在 客户端(web浏览器) 生效。
ts复制代码// filename: src/plugins/useGtm.client.ts export default defineNuxtPlugin(nuxtApp => { nuxtApp.hook(''app:created'', () => { // 将原始的<script>代码内容放入这里 const scriptContent = ` ;(function (w, d, s, l, i) { w[l] = w[l] || [] w[l].push({ ''gtm.start'': new Date().getTime(), event: ''gtm.js'' }) var f = d.getElementsByTagName(s)[0], j = d.createElement(s), dl = l != ''dataLayer'' ? ''&l='' + l : '''' j.async = true j.src = ''https://www.googletagmanager.com/gtm.js?id='' + i + dl f.parentNode.insertBefore(j, f) })(window, document, ''script'', ''dataLayer'', ''GTM-123456'') ` // 创建并注入<script>标签 const scriptTag = document.createElement(''script'') scriptTag.textContent = scriptContent scriptTag.async = true document.head.appendChild(scriptTag) // 创建并注入<iframe>标签 const iframeTag = document.createElement(''iframe'') iframeTag.src = ''https://www.googletagmanager.com/ns.html?id=GTM-123456'' iframeTag.height = ''0'' iframeTag.width = ''0'' iframeTag.style.display = ''none'' iframeTag.style.visibility = ''hidden'' document.body.appendChild(iframeTag) }) })
2. middleware 处理 404
nuxt 项目,当路由不匹配时会去默认的 404,我们老大觉得那个 404 页面不好看,不匹配时直接去首页,这个如何处理。
我在 App.vue layout 等文件处理一直不行,后来在 翻文档 + 百度comate + 阿里通义千问 等的协助下,经过多次测验才找到正解。
现在揭晓答案,直接在 src/middleware 文件夹编写 redirect-404-to-home.global.ts 即可,注意需要 .global,会直接自动加载该中间件。
ts复制代码// filename: src/middleware/redirect-404-to-home.global.ts export default defineNuxtRouteMiddleware((to, form) => { if (to.matched.length === 0) { // 404自动重定向到首页 return navigateTo(''/'') } })
3. 请求第三方接口
server/api/demo.ts 代码如下
ts复制代码import { BASE_URL } from ''../utils/constant'' import axios from ''axios'' // 设置基础URL,例如 ''https://api.example.com'' axios.defaults.baseURL = BASE_URL export default defineEventHandler(async event => { const body = await readBody(event) console.log(''前端传过来的body->'') console.log(body) const { username, email, phone = '''', message='''', } = body const bodyObj = { username, email, phone, message, version: ''v2'' } const params = { key: value, key2: value2, } console.log(new Date().toLocaleString()) console.log(''/n 1) 整理后发送给第三方的请求路径->'') console.log(BASE_URL + ''/api/xxx'') console.log(''/n 2) 整理后发送给第三方的params->'') console.log(params) console.log(''/n 3) 整理后发送给第三方的body->'') console.log(bodyObj) try { const { data } = await axios.post(''/api/xxx'', bodyObj, { params }) console.log(''/n接口返回的数据:'', data) return data } catch (error) { console.error(''Error fetching data:'', error) event.node.res.statusCode = 500 event.node.res.end(error) } })
前端页面部分,直接如下编写即可:
ts复制代码async function onSubmit(event: FormSubmitEvent<Schema>) { // Do something with event.data console.log(event.data) const { username, email, phone, message } = event.data state.sending = true const { data } = await useFetch(''/api/demo'', { method: ''post'', body: { username, email, phone, message, }, }) console.log(data.value) state.sending = false }
4. nuxt.config.ts 配置
php复制代码// https://nuxt.com/docs/api/configuration/nuxt-config export default defineNuxtConfig({ devtools: { enabled: true }, modules: [ ''@nuxt/ui'', ''@vueuse/nuxt'', ''@nuxt/image'', ], colorMode: { preference: ''light'', }, image: { format: [''webp'', ''avif'', ''jpg''], provider: ''ipx'', domains: [''https://www.sanyuk.com''], // 允许加载的图片域名 loader: { type: ''http'', // 默认的图片加载器 options: { cache: true, // 是否开启缓存 format: ''webp'', // 图片格式,默认为自动选择 quality: 75, // 图片压缩质量,默认为75 }, }, strategies: { local: { transform: true, // 是否开启图片转换 inline: ''base64'', // 小于多少字节的图片转为内联base64,默认为20KB }, }, }, css: [''animate.css'', ''~/assets/css/main.css''], devServer: { port: 3333, }, app: { head: { title: ''SANY UK'', charset: ''utf-8'', viewport: ''width=device-width, initial-scale=1'', meta: [ { name: ''description'', content: ''SANY UK'', }, { name: ''keywords'', content: ''SANY, SANY UK, SANY GLOBAL'', }, ], }, }, })
5. Carausel + NuxtImg 配置
NuxtImg 在上一步已经配置,可以使用,NuxtImg 有很多特性,什么优先级,什么图片 placeholder等,如下图。
文档传送门在此 image.nuxt.com/
carousel 本不支持循环播放,需要编写如下代码:
ts复制代码onMounted(() => { setInterval(() => { if (!carouselRef.value) return if (carouselRef.value.page === carouselRef.value.pages) { return carouselRef.value.select(0) } carouselRef.value.next() }, 8000) })
完整代码如下:
vue复制代码<template> <section> <UCarousel ref="carouselRef" v-slot="{ item }" :items="items" :ui="{ item: ''basis-full'', indicators: { active: ''bg-white'', }, }" arrows indicators > <NuxtImg :key="item" :src="item" width="100%" height="auto" layout="responsive" alt="Carousel Image" :priority="true" /> </UCarousel> </section> </template> <script setup lang="ts"> const items = [''/index/1.jpg'', ''/index/2.jpg'', ''/index/3.jpg''] const carouselRef = ref() onMounted(() => { setInterval(() => { if (!carouselRef.value) return if (carouselRef.value.page === carouselRef.value.pages) { return carouselRef.value.select(0) } carouselRef.value.next() }, 8000) }) </script> <style lang="scss" scoped></style>
总结
没啥总结,我感觉 nuxt3 又行了,哈哈~