前言
上个月写了一篇 【2024年4月】nuxt3 项目模板,让你开发官网得心应手,本人看到后,觉得略显单调,再加点辅料吧。
1. plugins 处理第三方脚本引入
nuxt
项目经常需要像 CSR
项目一样,在 html
引入 第三方脚本
,比如如下这样代码。但是 nuxt
没有 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浏览器)
生效。
// 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
,会直接自动加载该中间件。
// 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
代码如下
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)
}
})
前端页面部分,直接如下编写即可:
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 配置
// 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
本不支持循环播放,需要编写如下代码:
onMounted(() => {
setInterval(() => {
if (!carouselRef.value) return
if (carouselRef.value.page === carouselRef.value.pages) {
return carouselRef.value.select(0)
}
carouselRef.value.next()
}, 8000)
})
完整代码如下:
<template>
<section>
<UCarousel
ref="carouselRef"
v-slot="{ item }"
:items="items"
:ui="{
item: 'basis-full',
indicators: {
active: 'bg-white',
},
}"
class="overflow-hidden"
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
又行了,哈哈~