You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.19 14:17:04