在我的 Nuxt.js 3 项目中,我想实现单页导航。我遵循了以下文章,但没有成功。有什么建议吗?
在 Nuxt.js 3 中执行此操作的正确方法是在
plugins/
目录中创建“router.scrollBehaviour.js”文件。其内容应该是
import { defineNuxtPlugin } from "#app";
export default defineNuxtPlugin((nuxtApp) => {
nuxtApp.$router.options.scrollBehavior = async (to, from, savedPosition) => {
if (savedPosition) {
return savedPosition;
}
const findEl = async (hash, x = 0) => {
return (
document.querySelector(hash) ||
new Promise((resolve) => {
if (x > 0) {
return resolve(document.querySelector("#app"));
}
setTimeout(() => {
resolve(findEl(hash, 1));
}, 300);
})
);
};
if (to.hash) {
const el = await findEl(to.hash);
if ("scrollBehavior" in document.documentElement.style) {
console.log("hash path hit scroll to");
return window.scrollTo({ top: el.offsetTop, behavior: "smooth" });
} else {
return window.scrollTo(0, el.offsetTop);
}
}
return { left: 0, top: 0, behaviour: "smooth" };
};
})
在 Nuxt.js 3 中,您无需插件即可完成此操作。只需将“app/router.options.ts”放置在项目的根目录中,然后添加以下代码即可:
import type { RouterConfig } from "@nuxt/schema";
export default {
scrollBehavior(to, from, savedPosition) {
if(savedPosition)
return savedPosition;
if (to.hash && to.path == from.path) {
const el = document.querySelector(to.hash);
return { top: el.offsetTop, left: 0, behavior: "smooth" };
}
return {
top: 0,
left: 0
}
}
};
我更喜欢这个:
插件/scroll-behavior.client.ts
import { useRouter } from "vue-router";
export default async function () {
if (typeof window !== "undefined") {
const router = useRouter();
router.afterEach(async (to, from) => {
if (to.hash) {
const targetElement = document.querySelector(to.hash);
if (targetElement) {
await targetElement.scrollIntoView({
behavior: "smooth",
block: "start",
inline: "nearest",
});
return;
}
}
window.scrollTo({ top: 0, behavior: "smooth" });
});
}
}
在 nuxt.config.ts 中添加以下内容:
plugins: [
{ src: '~/plugins/scroll-behavior.client.ts', mode: 'client' }
]
然后,在你的组件中,引用带有 id 的内容,比如 id="about" 页面上有一个按钮,可以顺利地显示 about 哈希值。
<nuxt-link :to="{ hash: '#about' }" class="btn btn-lg btn-warning mx-1">Learn more</nuxt-link>
为 Nuxt3 定义 pulgin 文件 plugins/scroll-behavior.client.ts 就像 Kaiser 提到的, 但我必须修改它才能适用于 Nuxt3。主要区别是您应该在转换实际发生之前使用 beforeEach 调用动画。否则你最终会尝试为已经存在的位置设置动画。延迟承诺弥补了过渡时间,如果你把它缩短,过渡就会更快。这适用于单页面,但可能需要升级才能在页面之间导航锚点。
export default defineNuxtPlugin(async function () {
if (typeof window !== "undefined") {
const router = useRouter();
router.beforeEach((to) => {
if (to.hash) {
const targetElement = document.querySelector(to.hash);
if (targetElement) {
targetElement.scrollIntoView({
behavior: "smooth"
})
const p:Promise<boolean> = new Promise((resolve)=>{
setTimeout(()=>{
resolve(true);
},1000)
})
return p
}
}
window.scrollTo({ top: 0, behavior: "smooth" });
});
}
});
并像前面提到的那样在 nuxt.config.ts 中设置插件:
plugins: [
{ src: '~/plugins/scroll-behavior.client.ts', mode: 'client' }
]
然后您可以使用带有哈希值的导航:
<NuxtLink :to="{path: '/', hash: '#anchor1'}">
<div class="button">Link 1</div>
</NuxtLink>
...
<div id="anchor1"> Target content block </div>
在 Nuxt 3 中使用插件不是实现此目的的方法 - 请看这里:https://github.com/nuxt/nuxt/issues/22663