闽公网安备 35020302035485号
import { RouteRecordRaw } from "vue-router";
export const routes: RouteRecordRaw[] = [
{
path: "/",
redirect: '/home'
},
{
path: "/home",
name: "Home",
component: () => import("./Home.vue"),
children: [
{
path: ':id',
name: "Detail",
component: () => import('./Detail.vue'),
}
]
},
]
router.tsimport {createRouter, createWebHistory} from "vue-router";
import { routes } from './routes.ts'
export const router = createRouter({
history: createWebHistory(),
routes,
})
文件结构:<template>
<div>
<div class="text-red-700">Home</div>
<div class="w-full flex flex-wrap gap-3">
<router-link v-for="item in dataList" :to="`/home/${item.id}`">
<img :src="item.url" alt="">
</router-link>
</div>
<el-dialog title="Detail" v-model="dialogVisible">
<router-view></router-view>
</el-dialog>
</div>
</template>
<script setup lang="ts">
import {computed, ref} from "vue";
import {useRoute, useRouter} from "vue-router";
import axios from "axios";
import {randomSize} from "../utils/randomSize.ts";
// 堆代码 duidaima.com
const route = useRoute()
const router = useRouter()
const lastRoute = computed(() => route.matched[route.matched.length - 1])
const dialogVisible = computed({
get() {
return lastRoute.value.name == 'Detail'
},
set(val) {
if (!val) {
router.go(-1)
}
},
})
const dataList = ref([])
const loading = ref(false)
function getList() {
loading.value = true
const data = localStorage.getItem('imageData')
if (!data) {
axios.get('https://picsum.photos/v2/list')
.then(({data}) => setDataList(data))
.then(data => localStorage.setItem('imageData', JSON.stringify(data)))
.finally(() => {
loading.value = false
})
} else {
setDataList(JSON.parse(data))
}
}
getList()
function setDataList(data) {
dataList.value = data.map(item => ({
id: item.url.split('/').pop(),
url: randomSize(item.download_url)
}))
return data
}
</script>
这里重点看两个地方:2.为了控制弹窗的显隐,我定义了一个dialogVisible计算对象,他的get来自router.matched列表中最后一个路由(最终命中的路由)是否为Detail,如果为Detail,就true,否则为false;它的set我们只需要处理false的情况,当false的时候,路由回退1。(其实是用push/replace还是用go我是有点纠结的,但是我看到小红书这里是用的回退,所以我也就用回退了,虽然回退在这种使用场景中存在一定的隐患)
// route.ts
export const routes = [
...
{
path: '/home/:id',
name: "DetailId",
component: () => import('./Detail.vue')
}
]
这个路由跟Home是同级的,使用了绝对路径来标记path(这就是上面detail采用相对路径的原因),同时为了避免name冲突,我换了一个name,component还是使用Detail.vue(这里我后来发现其实也可以使用其他的组件,其实真正起作用的是path,而不是component)。// router.ts
router.beforeEach((to, from) => {
if (to.name === 'Detail') {
if (from.name === 'Home') {
return true
} else {
return { name: 'DetailId', params: to.params }
}
}
})
这个守卫的作用是,当发生路由跳转时,如果to为Detail,则判断from是否为Home,如果from为Home,则可以正常跳转,如果from不为Home,则说明是刷新或者链接打开,这时跳转至DetailId页面,并且params保持不变。短短十行代码,就解决了问题。可以看到,正常从列表显示详情还是会正常从弹窗中显示,而如果此时刷新页面,就会直接进入到详情页面。