在Deno Fresh框架中点击链接时展示加载状态的实现方案咨询
在Deno Fresh框架中实现Prune操作的页面加载指示器
问题分析
当前点击Prune链接时,浏览器触发整页导航到/posts/prune,但该页面的GET处理逻辑直接返回303重定向回/posts,导致/posts/prune的页面从未被渲染,用户只能看到浏览器标签页的加载图标,无法在/posts页面看到自定义的加载状态提示。
解决方案
核心思路是将原生a标签的跳转改为客户端异步请求,手动控制加载状态的显示,直到操作完成后再处理页面更新或跳转。
方案1:保持重定向,在/posts页面显示加载状态
修改/posts页面代码,用Preact的useState管理加载状态,阻止a标签默认跳转行为,通过fetch发起请求并控制状态:
import { useState } from "preact/hooks"; export default () => { const [isPruning, setIsPruning] = useState(false); const handlePruneClick = async (e) => { e.preventDefault(); setIsPruning(true); try { await fetch("/posts/prune"); // 请求完成后刷新posts页面 window.location.reload(); } catch (error) { console.error("清理操作失败:", error); // 可在此添加错误提示逻辑 } finally { setIsPruning(false); } }; return ( <div> {/* 其他页面内容 */} {isPruning ? ( <div className="loading-indicator"> {/* 自定义加载指示器,比如spinner或文本 */} 正在清理文章... </div> ) : ( <a href="/posts/prune" onClick={handlePruneClick}>Prune</a> )} </div> ); };
同时修正/posts/prune页面的handler,确保prune()执行完成后再返回重定向:
import { Handlers } from "$fresh/server.ts" import { prune } from "~/services/prune/index.ts" export const handler: Handlers = { async GET(_req, ctx) { // 等待prune逻辑执行完成 await prune(); const headers = new Headers() headers.set("location", `/posts/`) return new Response(null, { status: 303, headers, }) }, } // prune页面组件可保留,但实际不会被渲染 export default () => { return ( <body class="py-10 px-20"> <h1 class="tracking-tight text-6xl text-gray-600 font-normal leading-normal mt-0 mb-2"> Pruning </h1> </body> ) }
方案2:取消重定向,异步更新页面(无刷新)
如果不需要页面刷新,可让/posts/prune返回JSON结果,在/posts页面请求完成后直接更新本地数据:
修改/posts/prune的handler:
import { Handlers } from "$fresh/server.ts" import { prune } from "~/services/prune/index.ts" export const handler: Handlers = { async GET(_req, ctx) { await prune(); // 返回成功状态的JSON return new Response(JSON.stringify({ success: true }), { headers: { "Content-Type": "application/json" }, }) }, }
修改/posts页面的处理逻辑,请求完成后更新页面数据(比如重新获取文章列表):
import { useState, useEffect } from "preact/hooks"; import { getPosts } from "~/services/posts/index.ts"; // 假设获取文章列表的函数 export default () => { const [isPruning, setIsPruning] = useState(false); const [posts, setPosts] = useState([]); // 初始化加载文章列表 useEffect(() => { const loadPosts = async () => { const data = await getPosts(); setPosts(data); }; loadPosts(); }, []); const handlePruneClick = async (e) => { e.preventDefault(); setIsPruning(true); try { const res = await fetch("/posts/prune"); if (res.ok) { // 重新加载文章列表 const updatedPosts = await getPosts(); setPosts(updatedPosts); } } catch (error) { console.error("清理操作失败:", error); } finally { setIsPruning(false); } }; return ( <div> {/* 文章列表渲染 */} {posts.map(post => <div key={post.id}>{post.title}</div>)} {/* 加载状态或Prune按钮 */} {isPruning ? ( <div className="loading-indicator">正在清理文章...</div> ) : ( <a href="/posts/prune" onClick={handlePruneClick}>Prune</a> )} </div> ); };
关键说明
- 阻止a标签默认跳转行为,避免整页导航导致的加载状态不可控。
- 使用
useState管理加载状态,请求开始时设为true,结束(成功/失败)时设为false。 - 确保
prune()函数被await,避免未完成操作就跳转或返回结果。
内容的提问来源于stack exchange,提问作者Norfeldt
相关产品推荐
相关产品推荐

