我正在使用 nuxt3、tailwindcss 和 Wordpress REST API 制作一个作品集网站。
作品集网站总体布局如下:
<body>
<div id="page-wrapper">
<section id="landing-image" class="w-screen h-screen">...</section>
<section id="about">...</section>
<section id="projects-grid">...</section>
</div>
</body>
目标:
我希望网站感觉只有一页,但支持从项目网格中单击项目来阅读有关该项目的更多信息。单击项目时,内容应该加载,而无需(可见)重新加载页面。请参阅此作品集网站作为项目网格的示例,其中包含我尝试实现的项目弹出窗口:https://www.tessarosejacksoncomposer.com/
我尝试过的:
1.)我想到的一种方法是向包含被 tailwind 隐藏的帖子内容的页面添加一个 div,并且 nuxt 跟踪状态。当帖子需要查看或不查看并且加载正确的项目内容时,Nuxt 有条件地设置“隐藏”类。
app.vue
<template>
<div id="page-wrapper">
<section id="landing-image" class="w-screen h-screen">...</section>
<section id="about">...</section>
<section id="projects-grid">...</section>
</div>
<div id="project-content-wrapper" class="absolute h-screen w-screen" :class="{'hidden': postHidden }">
... (dynamically load project content and unhide by nuxt state management) ...
</div>
</template>
这是一个很好且简单的实现,但我的主要问题是每个项目没有唯一的 url。当我想分享一个特定的项目时,我想发送一个立即打开该项目的网址。现在该网址始终保留在主页上。第二个问题是使用该网站时没有 url 历史记录,我认为这不直观。
2.)因此,我找到了第二种方法,使用嵌套的 nuxt 页面和
<NuxtPage />
组件(参考:https://v2.nuxt.com/examples/routing/nested-pages/ )。我的想法是将 <NuxtPage />
标签放在项目内容 div 中,然后有一个根据 url 进行更改的嵌套页面,但不会重新加载整个页面(明显)。在 pages/
目录中,我创建了一个 project/
目录、project.vue
文件,并在 project/
目录中添加了一个 [...slug].vue
文件,其中包含项目布局并呈现内容。这样我的项目就有了 url example.com/project/project-slug
。 project.vue
文件只是获得漂亮 url 的传递,并且仅包含带有 <NuxtPage />
的模板来嵌套项目子项。
app.vue
<template>
<div id="page-wrapper">
<section id="landing-image" class="w-screen h-screen">...</section>
<section id="about">...</section>
<section id="projects-grid">...</section>
</div>
<div id="project-content-wrapper" class="absolute h-screen w-screen" :class="{'hidden': postHidden }">
<NuxtPage />
</div>
</template>
第二种方法解决了url问题,但是页面明显重新加载并破坏了单页效果。这是因为页面可以滚动,当使用
<NuxtLink>
转到项目时,站点会滚动到顶部。当我添加一个跨 UI 元素来关闭项目弹出窗口并返回主页时,这成为一个问题。单击十字时,页面位于顶部,迫使用户再次向下滚动回到项目网格。我想要这样的错觉:弹出窗口在网站上打开,当单击十字时,用户会从上次中断的地方继续。
问题:
有谁知道一种方法来实现这个项目网格弹出效果,每个项目都有唯一的网址,同时保持留在同一个页面上的感觉?
你可以尝试这样的事情(注意:你应该有一个根元素):
<template>
<main>
<div v-if="project_list">
<div id="project-wrapper" v-for="item,index in project_list" :key="'project'+index" @click="handle(item)">
<section id="landing-image" class="w-screen h-screen">...</section>
<section id="about">...</section>
<section id="projects-grid">...</section>
</div>
</div>
<div id="project-content-wrapper" class="absolute h-screen w-screen" :class="{'hidden': postHidden }">
... (dynamically load project content and unhide by nuxt state management) ...
</div>
</main>
</template>
<script setup>
import {ref,onMounted} from 'vue'
const route = useRoute()
const postHidden = ref(true)
const postContent = ref(null)
const { data: project_list} = await useFetch('/path/to/myapi')//return an array of projects
const handle = (item)=>{
if(!window)return
window.history.pushState(null,'',`?p=${item.slug}`)
postHidden.value = false
postContent.value = item
}
onMounted(()=>{
if(route.query.p){
const post = route.query.p
const {data,error} =
postHidden.value = false
project_list.forEach(item=>{
if (item.slug == p) postContent.value = item
})
}
})
</script>
这是一个粗略的实现,例如不支持错误。这个想法是使用“window.history.pushState”通过查询字符串修改 url,并在页面加载时使用此查询字符串(如果存在)