随机获取一张图片

https://picsum.photos/(官方称为 Lorem Picsum)是一个非常实用的免费 API,它提供高质量的随机占位图片。对于开发者来说,它极其方便,无论是快速搭建 UI 原型、填充测试数据,还是作为小型应用中的随机图片来源,都非常适合。

下面我们来详细说说它的用法和在 JSBox 中的集成。


Lorem Picsum (https://picsum.photos/) 详细用法

Lorem Picsum 的设计哲学是极简主义,它的用法非常直观。

一、基本用法:获取随机图片

最简单的用法是直接指定图片的宽度和高度。

  • API: https://picsum.photos/{width}/{height}

  • 示例:

    • https://picsum.photos/200/300 - 返回一张宽度 200 像素,高度 300 像素的随机图片。

    • https://picsum.photos/400 - 返回一张宽度和高度都是 400 像素的正方形随机图片(如果只提供一个维度,则假定为正方形)。

每次刷新这个 URL,你都会得到一张不同的随机图片

二、获取指定图片:通过 ID

如果你想获取某张特定的图片,并且每次都一样,你可以使用图片的 ID。图片的 ID 可以通过 List API 获取(后面会讲)。

  • API: https://picsum.photos/id/{id}/{width}/{height}

  • 示例:

    • https://picsum.photos/id/237/200/300 - 返回 ID 为 237 的图片,尺寸 200x300。

三、保持随机但可重复:通过 Seed

如果你想要每次获取的图片是随机的,但对于同一个“种子”,每次请求都能得到相同的随机图片,可以使用 seed。这在测试或需要可预测的随机性时非常有用。

  • API: https://picsum.photos/seed/{seed}/{width}/{height}

  • 示例:

    • https://picsum.photos/seed/myuniqueid/200/300 - 每次请求这个 URL,即使是随机的,也会得到同一张图片。

四、图片修饰:灰度与模糊

Lorem Picsum 还提供了简单的图片修饰功能。

  1. 灰度 (Grayscale)

    • API: 在 URL 后添加 ?grayscale

    • 示例: https://picsum.photos/200/300?grayscale - 返回一张 200x300 的灰度随机图片。

  2. 模糊 (Blur)

    • API: 在 URL 后添加 ?blur?blur={amount} (模糊量从 1 到 10)

    • 示例:

      • https://picsum.photos/200/300?blur - 默认模糊量。

      • https://picsum.photos/200/300?blur=5 - 返回一张中等模糊的图片。

  3. 同时使用: 可以组合使用 & 符号。

    • 示例: https://picsum.photos/200/300?grayscale&blur=2 - 返回一张灰度且轻微模糊的图片。

五、获取图片列表和元数据

除了直接获取图片,你还可以获取一个图片列表,包含每张图片的 ID、作者、URL 等信息。

  • 获取图片列表:

    • API: https://picsum.photos/v2/list

    • 分页: https://picsum.photos/v2/list?page={page}&limit={limit}

      • page: 页码 (从 1 开始)。

      • limit: 每页返回的图片数量 (最大通常为 100)。

    • 响应示例 (JSON 数组):

      
      [
        {
          "id": "0",
          "author": "Alejandro Escamilla",
          "width": 5000,
          "height": 3333,
          "url": "https://unsplash.com/photos/yC-YJtJrxP4",
          "download_url": "https://picsum.photos/id/0/5000/3333"
        },
        {
          "id": "1",
          "author": "Alejandro Escamilla",
          "width": 5000,
          "height": 3333,
          "url": "https://unsplash.com/photos/LNRyGwQM7Ts",
          "download_url": "https://picsum.photos/id/1/5000/3333"
        }
        // ...
      ]
      

      download_url 字段是直接可用于获取图片的 URL。

  • 获取单张图片元数据:

    • API: https://picsum.photos/id/{id}/info

    • 示例: https://picsum.photos/id/237/info - 返回 ID 237 图片的详细信息。


在 JSBox 中使用 Lorem Picsum

Lorem Picsum 非常适合在 JSBox 中进行网络请求和图片显示练习。

1. 在 image 控件中直接显示随机图片

这是最简单快捷的方式。

  
$ui.render({
  
  props: {
  
    title: "随机图片",
  
    bgcolor: $color("systemBackground"),
  
    theme: "auto"
  
  },
  
  views: [
  
    {
  
      type: "image",
  
      props: {
  
        // 直接使用 URL 作为 src
  
        src: "https://picsum.photos/400/600", // 每次运行都会显示不同的图片
  
        contentMode: $contentMode.scaleAspectFit // 保持图片宽高比并适应视图
  
      },
  
      layout: (make) => {
  
        make.center.equalTo(make.super);
  
        make.width.equalTo(300);
  
        make.height.equalTo(450);
  
      }
  
    },
  
    {
  
      type: "button",
  
      props: { title: "换一张" },
  
      layout: (make) => {
  
        make.centerX.equalTo(make.super);
  
        make.top.equalTo($("image").bottom).offset(20);
  
        make.size.equalTo($size(100, 40));
  
      },
  
      events: {
  
        tapped: (sender) => {
  
          // 动态更新图片 src
  
          $("image").src = `https://picsum.photos/400/600?${Date.now()}`; // 加一个时间戳确保强制刷新
  
          $ui.toast("已换新图片");
  
        }
  
      }
  
    }
  
  ]
  
});
  

2. 下载图片数据并进行操作(例如保存、分享或处理)

如果你需要对图片进行额外的操作(如保存到文件、分享、进行图像处理),你需要先下载它的原始数据。

  
$ui.render({
  
  props: {
  
    title: "下载与操作图片",
  
    bgcolor: $color("systemBackground"),
  
    theme: "auto"
  
  },
  
  views: [
  
    {
  
      type: "button",
  
      props: { title: "下载并分享" },
  
      layout: $layout.center,
  
      events: {
  
        tapped: async (sender) => {
  
          $ui.loading(true);
  
          $ui.toast("下载中...");
  
          try {
  
            // 下载一张灰度模糊图片
  
            const imageUrl = "https://picsum.photos/600/800?grayscale&blur=3";
  
            const resp = await $http.download({ url: imageUrl });
  
            $ui.loading(false);
  

  
            if (resp.error) {
  
              $ui.alert("下载失败: " + resp.error.localizedDescription);
  
              return;
  
            }
  

  
            if (resp.data) {
  
              $share.sheet(resp.data); // 分享图片数据
  
              $ui.toast("图片下载完成,已调起分享。");
  

  
              // 也可以选择保存到文件
  
              // const saveSuccess = $file.write({ data: resp.data, path: "downloaded_image.jpg" });
  
              // if (saveSuccess) $ui.toast("图片已保存到文件。");
  
              // else $ui.alert("图片保存失败。");
  

  
            } else {
  
              $ui.alert("未获取到图片数据。");
  
            }
  
          } catch (e) {
  
            $ui.loading(false);
  
            $ui.alert("操作异常: " + e.message);
  
            console.error("图片下载或操作错误:", e);
  
          }
  
        }
  
      }
  
    }
  
  ]
  
});
  

3. 获取图片列表并显示在 matrix(网格)中

这是一个更复杂的例子,结合了网络请求、JSON 解析和 matrix 控件的用法。

  
$ui.render({
  
  props: {
  
    title: "图片画廊",
  
    bgcolor: $color("systemBackground"),
  
    theme: "auto"
  
  },
  
  views: [
  
    {
  
      type: "matrix",
  
      props: {
  
        id: "imageMatrix", // 给 matrix 控件一个 ID
  
        columns: 3, // 每行 3 列
  
        itemHeight: 120, // 每个图片项的高度
  
        spacing: 5, // 项间距
  
        template: {
  
          // 定义每个图片项的视图模板
  
          views: [
  
            {
  
              type: "image",
  
              props: {
  
                id: "itemImage", // 模板中图片的 ID
  
                contentMode: $contentMode.scaleAspectFill, // 图片填充并裁剪
  
                clipsToBounds: true, // 裁剪超出部分
  
                cornerRadius: 8
  
              },
  
              layout: $layout.fill // 图片填充整个项
  
            },
  
            {
  
              type: "label",
  
              props: {
  
                id: "itemAuthor", // 模板中作者标签的 ID
  
                font: $font(10),
  
                textColor: $color("white"),
  
                align: $align.center,
  
                bgcolor: $rgba(0, 0, 0, 0.4) // 半透明背景
  
              },
  
              layout: (make) => {
  
                make.left.right.bottom.equalTo(0); // 位于项底部
  
                make.height.equalTo(20);
  
              }
  
            }
  
          ]
  
        },
  
        data: [], // 初始空数据
  
        actions: [ // 左滑动作
  
          {
  
            title: "作者",
  
            color: $color("systemBlue"),
  
            handler: (sender, indexPath, data) => {
  
              $ui.alert(`作者: ${data.itemAuthor.text}`);
  
            }
  
          },
  
          {
  
            title: "下载",
  
            color: $color("systemGreen"),
  
            handler: async (sender, indexPath, data) => {
  
              $ui.loading(true);
  
              try {
  
                const resp = await $http.download({ url: data.itemImage.src });
  
                $ui.loading(false);
  
                if (resp.error) throw new Error(resp.error.localizedDescription);
  
                if (resp.data) {
  
                  $share.sheet(resp.data);
  
                  $ui.toast("图片下载并分享完成!");
  
                }
  
              } catch (e) {
  
                $ui.alert("下载失败: " + e.message);
  
              }
  
            }
  
          }
  
        ]
  
      },
  
      layout: $layout.fill,
  
      events: {
  
        didSelect: (sender, indexPath, data) => {
  
          // 点击图片时预览大图
  
          $ui.preview({
  
            title: data.itemAuthor.text,
  
            url: data.itemImage.src // 使用原始 URL 进行预览
  
          });
  
        },
  
        pulled: async (sender) => { // 下拉刷新加载新页
  
          await loadImages(sender);
  
          sender.endRefreshing();
  
        },
  
        didReachBottom: async (sender) => { // 滚动到底部加载下一页
  
          await loadImages(sender, true);
  
          sender.endFetchingMore();
  
        }
  
      }
  
    }
  
  ]
  
});
  

  
let currentPage = 1; // 当前页码
  
const imagesPerPage = 30; // 每页图片数量
  

  
/**
  
 * 加载图片到 Matrix 列表
  
 * @param {Object} [sender] - 事件发送者 (用于下拉刷新/加载更多)
  
 * @param {boolean} [append=false] - 是否追加数据
  
 */
  
async function loadImages(sender, append = false) {
  
  if (!append) { // 如果不是追加,则重置页码
  
    currentPage = 1;
  
  }
  
  
  
  $ui.loading(true);
  
  try {
  
    const listUrl = `https://picsum.photos/v2/list?page=${currentPage}&limit=${imagesPerPage}`;
  
    const resp = await $http.get({ url: listUrl });
  
    $ui.loading(false);
  

  
    if (resp.error) {
  
      $ui.alert("加载图片列表失败: " + resp.error.localizedDescription);
  
      return;
  
    }
  

  
    const rawImages = resp.data;
  
    if (!rawImages || rawImages.length === 0) {
  
      $ui.toast("没有更多图片了。");
  
      return;
  
    }
  

  
    const matrixData = rawImages.map(img => ({
  
      itemImage: { src: img.download_url }, // 将 download_url 作为图片 src
  
      itemAuthor: { text: img.author } // 将作者作为标签文本
  
    }));
  

  
    const currentMatrix = $("imageMatrix");
  
    if (append) {
  
      // 获取当前数据并追加
  
      const existingData = currentMatrix.data.length > 0 ? currentMatrix.data[0].rows : [];
  
      currentMatrix.data = [{ rows: existingData.concat(matrixData) }];
  
    } else {
  
      currentMatrix.data = [{ rows: matrixData }];
  
    }
  
    currentPage++; // 增加页码,为下次加载做准备
  

  
  } catch (e) {
  
    $ui.loading(false);
  
    $ui.alert("加载图片异常: " + e.message);
  
    console.error("加载图片列表错误:", e);
  
  }
  
}
  

  
// 首次加载图片
  
loadImages();
  

最佳实践与提示:

  • URL 强制刷新: https://picsum.photos/200/300 这样的 URL 可能会被浏览器缓存。如果你想要每次点击按钮都获取一张全新的随机图片,可以在 URL 后添加一个不影响请求结果的随机参数,例如 https://picsum.photos/200/300?${Date.now()}

  • 缓存: 对于已经下载的图片,如果你需要重复使用,可以考虑使用 $cache$file 进行本地缓存,减少网络请求。

  • 错误处理: 始终对网络请求结果进行 resp.error 检查,并使用 try...catch 捕获 Promise 链中的错误。

  • 图片模式: contentMode: $contentMode.scaleAspectFillclipsToBounds: true 组合常用于网格布局,使图片填充整个区域并裁剪多余部分,达到美观的视觉效果。

  • 作者归属: 在公共项目或需要遵循版权协议的场景中,请确保为图片作者进行适当的归属。

通过这些示例,你可以充分利用 Lorem Picsum API 在 JSBox 中实现各种有趣的图片功能!