目录
[五、fetch、useFetch 、useAsyncData的区别](#五、fetch、useFetch 、useAsyncData的区别)
一、NUXT3实现黑夜白天模式切换
需求
实现对网页颜色的整体控制,适配夜晚模式或者其他风格的页面用于迎合更多用户的页面样式多样化的需求。
实现
index.js
javascript
import theme from '@/utils/theme'
// 选择主题
const themeChange = (val: boolean) => {
localStorage.setItem('theme', String(val))
isDark.value = val
if (val) {
currentSkinName.value = 'defaultTheme'
switchTheme(currentSkinName.value)
} else {
currentSkinName.value = 'darkTheme'
switchTheme(currentSkinName.value)
}
}
const switchTheme = (type?: string) => {
type = type || 'darkTheme'
const colorObj: ColorObject = (theme as { [key: string]: ColorObject })[type];
Object.keys(colorObj).map(item => {
document.documentElement.style.setProperty(item, colorObj[item])
})
}
theme.js
javascript
export default {
// 默认主题
'defaultTheme': {
// 主题色
'--color-primary': '#2966df',
'--el-color-primary': '#409eff',
'--el-color-white': '#ffffff',//基础白色,
// 导航条背景色
'--navbar-bg': '#ffffff00',
// 主体背景色
'--background-color': '#ffffff',
// banner背景色
'--banner-bg': '#ffffff00',
// 主要文字色
'--text-color': '#000000',
// 次要文字色
'--text-color-secondary': '#909399',
// 最次要文字色
'--text-color-th': 'rgba(0, 0, 0, 0.3)',
// 边框色
'--border-color': '#e3e3e3',
// 浅边框阴影
'--border-shadow-shallow': 'rgb(0, 0, 0, 0.2)',
// 深边框阴影
'--border-shadow-deep': 'rgb(0, 0, 0, 0.5)',
'--card-color': '#F8FBFE',
'--el-color-primary-light-1': '#53a8ff',
'--el-color-primary-light-2': '#66b1ff',
'--el-color-primary-light-3': '#79bbff',
'--el-color-primary-light-4': '#8cc5ff',
'--el-color-primary-light-5': '#a0cfff',
'--el-color-primary-light-6': '#b3d8ff',
'--el-color-primary-light-7': '#c6e2ff',
'--el-color-primary-light-8': '#d9ecff',
'--el-color-primary-light-9': '#ecf5ff',
},
'darkTheme': {
'--color-primary': '#2966df',
'--el-color-primary': '#409eff',
"--el-color-white": "#ffffff", // 基础白色
// 导航条背景色
'--navbar-bg': '#00000000',
// banner背景色
'--banner-bg': '#00000070',
// 主体背景色
'--background-color': '#262727',
// 主要文字色
'--text-color': '#ffffff',
// 次要文字色
'--text-color-secondary': 'rgba(255, 255, 255, 0.8)',
// 最次要文字颜色
'--text-color-th': 'rgba(255, 255, 255, 0.5)',
// 边框色
'--border-color': '#e3e3e3',
'--card-color': '#011522',
// 浅边框阴影
'--border-shadow-shallow': 'rgb(255, 255, 255, 0.2)',
// 深边框阴影
'--border-shadow-deep': 'rgb(255, 255, 255, 0.5)',
}
}
整个代码的核心在于 document.documentElement.style.setProperty 的这个js方法。
'document'
是JavaScript中表示当前文档的对象。'document.documentElement'
是文档对象模型中表示HTML文档根元素的对象。'.style'
获取根元素的样式属性对象。'.setProperty(item, colorObj[item])'
是设置根元素样式属性的方法。item
是一个变量,表示要设置的CSS属性名称,而colorObj[item]
是相应属性的值。
当然你也可以通过设置更多的主题来达到主题切换的效果。
效果
二、scrollreveal插件实现动画效果
需求
网站想要高大上,动画必不可少,如何实现优雅的动画就成了关键。实现的方式有很多比如animate.css + wow.js 实现。又或者使用scrollreveal插件来实现。这里我们来通过scrollreveal插件来实现动画效果。
实现
第一步,在src下创建plugins文件夹,写入名为scrollreveal.client.ts的文件。
javascript
import { defineNuxtPlugin } from "#app";
import scrollReveal from 'scrollreveal'
export default defineNuxtPlugin((nuxtApp) => {
let data = scrollReveal();
return {
provide: {
scrollReveal: data,
},
}
});
封装
在components文件夹下创建名为RevealAnimation.vue的文件
TypeScript
<template>
<div :id="ID" className="load-hidden">
<slot></slot>
</div>
</template>
<script setup lang="ts">
import { ref, onMounted } from 'vue';
const props = defineProps({
options: {
type: Object,
default: () => ({
// 动画的时长
duration: 800,
// 延迟时间
delay: 100,
// 动画开始的位置,'bottom', 'left', 'top', 'right'
origin: 'bottom',
// 回滚的时候是否再次触发动画
reset: false,
// 延时执行方式(always(一直延时执行),once(只延时执行一次),onload(只在加载时延时执行))
useDelay: 'onload',
// 在移动端是否使用动画
mobile: true,
// 滚动的距离,单位可以用%,rem等
distance: '5rem',
// 其他可用的动画效果
opacity: 0.01,
// 执行速度 线性函数啥的
easing: 'ease-in-out',
// 执行方式(缩放)
scale: 0.9,
}),
},
ID: {
type: String,
default: 'reveal',
},
});
const { $scrollReveal } = useNuxtApp()
onMounted(() => {
if (process.client) {
retScroll($scrollReveal);
}
});
const retScroll = (data: any) => {
data.reveal(`#${props.ID}`, { ...props.options })
};
</script>
<style scoped>
.load-hidden {
visibility: hidden;
}
</style>
另外我们再封装一个自动生成options配置项的工具,这里我只把几个关键的配置项写上了,需要更多配置项自己手动添加就可以。
TypeScript
export const createAnimationOptions = (origin: string, duration: number, scale: number) => {
return {
// 动画的时长
duration: duration || 800,
// 延迟时间
delay: 100,
// 动画开始的位置,'bottom', 'left', 'top', 'right'
origin: origin || 'bottom',
// 回滚的时候是否再次触发动画
reset: false,
// 延时执行方式(always(一直延时执行),once(只延时执行一次),onload(只在加载时延时执行))
useDelay: 'always',
// 在移动端是否使用动画
// mobile: true,
// 滚动的距离,单位可以用%,rem等
distance: '5rem',
// 其他可用的动画效果
opacity: 0.01,
// 执行速度 线性函数啥的
easing: 'ease-in-out',
// 执行方式(缩放)
scale: scale || 0.9,
};
}
使用
TypeScript
<template>
<RevealAnimation :ID="'web'" :options="createAnimationOptions('top', 300, .9)">
<div class="title">
<h1>题海·网页搜题</h1>
<h2>Questions · Web search questions</h2>
</div>
<div class="center">
<div class="contentImage">
<img :src="Webimg" alt="">
<ComBotton :title="'开始搜题'" @onclick="handleRoute('web')"/>
</div>
<ContentCard v-for=" (val, key) in getContent('web')" :ID="`web_card_${key}`"
:options="createAnimationOptions('left', 800 + key * 300, .5)" :content="val" :key="key" />
</div>
</RevealAnimation>
</template>
<script setup lang="ts">
import { createAnimationOptions } from "@/utils/tool";
</script>
文档
nullhttps://scrollrevealjs.org/api/reveal.html更多方法API详见官方文档
效果
三、useSeoMeta的使用
作用
useSeoMeta组合函数能够以完全支持TypeScript的形式将你网站的SEO元标签定义为一个扁平对象。里面包含了许多的属性,比如:
"ogDescription" 通常是指 Open Graph 描述,也是 Open Graph 协议的一部分。这是一个用于指定在社交媒体分享时显示的描述文本的元数据。
"Open Graph" 是一种用于社交媒体分享的元数据协议。Open Graph 协议是由 Facebook 提出的一种协议,用于在分享链接时显示更富有信息的预览内容,包括标题、描述和图像。
更多详细属性请参阅官方文档
使用
TypeScript
<script setup lang="ts">
import {useSeoMeta} from "unhead";
const data = res.value as QuestionData[]
useSeoMeta({
title: data[0].question + ' - 题海',
description,
ogTitle: data[0].question,
ogSiteName: '题海',
ogType: "website",
ogDescription: description
})
}
</script>
只需要在setup中调用该方法即可使用。
效果
四、NUXT3开启代理
使用
找到根目录下的nuxt.config.ts 文件即可。
TypeScript
// https://nuxt.com/docs/api/configuration/nuxt-config
export default defineNuxtConfig({
routeRules: {
'/question/**': {swr: true},
"/web-service/**": {
proxy: "http://app.******.com/web-service/**",
},
"/sso-service/**": {
proxy: "http://app.******.com/sso-service/**",
},
"/payService/**": {
proxy: "http://app.******.com/payService/**",
}
},
})
注意
NUTXT的代理和普通的VUE和REACT项目的代理不太一样,一般来说正常的项目代理只需要拼接域名端口号就行,但是NUXT需要把要代理的路由地址也填写上。这里需要特别注意一下。
五、$fetch、useFetch 、useAsyncData的区别
-
$fetch
:- 用法 :在页面组件中,你可以通过在
asyncData
或fetch
钩子中调用$fetch
来触发数据的获取。 - 作用 :
$fetch
用于在服务端渲染时获取数据,或者在客户端导航时获取数据。它允许你在组件级别发起数据请求。
- 用法 :在页面组件中,你可以通过在
-
useFetch
:- 用法 :
useFetch
是 Nuxt.js 提供的一个插件,允许你在组件中使用 Composition API 风格的fetch
钩子,而不是使用传统的生命周期钩子。 - 作用 :与
$fetch
类似,useFetch
也用于在组件级别发起数据请求,但它更适用于使用 Composition API 风格的组件。
- 用法 :
-
useAsyncData
:- 用法 :
useAsyncData
用于将异步数据加载到 Nuxt.js 页面中。它被设计用于在服务端渲染和客户端导航之间共享数据。 - 作用 :
useAsyncData
主要用于在页面组件中预取数据,以便在服务端渲染时提供页面所需的数据。
- 用法 :
总体而言,这些方法提供了不同的方式来处理数据获取,你可以根据具体的需求选择适合的方法。$fetch
和 useFetch
更加灵活,适用于各种场景,而 useAsyncData
更专注于服务端渲染时的数据获取。
具体请参阅官方文档:
数据获取 · 快速入门 NuxtNuxt 提供了组合函数来处理应用程序中的数据获取。https://nuxt.com.cn/docs/getting-started/data-fetching
六、错误页面处理
使用
在src下创建 error.vue页面即可。
代码
TypeScript
<template>
<div class="container">
<img :src="noFound" alt="">
<div class="info">
<p>The Page not Found-找不到你要访问的页面</p>
<div class="sub">
<a href="/">Back</a>
</div>
</div>
</div>
</template>
<script setup>
import noFound from '@/assets/svg/404error.svg'
</script>
<style scoped lang="scss">
.container {
width: 100vw;
height: 100vh;
--color: #E1E1E1;
background-color: #F3F3F3;
background-image: linear-gradient(0deg, transparent 24%, var(--color) 25%, var(--color) 26%, transparent 27%, transparent 74%, var(--color) 75%, var(--color) 76%, transparent 77%, transparent),
linear-gradient(90deg, transparent 24%, var(--color) 25%, var(--color) 26%, transparent 27%, transparent 74%, var(--color) 75%, var(--color) 76%, transparent 77%, transparent);
background-size: 55px 55px;
position: relative;
img {
position: absolute;
top: 40%;
left: 50%;
transform: translate(-50%, -50%);
width: 600px;
height: 600px;
}
.info {
position: absolute;
top: 75%;
left: 50%;
transform: translate(-50%, -50%);
text-align: center;
p {
font-size: 24px;
color: #666;
}
.sub {
margin-top: 30px;
a {
color: #fff;
font-size: 16px;
padding: 6px 10px;
border-radius: 10px;
border: 1px solid #666;
background-color: var(--color-primary);
}
}
}
}</style>