好的, 我来为你创建一个使用 Bun、UnoCSS、HTMX 和 Elysia 的实时天气预报程序。这个程序将使用服务器端渲染 (SSR), 允许用户选择不同的城市, 并可以展示未来一天、三天或一周的天气预报。

首先, 让我们设置项目结构和安装必要的依赖:

  1. 创建项目并安装依赖:
mkdir weather-forecast
cd weather-forecast
bun init
bun add elysia @elysiajs/html @elysiajs/static unocss htmx.org
  1. 创建以下文件结构:
weather-forecast/
├── src/
│   ├── index.ts
│   ├── weather.ts
│   └── views/
│       ├── layout.ts
│       └── forecast.ts
├── public/
│   └── styles.css
└── package.json
  1. src/index.ts 中设置主应用:
import { Elysia } from "elysia";
import { html } from "@elysiajs/html";
import { staticPlugin } from "@elysiajs/static";
import { layout } from "./views/layout";
import { forecast } from "./views/forecast";
import { getWeatherData } from "./weather";
 
const app = new Elysia()
  .use(html())
  .use(staticPlugin())
  .get("/", ({ html }) => html(layout(forecast())))
  .get("/forecast/:city/:days", async ({ params, html }) => {
    const { city, days } = params;
    const weatherData = await getWeatherData(city, parseInt(days));
    return html(forecast(city, parseInt(days), weatherData));
  })
  .listen(3000);
 
console.log(`Server is running at http://localhost:${app.server?.port}`);
  1. src/weather.ts 中创建一个模拟的天气数据获取函数:
export interface WeatherData {
  date: string;
  temperature: number;
  description: string;
}
 
export async function getWeatherData(city: string, days: number): Promise<WeatherData[]> {
  // 这里应该是实际的API调用,但我们用模拟数据代替
  return Array.from({ length: days }, (_, i) => ({
    date: new Date(Date.now() + i * 24 * 60 * 60 * 1000).toLocaleDateString(),
    temperature: Math.round(Math.random() * 20 + 10),
    description: ["Sunny", "Cloudy", "Rainy"][Math.floor(Math.random() * 3)]
  }));
}
  1. src/views/layout.ts 中创建布局组件:
export const layout = (content: string) => `
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Weather Forecast</title>
  <script src="https://unpkg.com/htmx.org@1.9.6"></script>
  <link href="/public/styles.css" rel="stylesheet">
</head>
<body class="bg-gray-100 text-gray-800">
  <div class="container mx-auto p-4">
    <h1 class="text-3xl font-bold mb-4">Weather Forecast</h1>
    ${content}
  </div>
</body>
</html>
`;
  1. src/views/forecast.ts 中创建天气预报组件:
import { WeatherData } from "../weather";
 
export const forecast = (city: string = "", days: number = 1, weatherData: WeatherData[] = []) => `
  <div>
    <form hx-get="/forecast" hx-target="#forecast" class="mb-4">
      <input type="text" name="city" value="${city}" placeholder="Enter city" class="p-2 border rounded">
      <select name="days" class="p-2 border rounded">
        <option value="1" ${days === 1 ? 'selected' : ''}>1 day</option>
        <option value="3" ${days === 3 ? 'selected' : ''}>3 days</option>
        <option value="7" ${days === 7 ? 'selected' : ''}>7 days</option>
      </select>
      <button type="submit" class="p-2 bg-blue-500 text-white rounded">Get Forecast</button>
    </form>
    <div id="forecast">
      ${city && weatherData.length > 0 ? `
        <h2 class="text-2xl mb-2">Forecast for ${city}</h2>
        <div class="grid grid-cols-1 md:grid-cols-3 gap-4">
          ${weatherData.map(day => `
            <div class="bg-white p-4 rounded shadow">
              <h3 class="font-bold">${day.date}</h3>
              <p>Temperature: ${day.temperature}°C</p>
              <p>Description: ${day.description}</p>
            </div>
          `).join('')}
        </div>
      ` : ''}
    </div>
  </div>
`;
  1. public/styles.css 中添加 UnoCSS 样式:
@import 'https://cdn.jsdelivr.net/npm/@unocss/reset/tailwind.min.css';
@unocss all;
  1. 更新 package.json 中的 scripts:
{
  "scripts": {
    "dev": "bun run --watch src/index.ts"
  }
}

现在, 你可以运行 bun run dev 来启动服务器。访问 http://localhost:3000 就能看到天气预报应用了。

这个应用使用了:

  • Elysia 作为 web 框架
  • HTMX 进行无刷新的页面更新
  • UnoCSS 进行样式设置
  • 服务器端渲染 (SSR) 生成初始 HTML
  • 允许用户选择不同的城市和预报天数

注意, 这个例子使用了模拟的天气数据。在实际应用中, 你需要替换 getWeatherData 函数, 使用真实的天气 API 来获取数据。