指南与教程 - 背景图片 | Rainy Design Studio

Next.js + Strapi + Tailwind CSS 建站教程 - 第二部分

RainyMay 26, 2026

本文章的版权归属 Rainy Design Studio - 雨点设计工作室 ,且最终解释权归站长所有。
除本站自媒体官号以外,本文的内容禁止任一组织、个人、账号或平台,以任何形式转载到 RainyDesign.cn 站外。
任何个人或组织进行非法转载的,本站工作人员可对其追究法律责任。

具体信息详见 条例与条款

Next.JS + Strapi + Tailwind CSS 全套网建实战教学 —— Strapi

通过 Strapi 搭建所有的组件、页面与数据类型,设置权限并填充必要的内容,以便开始接口测试。

章节回顾

我们在上一个章节已经做好了准备工作,课程的完整目录如下:

  1. 准备工作

    1. 准备工作:基本需求
    2. 准备工作:项目流程
    3. 准备工作:通读设计稿 + 数据与接口设计
    4. 准备工作:MySQL简介
  2. Strapi

    📌 当前位置
    1. Strapi:创建无头数据管理系统
    2. Strapi:管理数据库表结构
    3. Strapi:管理多媒体资源
    4. Strapi:填写内容、配置 API 权限并测试
    5. Strapi:REST API 讲解,实现增删改查及筛排分页
    6. Strapi:章节知识点汇总
  3. Next.JS

    1. Next.JS:创建项目并管理目录
    2. Next.JS:管理路由,搭建基础布局与页面
    3. Next.JS:API 函数与页面渲染(SSR、SSG、CSR)
    4. Next.JS:内建组件与资源引用
    5. Next.JS + Strapi:开发与数据传递
    6. Next.JS:章节知识点汇总
  4. Tailwind CSS

    1. Tailwind CSS:简介、安装、新特性与旧版本升级
    2. Tailwind CSS:示例、核心概念与演练
    3. Tailwind CSS:全局组件样式开发
    4. Tailwind CSS:主要页面布局实战
    5. Tailwind CSS:章节知识点汇总
  5. 细节完善

    1. React.JS (JSX) :使用 ReactMarkdown 插件美化正文
    2. Strapi + Next.JS + JSX:博客文章搜索
    3. Strapi + Next.JS + JSX:文章列表分页
    4. Next.JS:为 SSG 页面设置 ISR 以实现性能优化与预生成
    5. Strapi Lifecycles hooks:客户联络自动转发邮件
    6. Next.JS:自定义错误页面如 404、500
    7. Next.JS:创建 sitemap.xml 文件并自更新
  6. 网站部署 (撰写中)

    1. 网站部署:Cloudflare、Vercel或租赁云服务器(仍在撰写)

    2. 网站部署:注册域名 + SSL证书申请(仍在撰写)

    3. SEO:搜索引擎提交收录(仍在撰写)

  7. 资源与教程项目包下载

    点击此处下载,最后更新于:2026 年 5 月 26 日。为获取良好的学习体验,请务必以最新版本为主!
  8. FAQ(常见疑问解答)

二、Strapi

Hello 宝子们,我是Rainy,今天我们继续来讲解本课程的第二章:Strapi 的基本知识。

2.1 Strapi:创建无头内容管理系统

首先为大家介绍 Headless CMS 的概念:CMS 是 Content Management System 的缩写,所以 Headless CMS 就是“无头内容管理系统”;顾名思义, Headless CMS 不像传统的建站系统那样包含了网站前台,而是只提供数据管理后台和 API 接口,不包含前端展示层,以此管理接口、权限、Webhook、Token 等内容。

Strapi logo | Rainy Design Studio 雨点设计工作室

开始前,我们需要先理解 Strapi 必须关联数据库,创建项目时它将自动完成结构与初始内容配置。

温馨提醒下部分宝子,如果你在创建 Strapi 项目的时候疯狂报错,请注意 路径最好不包含中文字符和特殊符号,建议使用英文小写、 mysql 必须处于运行状态且已手动创建了名为 “my-project“ 的数据库。请报错的宝子仔细阅读 对应章节 中的内容并按顺序操作。
以下演示的版本是文档撰写时发布的稳定版本:Strapi v5.23.1。为了与教学体验一致,宝子们可以安装这个特定版本,否则下列内容中的 strapi-app 后面的 @... 可以不用输入。

以下内容以 ~/Documents/my-project 目录为例。确保以上内容后,请在终端输入:

Terminal
# 以下为终端命令行 cd ~/Documents # 回到用户的 Documents(文档)目录 mkdir my-project # 创建项目目录 cd my-project # 进入目录 npx create-strapi-app@5.23.1 strapi # 个人喜欢用 yarn,但是要安装特定版本必须用 npx,yarn 的命令为 yarn create strapi-app [project-name] (默认安装最新版)。具体请自查官方文档:https://strapi.io # 等待读条后出现以下选项 > Please log in or sign up. # 默认让你登录,直接跳过 Skip > Do you want to use the default database (sqlite) ? # 默认数据库是 SQLite,我们用 MySQL 所以 n n > Choose your default database client # 手动选择 MySQL mysql > Database name: # 这里要输入上个章节创建的数据库的名称 `my-project` > Host: (127.0.0.1) # 默认 [直接回车] > Port: (3306) # 默认 [直接回车] > Username: # 输入数据库的用户名 [Your mysql username] # (……宝子你不会没明白我意思吧?输入自己设置的 mysql 用户名) > Password: # 输入数据库的密码 [Your mysql password] # (同上) > Enable SSL connection? # 因为是本地部署所以暂时不用 SSL,后续是直接 http://127.0.0.1:1337 或 http://localhost:1337 访问本地 Strapi n > Start with an example structure & data? # 参考的数据结构与默认数据,默认为是 y > Start with Typescript? # 看着用,本教程不包含 Typescript 所以 n n > Install dependencies with npm? # 默认为是,也就会直接安装所有依赖 y > Initialize a git repository? # 默认为是,看着用 y > Participate in anonymous A/B testing (to improve Strapi)? # 默认为是,不想看 Strapi 用调的可以 n(Strapi 会偶尔弹出提示,但并不频繁)。 y # 等待读条完毕后显示 "Strapi Your application was created!" 并打印命令后继续 cd strapi # 进项目目录 npm install # 如果上一步没有安装依赖,则需要此时安装 npm run dev # 启动项目;之后也可以用 yarn dev 启动项目。

Okay,现在系统会自动切到你的默认浏览器并打开新标签页,以显示 Strapi 的注册界面。

Strapi 登录注册页面 | Rainy Design Studio 雨点设计工作室

Strapi 欢迎页

现在我们得先登录。因为是本地系统,所以账号密码也请自设:

Strapi 登陆注册页面 2 | Rainy Design Studio 雨点设计工作室

创建你的账户并点选按钮开始

可能会弹出一个职业询问框,随便选一个职业点确认,之后就会如下图所示来到 Strapi 的欢迎页:

Strapi 欢迎页 | Rainy Design Studio 雨点设计工作室

Strapi 欢迎页

这里简单介绍下 Strapi 的各个页面和功能:

页面名称英文功能与说明
主页Home欢迎、指南、事项、最后编辑、数据指标等
内容管理器Content Manager管理创建的各项数据结构中的内容
媒体库Media Library存储静态内容,它们都会被存放到项目下的 /public/uploads 目录中
内容类型构建器Content-Type Builder管理数据结构,仅在开发模式下(yarn run develop)可用,用于管理数据结构与接口
部署DeployStrapi 提供了官方付费托管方案,不过我们也可以用 CLI 自行部署,具体下述
插件广场MarketplaceStrapi 官方社区有很多适配版本的插件,可在这里查阅并安装
设置Settings管理各项设置

点进每个页面看一下,因为我们在创建 Strapi 项目的时候于 Start with an example structure & data? 选择了是,所以此处会发现 Strapi 已经默认设置了 Article、Author、Category、User 四个 Collection types,以及 About、Global 两个 Single types,并上传了一些图片到媒体库中,同时在组件分类下创建好了 Shared 目录与各个组件;如果选否则没有以上预设参考内容。

常见问题解决

  • 如果 Strapi 安装或启动失败:
    • 安装时提示 node 版本号不正确;

    切换 Node.JS 至合适的运行环境

    • 查看 MySQL 数据库是否正在运行;

    Unix OS:brew services start mysqlmysql.server start ,Windows OS:net start mysql

    • 检查数据库账号密码是否对应;

    终端打 root -u _username_ -p,输入密码登陆后输入 SHOW DATABASES 查看

    • 是否错误启用了 SSL 连接。

    不确定的话就重新走一遍 Strapi 安装流程。

如仍未解决问题,请查阅 Strapi 使用指南 - 故障排查 了解更多排障方案。

2.2 Strapi:管理组件与字段

本节我们将讲述如何通过 Strapi 直接管理上个章节创建的数据库。我们先点击左侧菜单栏的第二个图标(羽毛)访问 content manager。如图所示,由于先前在 参考的数据结构与默认数据 (Start with an example structure & data?) 这一项中默认选择了“是”,所以一些常见页面都已经自动创建好了:

Strapi Content Manager - 内容管理器 | Rainy Design Studio 雨点设计工作室

Strapi Content Manager - 内容管理器

不过对应我们的 字段列表文档 所需的页面结构还需要手动创建一些,现在请访问内容类型构建器(左侧菜单栏第四个图标)进行数据结构管理。

Strapi Content-Type Builder - 内容类型构建器 | Rainy Design Studio 雨点设计工作室

Strapi Content-Type Builder 内容类型构建器

我们先了解一下左侧第二个侧边栏中的两种类型区别:集合类型 (Collection types) 、单一类型 (Single types) 与组件 (Components) 。众所周知,一个网站上可能会有很多博客文摘,以及对应的标签与作者,但关于我们、条款政策、联络、主页等页面通常只有一个,且导航与页尾也是通用的,所以我们可以对应 字段列表文档 中的数据结构,将各项数据表分类好:

Pages

Collection types


  • Article
  • Author
  • Category
  • Contact
  • Subscription

Single types


  • Global
  • Home
  • Course
  • Blog
  • About

Components

Course


  • Courses
  • Specialized courses
  • Specialized courses contents

Global


  • About Us
  • Contact
  • Footer
  • Information
  • Meta
  • Navigation
  • Social
  • Subscription

Home


  • Comparison content
  • Comparison detail list
  • Comparison informations
  • Frameworks
  • Guide chapter content
  • Introduction
  • Playground contents

Shared (default)


  • Media (default)
  • Quote (default)
  • Rich text (default)
  • Seo (default)
  • Slider (default)

2.2.1 Strapi:创建全局组件

接下来,我们就要边参考 字段列表文档,边将 Strapi 中的每个页面填充起来。不过在此之前,我们需要先将数据类型创建并封装在各自的组件下,以便于后续管理以及全局调用。结合设计稿与字段列表文档来看,我们会发现全页有一组调用率非常高的数据类型,所以我们将其封装成一个专属子组件——Information ;它包含了常用的 heading、description、buttonText、buttonLink、openInNewTab、image 这六项字段,现在一起实操一下:

点击左侧 Components 栏目的加号创建一个新组件,以 Information 为例:

Strapi Components - 创建组件 | Rainy Design Studio 雨点设计工作室

在弹出的窗口中,在组件显示名一栏下输入 Pascal Case 的 Information ,然后在右侧的目录中选择 global 以分类到全局目录下,再选择一个图标继续:

Strapi Components - 创建组件 2 | Rainy Design Studio 雨点设计工作室

接下来我们需要在 Information 组件中点击 Add new field,然后在弹出窗口中为该组件添加一个名为 heading 的 text 数据类型,随后默认 Short text 不做修改,点击窗口右上角的 Advanced Settings 选项卡,切换至高级设置并勾选 Required field,以及将默认内容粘贴到 Default value 一项中来:

注意:与页面、组件显示名 (Display name) 不同,数据字段名称必须遵循 camelCase 命名规则(首字母小写的驼峰命名),以避免后续接口调用时出现错误。

Strapi Components - 创建数据类型:text | Rainy Design Studio 雨点设计工作室

Strapi Components - 创建数据类型:text - 高级设置 advanced settings | Rainy Design Studio 雨点设计工作室

现在请继续创建下一个数据字段 description。作为一个长文本类型,这里要选择 Long text,也同样需要设置 Required field:

Strapi Components - 创建数据类型:long text | Rainy Design Studio 雨点设计工作室

Strapi Components - 创建数据类型:long text - 高级设置 advanced settings | Rainy Design Studio 雨点设计工作室

我们可以点击 Add another field 连续创建下一个字段,无需每次都确认保存,将 buttonText、 buttonLink 依次创建好,且可以在高级设置里头为 buttonText 设置对应的默认值(Start Guide >>)。注意与组件显示名不同的是,这些数据字段均需遵循 camelCase 命名规则:

Strapi Components - 创建数据类型:text 2 | Rainy Design Studio 雨点设计工作室

Strapi Components - 创建数据类型:text 3 | Rainy Design Studio 雨点设计工作室

接下来继续创建名为 openInNewTab 的 Boolean 类型,顾名思义用于控制终端点击按钮时是否打开新标签:

Strapi Components - 创建数据类型:boolean | Rainy Design Studio 雨点设计工作室

这里依然为必填项,如果仅站内跳转,默认值可以给个 false,如跳出站外建议设置为 true:

Strapi Components - 创建数据类型:boolean - 高级设置 advanced settings | Rainy Design Studio 雨点设计工作室

紧接着是入站背景图片 image 的设置,这是一个媒体类型,我们选择 media ,且由于我们只需要用到一张图片,所以选择 Single media:

Strapi Components - 创建数据类型:media | Rainy Design Studio 雨点设计工作室

在高级设置中仅允许图片类型:

Strapi Components - 创建数据类型:media - 高级设置 advanced settings | Rainy Design Studio 雨点设计工作室

点击 Finish 提交之后我们可以点左上角 Save 进行保存,此时 Strapi 会自动重新构建并刷新页面以应用更改(迟迟没有反应比如白屏的话可以手动刷新页面):

Strapi Components - 创建数据类型:保存调整 | Rainy Design Studio 雨点设计工作室

刷新页面后,我们能看到新的组件 Information 已于 Global 目录下添加:

Strapi Components - 刷新查看改动 | Rainy Design Studio 雨点设计工作室

之后添加好用于 HTML head 结构的 Meta,以及全局使用的关于信息 About Us 、联络 Contact 、页尾 Footer 、导航 Navigation 、社媒 Social 以及订阅 Subscription ,可以一并完成,稍后一次性提交。其中创建 About Us 时需注意与 Information 大致相同,但 Image 是 Multiple media 即复数类型,且为必填项:

Strapi Components - 创建数据类型:multiple media | Rainy Design Studio 雨点设计工作室

此外可以按住并拖动左侧的排序按钮变动组件或字段排序:

Strapi Components - 改变组件或字段排序 | Rainy Design Studio 雨点设计工作室

而创建 Contact 这一组件时出现了 enum 这一类型,这里我们直接在 value 一项中通过换行区分不同类型即可:

Strapi Components - 创建数据类型:enum | Rainy Design Studio 雨点设计工作室

还需注意部分组件需要在高级设置中设置最大字符长度,比如 Meta 中的 metaTitle 与 metaDescription:

Strapi Components - 字符长度限制 | Rainy Design Studio 雨点设计工作室

此外,新建的组件会显示 New(左侧显示为绿色的 N,下同),有变动的组件会显示 Modified,删除组件则会提示 Deleted,保存时各项改动为一次性提交至Strapi,等待重启即可保存变动,具体方法同先前讲解的添加已有的组件:

Strapi Components - 保存变动 | Rainy Design Studio 雨点设计工作室

对内容变动不满意的话还可以点击左侧栏目右边的菜单键,在下拉菜单中选择撤销上一步变动:

Strapi Components - 撤销上一步变动 | Rainy Design Studio 雨点设计工作室

至此全局组件均已添加完毕,接下来开始搭建页面数据结构。

Strapi Components - 所有组件已创建完成 | Rainy Design Studio 雨点设计工作室

2.2.2 Strapi:创建单一类型数据结构

我们先配置全局数据结构,这些数据将在所有页面中可用。

打开 Single type 下的 Global 页面,我们会发现其默认创建好了几种数据类型,并调用了 Strapi 示例创建的 Shared 目录下的 Seo 组件(自带的内容可以先留着不删用于测试),我们直接添加 globalAddOn 与 globalMetaInjection 两种数据类型:

Strapi Single Types - 全局 - 添加数据类型 | Rainy Design Studio 雨点设计工作室

接下来我们来调用先前设置好的组件,此处以 Footer 为例,点击 Use an existing component 并继续,在窗口步骤 2/2 内命名为 footer ,并于右侧菜单 Select a component 中下拉选择 global - Footer ,然后选择类型为 Single component,最后不要忘了在 Advanced Settings 中勾选必填项:

Strapi Single Types - 全局 - 创建数据类型:调用组件 | Rainy Design Studio 雨点设计工作室

Strapi Single Types - 全局 - 创建数据类型:调用组件:步骤 2 | Rainy Design Studio 雨点设计工作室

Strapi Single Types - 全局 - 创建数据类型:调用组件:高级设置 | Rainy Design Studio 雨点设计工作室

再将先前创建好的其他组件如 Navigation 、 Contact 、 Social 、 About Us 、 Subscription 悉数调用:

Strapi Single Types - 全局 - 完成设置 | Rainy Design Studio 雨点设计工作室

这样全局数据就告一段落了,现在开始管理单一数据类型,先从 主页 (Home) 开始进行举例,请点击左侧 Single types 栏目的加号,在弹出的窗口中于 Display name 内输入 Home,其他内容默认不做修改,点击 Continue 按钮以继续创建:

Strapi Single Types - 创建主页 | Rainy Design Studio 雨点设计工作室

Strapi Single Types - 创建主页 2 | Rainy Design Studio 雨点设计工作室

接下来我们需要为主页添加一些专属组件。首先是 introduction ,我们点击 Add new field 然后在弹出窗口的最下方找到 Component:

Strapi Single Types - 主页 - 创建数据类型 | Rainy Design Studio 雨点设计工作室

这里的第一步和直接创建组件相同,直接在页面中创建组件时也会在 Components 中生成对应的新组件,所以我们需要采用 Pascal Case 将其命名为 Introduction ,并分类到新的 home 目录下:

Strapi Single Types - 主页 - 创建新组件 | Rainy Design Studio 雨点设计工作室

下一步则和调用相同——选择类型为 Single component,最后不要忘了在 Advanced Settings 中勾选必填项:

Strapi Single Types - 主页 - 调用组件 | Rainy Design Studio 雨点设计工作室

Strapi Single Types - 主页 - 调用组件 - 高级设置 | Rainy Design Studio 雨点设计工作室

点击 Add first field to the component 后为其添加数据类型:

Strapi Single Types - 主页 - 为新组件添加数据类型 | Rainy Design Studio 雨点设计工作室

搞定 Introduction 之后,接下来的 Frameworks 也是相同的逻辑,其区别只在于第二步需要选择 Repeatable Components 类型,再于 Advanced Settings 中设置数量限制,最小与最大均为 6 :

Strapi Single Types - 主页 - 创建复用组件 | Rainy Design Studio 雨点设计工作室

Strapi Single Types - 主页 - 创建复用组件 - 高级设置 | Rainy Design Studio 雨点设计工作室

紧接着的 comparisons 引用的是 Global - Information 这个全局组件:

Strapi Single Types - 主页 - 调用全局组件 | Rainy Design Studio 雨点设计工作室

接下来讲讲包含两层后代组件的父组件 Comparison informations ,它的结构关系为:

  • comparisonInformations (Home - Comparison informations)
    • contents (Home - Comparison content, repeatable; min:3; max:3)
      • detailList (Home - Comparison detailrlist, repeatable)

我们先将父组件 Comparison informations 的数据类型创建好,直到需要创建子组件 Comparison contents 为止:

Strapi Single Types - 主页 - 创建父组件 | Rainy Design Studio 雨点设计工作室

我们将其调用并命名为言简意赅的 contents ;由于这是个可复用组件,我们可以将其最大与最小数量均限制为 3 个以匹配项目需求:

Strapi Single Types - 主页 - 创建子组件 | Rainy Design Studio 雨点设计工作室

Strapi Single Types - 主页 - 创建子组件 - 高级设置 | Rainy Design Studio 雨点设计工作室

现在我们将为子组件 Comparison content 创建数据字段,调用并命名为 contents。需注意其中各项字段的参数,如 ratings 与 downloads 均限制了字符串长度最大为 5 :

Strapi Single Types - 主页 - 为子组件创建数据类型 | Rainy Design Studio 雨点设计工作室

Strapi Single Types - 主页 - 注意设置参数 | Rainy Design Studio 雨点设计工作室

到了 detailList 这一项,我们需要为其创建 Comparison detail list 子组件,调用并命名为 detailList ;

Strapi Single Types - 主页 - 进一步创建孙组件 | Rainy Design Studio 雨点设计工作室

Strapi Single Types - 主页 - 在子组件中调用孙组件 | Rainy Design Studio 雨点设计工作室

完成的结构如图所示:

Strapi Single Types - 主页 - 组件层级关系 | Rainy Design Studio 雨点设计工作室

接下来的 guideChapters 引用的也是 Global - Information 这个全局组件:

Strapi Single Types - 主页 - 调用全局组件 2 | Rainy Design Studio 雨点设计工作室

确认无误后可以先保存一下,然后继续完成余下的数据类型。接下来的 guideChapterContents 、playground 、 playgroundContents 、seo 均没有新的知识点了,多做练习巩固一下:

Strapi Single Types - 主页 - 创建数据类型:主页已完成 | Rainy Design Studio 雨点设计工作室

完成主页后,我们按导航顺序的 Home - Course - Blog - About 来陆续完成其他页面。不过由于本项目的字段列表是事先设计好的,所以可以一口气在组件列表中创建余下的所有组件再行引入:

Strapi Single Types - 优先创建组件 | Rainy Design Studio 雨点设计工作室

Strapi Single Types - 分别引入分页 | Rainy Design Studio 雨点设计工作室

进行到 Blog 页面时出现了新字段类型 relation ,这些字段需要选择一些关联数据,其中 articlesOfTheDay 、 articlesOfTheDay2 为一对一的每日推荐文章,而推荐类目 featuredCategories 则为一对多:

Strapi Single Types - 关联数据引用 - one way | Rainy Design Studio 雨点设计工作室

Strapi Single Types - 关联数据引用 - many way | Rainy Design Studio 雨点设计工作室

最后是 About 页面内容,因为改动较大,所以需要将原有的字段全部删除并重新填写:

Strapi Single Types - 关于页面 | Rainy Design Studio 雨点设计工作室

这样一来所有单页类型的字段设置就都完成了。

再次提醒:页面与组件的显示名建议 Pascal Case 以匹配 Strapi 自动创建的组件名称、确保规范的一致性,多个词汇之间也可以用空格,但于页面中调用时的数据接口相关名称——如此处提到的 introduction 必须为 Camel Case 。

Strapi Single Types - 主页 - 调用组件:注意与 Strapi 默认规范对齐 | Rainy Design Studio 雨点设计工作室

上图所示,蓝框为 Pascal Case 的组件命名,红框为 Camel Case 的组件字段

2.2.3 Strapi:调整字段布局

Okay,现在让我们回到 Content Manager 页面,确认 Home 是否已创建好并正确地显示了所有组件与字段:

Strapi - 确认组件与字段 | Rainy Design Studio 雨点设计工作室

内容正确,但布局看起来有点乱,此时我们需要点击右上角的菜单按钮,在下拉菜单中选择 Configure the view 进行布局管理:

Strapi - 调整组件与字段布局 | Rainy Design Studio 雨点设计工作室

我们会发现在这里无法直接控制名为 introduction 的组件中的字段布局,需要点下面的 Set the component's layout 来到组件布局页:

Strapi - 调整组件与字段布局 - 设置组件布局 | Rainy Design Studio 雨点设计工作室

在这里我们可以自由地排列组件与其中字段的顺序,并点选编辑按钮进行大小控制以及显示 placeholder 与 description,或是切换字段启用状态:

Strapi - 调整组件与字段布局 - 设置组件布局 2 | Rainy Design Studio 雨点设计工作室

按照你喜欢的布局进行调整并保存即可,再回到 home 页面查看下布局变动:

Strapi - 调整组件与字段布局 - 保存组件布局 | Rainy Design Studio 雨点设计工作室

Strapi - 调整组件与字段布局 - 查看结果应用 | Rainy Design Studio 雨点设计工作室

确认无误后,可以回到布局修改页面根据自己喜好改动所有布局并保存验证:

Strapi - 调整组件与字段布局 - 完成并验证 | Rainy Design Studio 雨点设计工作室

可按需为部分字段添加占位符以及标注,如可为 metaKeyword 添加使用逗号拆分关键词说明:

Strapi - 为字段添加占位符及标注 | Rainy Design Studio 雨点设计工作室

如有必要甚至可以将部分字段设置为不可编辑(即只读),以便提交内容或按照缺省值设置后锁定内容:

Strapi - 设置字段为不可编辑(只读) | Rainy Design Studio 雨点设计工作室

Strapi - 设置字段为不可编辑(只读) - 查看结果应用 | Rainy Design Studio 雨点设计工作室


至此主页的组件与其中的字段也以创建完毕,接下来我们可以参考 Strapi 使用指南 - 字段列表 创建所有类型的页面组件与其中的字段,并管理各页面和组件的视图设置。请于全部完成后继续下一节课程内容。

2.3 Strapi:管理多媒体资源

点击左侧菜单栏的第三个按钮以打开媒体库,先前已经提到过,在配置阶段的参考内容选择了"是"的话,这里会默认上传一些图片。不过无论有没有这些图片,我们都需要为内容分个类,点击右上角的 Add new folder 按钮创建一个文件夹。

Strapi Media Library - 创建文件夹 | Rainy Design Studio 雨点设计工作室

Strapi Media Library - 创建文件夹 - 命名 | Rainy Design Studio 雨点设计工作室

为了便于排序,我们需要依次创建带有序号的 0. Global4. About Us3. Blog2. Course1. Home,如图所示:

Strapi Media Library - 文件夹已创建 | Rainy Design Studio 雨点设计工作室

我们可以再在 0.Global 目录下新建一个 0. Temp 目录,用于将 Strapi 自带的 11 张图片存储进来,之后一些临时图片也可以上传到这里:

Strapi Media Library - 创建临时文件夹 | Rainy Design Studio 雨点设计工作室

图片有 11 张,但媒体库页面默认每页仅显示 10 张,我们可以让一页显示的图片更多一点,在页面滚动到底部,于下方左侧 [number] Entries per page 中调整到 20 张 / 每页:

Strapi Media Library - 调整每页显示的内容(临时) | Rainy Design Studio 雨点设计工作室

一张张手动勾选有点麻烦,我们可以点击右上角工具栏中的第二个按钮,将布局切换为列表模式,方便我们全选所有图片:

Strapi Media Library - 切换显示布局 | Rainy Design Studio 雨点设计工作室

工具栏中的设置按钮(齿轮图标)可用于修改排序方式和调整每页显示的文件数量。选择完毕后将图片移动到 0. Global - 0. Temp 目录下:

每页显示大量媒体文件会增加页面加载时间和内存使用,特别是包含大量高分辨率图片时。所以考虑到部署需求,建议根据服务器配置和网络环境合理设置显示数量,不宜修改默认每页显示过多,主要还是要规范命名便于查找分类媒体资源。

Strapi Media Library - 移动至目录 | Rainy Design Studio 雨点设计工作室

Strapi Media Library - 查看目录 | Rainy Design Studio 雨点设计工作室

媒体资源会存放于 Strapi 项目的 /public/uploads 目录下,且不会随着 Strapi 创建文件夹自行分类。这是考虑到便于管理 Strapi 媒体库文件夹与静态内容,而将所有文件平铺于单个层级;上传文件时,Strapi 会自动为文件添加基于时间戳与哈希算法的命名,以确保文件名的唯一性,且图片会自动生成多种尺寸规格(如缩略图、小图、中图、大图),以适应不同使用场景。

Strapi Media Library - 媒体资源存放目录 | Rainy Design Studio 雨点设计工作室

然后是上传文件,点击右上角的 Add new assets 会弹出一个拖拽上传窗口:

Strapi Media Library - 从本地上传内容 | Rainy Design Studio 雨点设计工作室

我们可以从本地上传一些内容,或是点击 From URL 选项卡从网络地址获取内容:

Strapi Media Library - 通过 URL 上传内容 | Rainy Design Studio 雨点设计工作室

确认文件后它们会被暂存到等待列表,我们可以将鼠标悬停在上面显示删除按钮,也可以点击编辑资源信息:

Strapi Media Library - 上传等待列表 | Rainy Design Studio 雨点设计工作室

在资源细节窗口中,我们除了删除、下载、复制链接以及裁剪图片外,还可以查看资源信息、修改文件名称、设置 Alt 值与说明,还可直接将其分类到特定目录下:

Strapi Media Library - 资源细节 | Rainy Design Studio 雨点设计工作室

点击右下角的 Finish 结束调整并保存,回到等待列表并点击右下角的 Upload * asset(s) to the library 以开始上传:

Strapi Media Library - 文件上传中 | Rainy Design Studio 雨点设计工作室

如需替换文件而非删除,可点击 Replace Media 替换图片,这样可以确保之前在 Strapi 中引用该文件的内容不会丢失资源链接:

文件替换机制:替换文件时,新文件会覆盖原文件并保持相同的文件名和 URL,但会更新文件的元数据(如大小、修改时间等)。这确保了所有引用该文件的内容都能自动显示新文件。

Strapi Media Library - 资源细节 - 替换按钮 | Rainy Design Studio 雨点设计工作室

这样一来我们就将文件上传到 Strapi 的 /public/uploads 目录下,并可以通过 URL 访问了:

Strapi Media Library - 资源细节 - 复制链接 | Rainy Design Studio 雨点设计工作室

Strapi Media Library - 通过 URL 在浏览器中预览资源 | Rainy Design Studio 雨点设计工作室

为确保课程的顺利进行,我们需要下载 课程资源包 并解压内容,然后按文件夹分类上传至 Strapi:

Strapi Media Library - 查看本地资源 | Rainy Design Studio 雨点设计工作室

请于上传完毕后继续下一节课程内容。

2.4 Strapi:填写内容、配置 API 权限并测试

本小节我们需要填写内容、设置好接口的访问权限,并介绍一些工具便于测试数据接口。

2.4.1 Single type 单一类型

先让我们从全局(Global)开始填写内容,先前采用预设参考值的话,这里会有 siteNamefaviconsiteDescriptiondefaultSeo 这些字段且填写好了测试内容,不过无论有无这些字段,我们都应该在下面追加好了 globalAddOnglobalMetaInjectionnavigationfootercontactsocialaboutUssubscription 这些组件与其中的字段:

Strapi - 填写内容 - Global - 默认字段 | Rainy Design Studio 雨点设计工作室

现在我们一个个填写过来,首先 globalAddOn 顾名思义是全站附加值,比如 meta title 、image alt 都会用到一个网站后缀,格式如 “Next.JS + Strapi + Tailwind CSS 全套建站指南 | Rainy Design Studio 雨点设计工作室”,那么这里的“ | Rainy Design Studio 雨点设计工作室”就是一个重复性的、常见的全站附加值;一个近在眼前的例子是,我们可以将鼠标悬停到下图稍作等待来查看图片 Alt 值:

Strapi - 填写内容 - Global - 自设字段 | Rainy Design Studio 雨点设计工作室

这里填写 globalAddOn 有助于 SEO 的规范性,能一键修改全站附加值,这大大减少了编辑图片 Alt 值的繁复性;下一个 globalMetaInjection 则是用于 Gtag 或 Meta Pixel 等需要全站 meta 注入 script 的预留字段项。可提到如此重要的字段,违反直觉的一点却是:这其实并不是一个必填选项,至少在测试阶段不需要,且修改这两项对于 Next.JS 的 SSG 而言意味着需要一次 rebuild,我们会在后续的课程中着重讲解 Next.JS 的 SSG 。

接下来的内容就显得很直白了——这里我们点击 footer 的添加按钮,如果你在本文小节 2.2.1 Strapi:创建全局组件 章节中按照流程所示,于内容类型构建器中为该组件设置了默认值,系统便会自动填充这些内容:

Strapi - 填写内容 - Global - 自动填充缺省值 | Rainy Design Studio 雨点设计工作室

Strapi Content-Type Builder - 内容构建器 - 设置字段默认值 | Rainy Design Studio 雨点设计工作室

接下来继续填写 contact 和 social ,此处因为都是 Repeatable Component,所以可以连续创建多项;不过它们可能不以 type 作为入口名称(Entry title),而是默认拿取了 text 的值做显示:

Strapi - 填写内容 - Global - 组件入口名称需做调整 | Rainy Design Studio 雨点设计工作室

现在编辑它需要跳转到布局页面,这会导致没有保存的改动丢失,所以我们需要先把 aboutUs 和 subscription 填好,然后点击 save 保存,再回来处理这一问题:

Strapi - 填写内容 - 临时保存内容 | Rainy Design Studio 雨点设计工作室

这是由于 Strapi 预设的页面类型没有于高级设置中启用 Draft & publish (草稿与发布)导致的,这会使得所有内容在保存时立即发布,无法保存为草稿状态;所以在必填选项尚未填写完毕的情况下无法保存,如下图所示:

Strapi - 填写内容 - 未启用草稿无法临时保存 | Rainy Design Studio 雨点设计工作室

Strapi 报错,并自动填充了上一次提交的内容

如需启用该选项,请跳转至 Content-Type Builder ,点击页面后点击右上角的 Edit 按钮,并于弹出的窗口中选择 Advanced Settings 选项卡,再勾选该选项并提交保存即可。

Strapi - 填写内容 - 启用草稿与发布 | Rainy Design Studio 雨点设计工作室

接下来我们为组件设置正确的入口名称。通过点击右上角下拉菜单中的 Configure the view 打开布局页面,滚动到 contact 与 social 组件,然后点击 Set the component‘s layout 打开组件的布局页面:

Strapi - 调整组件布局 - 修改入口名称 | Rainy Design Studio 雨点设计工作室

我们能看到最上方的 Entry title 选中了 text,这里我们需要手动将其调整为 type 然后在右上角保存继续,这样回到 Global 页面中再次填写数据就会以 type 作为显示名称了:

Strapi - 调整组件布局 - 查看入口名称应用 | Rainy Design Studio 雨点设计工作室

接下来将内容陆续填好,暂时留空的部分比如链接可以填个 / ,点击 Save 保存提交,然后 Publish 一下,没有错误或漏填的话就可以顺利发布了:

Strapi - 填写内容 - 保存成功并发布 | Rainy Design Studio 雨点设计工作室

So far so good,接下来继续完成其他 Single types 的内容填写,一些暂时没有数据的部分比如链接可以直接填写 / ,文字或富文本类型则可以先填入 Lorem ipsum 这类假字,图片也可以直接拿媒体资源库中 0. global - 0. temp 目录下的任意图片暂作测试,先 Save 然后点 Publish 检查是否有遗漏字段,依次填完后我们就可以对内容做测试了。

文字与图片资源均已打包在了 课程资源包 之中,请解压后使用 课程资源包/网站资源/ 下的内容。

Strapi - 填写内容 - 其他内容填写参考 - About | Rainy Design Studio 雨点设计工作室

Strapi - 填写内容 - 其他内容填写参考 - Blog | Rainy Design Studio 雨点设计工作室

Strapi - 填写内容 - 其他内容填写参考 - Course | Rainy Design Studio 雨点设计工作室

Strapi - 填写内容 - 其他内容填写参考 - Home | Rainy Design Studio 雨点设计工作室

2.4.2 Collection type 集合类型

参考用的数据结构与默认数据已经足够做测试了,所以我们暂时不需要填写。

Collection type 显示的是一个列表,此处以博客文章 Article 为例:

Strapi - 填写内容 - 合集页面列表 | Rainy Design Studio 雨点设计工作室

我们也可以通过点击工具栏上的小齿轮打开显示设置菜单:

Strapi - 填写内容 - 合集页面列表 - 显示设置菜单 | Rainy Design Studio 雨点设计工作室

与先前媒体资源库中显示图片数量的逻辑一样,在该菜单中直接切换字段的显隐并不会保存,如需设置并保存排序规则、页面文档数量与字段的显隐,则需要点击 Configure the view 打开显示配置页面:

Strapi - 填写内容 - 合集页面列表 - 显示配置页面 | Rainy Design Studio 雨点设计工作室

我们可以如图所示将文章按照日期倒序排序,并显示文档 id 、标题、作者、封面与创建日期,然后保存查看:

Strapi - 填写内容 - 合集页面列表 - 显示设置已修改 | Rainy Design Studio 雨点设计工作室

OK,这样就设置好了,然后来测试一下查找功能:

Strapi - 填写内容 - 查找文档 | Rainy Design Studio 雨点设计工作室

再来设置两个筛选条件:

Strapi - 填写内容 - 筛选文档 | Rainy Design Studio 雨点设计工作室

再分别进入 id 为 2,3,4 的文档并发布,以用作下文的 API 测试:

Strapi - 填写内容 - 文档发布状态 | Rainy Design Studio 雨点设计工作室

筛选与查找条件将会在切换集合类型后失效。

除此以外,我们还需要添加 Contact 与 Subscription 类型以作用户数据收集:

Strapi - 填写内容 - 新增集合类型 - Contact | Rainy Design Studio 雨点设计工作室

Strapi - 填写内容 - 新增集合类型 - Subscription | Rainy Design Studio 雨点设计工作室

最后在 Article 与 Category 两个集合类型下方添加 seo (Global - Meta) 组件:

Strapi - 设置字段 - 修改集合类型 - Article | Rainy Design Studio 雨点设计工作室

Strapi - 设置字段 - 修改集合类型 - Category | Rainy Design Studio 雨点设计工作室

不要忘了进入两者的文档并保存 / 发布内容:

Strapi - 填写内容 - 保存集合类型 - Article | Rainy Design Studio 雨点设计工作室

Strapi - 填写内容 - 发布集合类型 - Article | Rainy Design Studio 雨点设计工作室

Strapi - 填写内容 - 修改集合类型 - Category | Rainy Design Studio 雨点设计工作室

Strapi - 填写内容 - 保存集合类型 - Category | Rainy Design Studio 雨点设计工作室

2.4.3 设置公共 API

完成以上内容后,我们需要去设置中对部分接口开放访问:点击左侧菜单栏的 Settings 访问设置页面,菜单滚动到最下方的 Users & Permissions Plugin 查看用户与权限功能,点击 Roles 打开角色窗口,再点击 Public 查看公共角色组,我们能看到所有的接口权限陈列于下方:

Strapi - 设置 - 角色与权限 | Rainy Design Studio 雨点设计工作室

如我们在创建项目时启用了预设参考,则这里部分的接口权限已经设置好了,为做数据测试我们先点击 Global 展开内容,确保 find 已勾选,然后临时勾选下 update 做测试,点一下右侧的小齿轮可以查看 API 路由,然后在右上角点 Save 保存:

Strapi - 设置 - 角色与权限 - 设置公共接口 | Rainy Design Studio 雨点设计工作室

OK,现在我们就可以通过 REST API 直接访问 Global 的数据了 (http://127.0.0.1:1337/api/global ):

Strapi - 用浏览器访问接口 | Rainy Design Studio 雨点设计工作室

我们可以看到收到的 JSON 响应的 data 对象中除了自定义的字段数据外,还包含了系统自动生成的元数据字段 iddocumentIdcreatedAtupdatedAtpublishedAt 这些隐藏内容,它们对于 Collection type 来说至关重要,会在后续课程中为宝子们陆续讲解。

现在继续说说如何测试接口;相信很多宝子们对 Postman 很熟悉,这里 Rainy 就不多做讲解了,B 站教程也相当的多;但如果你对新工具感兴趣的话,这里我便拿 Insomnia 作示范:

Strapi - API 测试 - Insomnia 主界面 | Rainy Design Studio 雨点设计工作室

先 Get 一下数据做确认:

Strapi - API 测试 - Insomnia GET | Rainy Design Studio 雨点设计工作室

由于先前我们为 Global 启用了 update ,所以我们可以直接将数据 PUT 过去,此处将 Body 设置为 JSON 类型单传一项键对值即可:

Strapi - API 测试 - Insomnia PUT | Rainy Design Studio 雨点设计工作室

可以看到接口回传的数据已修改成功;接下来请回到 Strapi 中的 Settings - Users & Permissions Plugin - Roles - Public 页面,将各页面的权限按照下表设置:

页面名称页面类型权限设置说明
AboutSingle typefind关于我们 - 单页,公共权限为仅读取
ArticleCollection typefind; findOne博客文章 - 合集,公共权限为读取列表及内容
AuthorCollection typefind; findOne作者 - 合集,公共权限为读取列表及内容
BlogSingle typefind博客,公共权限为仅读取
CategoryCollection typefind; findOne分类 - 合集,公共权限为读取列表及内容
ContactCollection typecreate联络 - 合集,公共权限为仅提交创建
CourseSingle typefind课程 - 单页,公共权限为仅读取
GlobalSingle typefind全局内容 - 单页,公共权限为仅读取
HomeSingle typefind主页 - 单页,公共权限为仅读取
SubscriptionCollection typecreate订阅 - 合集,公共权限为仅提交创建

其余内容均不做改动,修改完毕后点 Save 保存。

2.5 Strapi:常用 API 讲解,实现增删改查及筛排分页

由于我们是基于 HTTP 标准考量整个项目的开发逻辑,搭建一个网站而非一个 H5 应用,所以相对于 GraphQL ,我们更建议选用 REST API 进行前端开发。以下是 Google Gemini 给出的 API 对比结论:

功能如果出现以下情况,请选择 REST如果出现以下情况,请选择 GraphQL
数据获取您的数据需求简单且可预测,并且资源从不同的 URL 获取。可以对相关数据发出多个请求。您需要在单个请求中获取复杂、嵌套或相关的数据。这对于最大限度地减少往返次数非常理想,从而有利于提高数据密集型应用的性能。
API 结构您更喜欢更简单、面向资源且具有多个不同端点的架构。这符合 HTTP 标准,易于理解。您希望客户端使用查询语言使用单个端点来定义其数据需求。这允许灵活的、客户端驱动的数据获取。
性能HTTP 缓存具有高优先级。REST 受益于标准 HTTP 缓存机制,因为它的端点是可预测的。您需要减少网络开销,尤其是在移动客户端或带宽有限的环境中。 GraphQL 通过仅​​获取请求的数据来消除过度获取。
客户端您或您的团队已经熟悉标准 HTTP 请求(例如,使用原生 fetch API、Axios)。您愿意设置和管理 GraphQL 客户端库(例如,Apollo Client)以实现缓存、突变和实时订阅等高级功能。
实时数据您的应用程序不需要实时更新。如果需要,您需要使用单独的技术,例如 WebSockets。您需要内置对通过订阅进行实时数据流传输的支持,这对于实时聊天或通知等功能至关重要。
团队专业知识您的团队更熟悉 REST 的标准约定,或者您已有 REST API。您的团队有使用 GraphQL 基于模式的函数的经验或愿意学习这种函数,这函数的学习曲线可能更陡峭。
Next.JS 集成对于简单的内部 API,您可以使用 Next.JS 的原生 API 路由或服务器操作。您还可以连接到任何外部 REST API。与 Apollo 等 GraphQL 客户端无缝集成,并且可以在服务器端和客户端进行,从而充分利用 Next.JS 的数据获取功能。
本小节配合 Strapi 官方文档 - REST API 阅读效果更佳。

2.5.1 Strapi:Endpoint 介绍

在开始讲解端点(Endpoint)之前,我们还需理解下 Strapi 的复数 API (:pluralApiId) 与单数 API (:singularApiId) 机制。我们在创建一个页面的时候,可以在显示名称右侧看到 API ID 分为以上两类,如默认的 Article 分为 article 的单数 API 及 articles 的复数 API:

Strapi - API - plural vs singular API ID | Rainy Design Studio 雨点设计工作室

Strapi 为集合类型(Collection Types)和单一类型(Single Types)提供了不同的 API 端点:

  • Collection type
函数URL描述
GET/api/:pluralApiId获取一个文档列表
POST/api/:pluralApiId创建一篇文档
GET/api/:pluralApiId/:documentId获取一篇文档
PUT/api/:pluralApiId/:documentId更新一篇文档
DELETE/api/:pluralApiId/:documentId删除一篇文档
  • Single type
函数URL描述
GET/api/:singularApiId获取一篇文档
PUT/api/:singularApiId更新或创建一篇文档
DELETE/api/:singularApiId删除一篇文档

现在我们已经知道了 Global 作为一项 Single type 仅能使用三种端点,这点在先前提到的设置中的 Users & Permission Plugin 页面中也有体现。

除此以外,我们还可以用 /api/upload 端点进行文件上传。

2.5.2 Strapi:REST API 简介

理解完端点,我们便可以开始用 REST API 语法进行接口测试。为了方便举例,我们需要回到 Collection type 的 Article 页面,确认 ID 为 2, 3, 4 的文档为已发布状态,1 与 5 则为归档状态:

Strapi - API - 变更并确认 Article 发布状态 | Rainy Design Studio 雨点设计工作室

然后回到 Insomnia ,对 /api/articles 接口进行测试:

Strapi - API - 测试 Article 接口 | Rainy Design Studio 雨点设计工作室

我们可以手动添加查询参数或直接编辑,比如直接在 /api/articles 后面添加 ?populate=* 做测试:

Strapi - API - REST API 测试 | Rainy Design Studio 雨点设计工作室

获取了几百行的 JSON;数据没问题,但实在太多太杂,现在就让我们来讲讲如何用 REST API 获取想要的数据,并实现排序。首先我们来看一下几种 API 参数:

操作符类型描述
filters对象过滤响应内容
locale字符串获取语言环境
status字符串获取状态(存档或发布)
populate字符串或对象填充关联数据、组件或动态区域
fields数组仅获取特定内容
sort字符串或数组排序内容
pagination对象分页内容

这里我们直接编辑一串包含了上述常用操作符的语句进行举例演示,你也可以 点击这里 快速预览 API 响应。

现在我们仅获取到想要的结果了:

Strapi - API - REST API 测试 2 | Rainy Design Studio 雨点设计工作室

如果你做到这里报错了,请确保 Settings - Users & Permissions Plugin - Roles - Public 中的 Permissions 已依照 上文小节 2.4 的末尾表格 正确设置,且 Article 正确包含了 titleslugdescriptioncoverauthorcategoryblocksseo 字段;如果你做到这里不显示任何数据,则需要查看你是否设置了部分或全部 ID 大于 2 的 Article 的发布状态为已发布。
各类常见错误具体可于 Strapi 使用指南 - 故障排查 中自查解决。

语句如下所示,为了便于阅读,每个 & 字符前都做了换行处理:

http://127.0.0.1:1337/api/articles ?status=published &filters[id][$gt]=2 &sort[1]=id:desc &fields[0]=title &fields[1]=slug &fields[2]=description &populate[cover][fields][0]=alternativeText &populate[cover][fields][1]=caption &populate[cover][fields][2]=url &populate[author][fields][0]=name &populate[category][fields][0]=name &populate[category][fields][1]=slug &populate=blocks &populate[seo]=*

这里逐条解释:

  • 从端点末端加一个半角问号 ? 开始添加操作符
  • 每一个操作符之间都需要用 & 连接
  • 使用 status=published 选中仅发布的页面
  • 使用 filters[id][$gt]=2 筛选出 id 大于 2 的数据
  • 使用 fields=value 仅选择你想要的数据,避免获取不必要的数据
  • 使用 fields[number]=value&fields[number]=value 选择多项数据,其他数据同样不做获取
  • 使用 populate[object][fields][number]=value 在填充的同时限制仅需的数据
  • 使用 populate=valuepopulate[value]=* 获取某个对象的所有数据

2.5.3 Strapi:数据获取与性能优化

接下来让我们以主页为例,通过添加正确的参数以筛选、排序、限定范围,以此获取想要的数据并做好性能优化。

首先让我们从首页开始,从 字段列表文档 与 Strapi 中我们了解到 Home 一共有以下九项内容:

Home ├── banner (required) ├── technologyStacks (required) ├── comparisons (required) ├── comparisonInformations (required) ├── guideChapters (required) ├── guideChapterContents (required) ├── playground (required) ├── playgroundContents (required) └── seo (required)

来看看直接访问首页会回传哪些数据:

http://127.0.0.1:1337/api/home

Strapi - API - Home 的数据 | Rainy Design Studio 雨点设计工作室

相信有很多宝子们看懵了,因为我们竟然只从该 API 获取了最基本的 iddocumentIdcreatedAtupdatedAtpublishedAt 于 data 之中。那其他的数据都去哪了?请不要忘了他们都是组件,必须使用 populate 操作符使其填充。我们先用通配符 * 获取所有内容以做测试:

http://127.0.0.1:1337/api/home?populate=*

Strapi - API - 填充单层所有数据 | Rainy Design Studio 雨点设计工作室

数据终于正常显示了,不过仔细检查会发现没有深度填充到第三级(如 comparisonInformations.contents.detailList 并未显示),且结果获取到很多不想要的。现在我们着手解决这一问题,首先请参考以下语句获取到 detailList:

http://127.0.0.1:1337/api/home?populate=comparisonInformations.contents.detailList <!-- 也可以写成 --> http://127.0.0.1:1337/api/home?populate[comparisonInformations][populate][contents][populate]=detailList

深度填充语法说明:

  • 点号语法:populate=relation.subRelation

    简洁,适用于简单的深度填充

  • 对象语法:populate[relation][populate][subRelation]=*

    复杂,但可以精确控制每一层的填充内容

Strapi - API - 深度填充 | Rainy Design Studio 雨点设计工作室

我们看到,comparisonInformations 和它的子级 contents 以及孙级 detailList 数据都通过深度填充顺利获取了,但是其他八个组件包括 bannertechnologyStackscomparisonsguideChaptersguideChapterContentsplaygroundplaygroundContentsseo 全都没有包含在内。我们来一并获取这些内容:

http://127.0.0.1:1337/api/home ?populate[0]=introduction &populate[1]=frameworks &populate[2]=comparisons &populate[3]=comparisonInformations.contents &populate[4]=comparisonInformations.contents.detailList &populate[5]=comparisonInformations.contents.logo &populate[6]=guideChapters &populate[7]=guideChapterContents &populate[8]=guideChapters.image &populate[9]=playground &populate[10]=playgroundContents &populate[11]=seo

Strapi - API - 选择性填充 | Rainy Design Studio 雨点设计工作室

至此数据都正确获取了;接下来让我们管理下 Collection type,先从 Article 开始。

假设现在我们要为 博客文章 - 草稿箱 获取必要且特定的数据并做好筛排,此外非必要数据一条都不用,那么我们的目标可以拟定为:

  • 页面的状态为 草稿
  • 筛选 作者Sarah Baker 的页面
  • 最后更新时间 进行 倒序排列
  • 仅获取一级数据中的 titledescriptionslugupdatedAt
  • 仅获取组件 coverurlalternativeTextcaption
  • 仅获取组件 authornameemail
  • 仅获取组件 categorynameslugdescription

让我们看看对应的 API 参数,并与不限定 fields 的情况做个对比:

With fields


  • API:
http://127.0.0.1:1337/api/articles ?status=draft &filters[author][name][$eq]=Sarah+Baker &sort=updatedAt:desc &fields[0]=title &fields[1]=description &fields[2]=slug &fields[3]=updatedAt &populate[cover][fields][0]=url &populate[cover][fields][1]=alternativeText &populate[cover][fields][2]=caption &populate[author][fields][0]=name &populate[author][fields][1]=email &populate[category][fields][0]=name &populate[category][fields][1]=slug &populate[category][fields][2]=description
  • Responsive:
JSON
{ "data": [ { "updatedAt": "2025-09-11T15:37:40.832Z", "id": 4, "documentId": "hkqhzs275eidnm6klwrek2sk", "title": "Beautiful picture", "description": "Description of a beautiful picture", "slug": "beautiful-picture", "cover": { "id": 8, "documentId": "qyr7f468ys7ya6qomwagmvxh", "url": "/uploads/beautiful_picture_9d09d9bc5e.jpeg", "alternativeText": "An image uploaded to Strapi called beautiful-picture", "caption": "beautiful-picture" }, "author": { "id": 2, "documentId": "bjmcens0sqbxb8cn8muo4jbo", "name": "Sarah Baker", "email": null }, "category": { "id": 4, "documentId": "lvaftwg3r3ii08lg4db7tav4", "name": "nature", "slug": "nature", "description": "test" } }, { "updatedAt": "2025-09-06T09:03:23.697Z", "id": 3, "documentId": "n2bt6z6wdhejxhy6uvr0k9g4", "title": "A bug is becoming a meme on the internet", "description": "How a bug on MySQL is becoming a meme on the internet", "slug": "a-bug-is-becoming-a-meme-on-the-internet", "cover": { "id": 7, "documentId": "td0bioj5p41t991wyq2op25x", "url": "/uploads/a_bug_is_becoming_a_meme_on_the_internet_1e11e82df1.jpeg", "alternativeText": "An image uploaded to Strapi called a-bug-is-becoming-a-meme-on-the-internet", "caption": "a-bug-is-becoming-a-meme-on-the-internet" }, "author": { "id": 2, "documentId": "bjmcens0sqbxb8cn8muo4jbo", "name": "Sarah Baker", "email": null }, "category": { "id": 2, "documentId": "jjvkd5s5x8xva402vof2ry44", "name": "tech", "slug": "tech", "description": "test" } }, { "updatedAt": "2025-08-30T09:35:24.069Z", "id": 5, "documentId": "rkgn7c8g9xjkprlkge6u8hb9", "title": "What's inside a Black Hole", "description": "Maybe the answer is in this article, or not...", "slug": "what-s-inside-a-black-hole", "cover": { "id": 9, "documentId": "e6nph13wqepty55075xgm6cq", "url": "/uploads/what_s_inside_a_black_hole_fbde111d23.jpeg", "alternativeText": "An image uploaded to Strapi called what-s-inside-a-black-hole", "caption": "what-s-inside-a-black-hole" }, "author": { "id": 2, "documentId": "bjmcens0sqbxb8cn8muo4jbo", "name": "Sarah Baker", "email": null }, "category": { "id": 1, "documentId": "k33z8t7u5ynapq8nv2tkt1p9", "name": "news", "slug": "news", "description": "test" } } ], "meta": { "pagination": { "page": 1, "pageSize": 25, "pageCount": 1, "total": 3 } } }

Without fields


  • API:
http://127.0.0.1:1337/api/articles ?status=draft &filters[author][name][$eq]=Sarah+Baker &sort=updatedAt:desc &populate=*
  • Responsive:
JSON
{ "data": [ { "updatedAt": "2025-09-11T15:37:40.832Z", "id": 4, "documentId": "hkqhzs275eidnm6klwrek2sk", "title": "Beautiful picture", "description": "Description of a beautiful picture", "slug": "beautiful-picture", "createdAt": "2025-08-30T09:35:23.993Z", "publishedAt": null, "cover": { "id": 8, "documentId": "qyr7f468ys7ya6qomwagmvxh", "name": "beautiful-picture", "alternativeText": "An image uploaded to Strapi called beautiful-picture", "caption": "beautiful-picture", "width": 3824, "height": 2548, "formats": { "large": { "ext": ".jpeg", "url": "/uploads/large_beautiful_picture_9d09d9bc5e.jpeg", "hash": "large_beautiful_picture_99fb88a15c", "mime": "image/jpeg", "name": "large_beautiful-picture", "path": null, "size": 83.36, "width": 1000, "height": 666, "sizeInBytes": 83355 }, "small": { "ext": ".jpeg", "url": "/uploads/small_beautiful_picture_9d09d9bc5e.jpeg", "hash": "small_beautiful_picture_99fb88a15c", "mime": "image/jpeg", "name": "small_beautiful-picture", "path": null, "size": 23.35, "width": 500, "height": 333, "sizeInBytes": 23351 }, "medium": { "ext": ".jpeg", "url": "/uploads/medium_beautiful_picture_9d09d9bc5e.jpeg", "hash": "medium_beautiful_picture_99fb88a15c", "mime": "image/jpeg", "name": "medium_beautiful-picture", "path": null, "size": 47.81, "width": 750, "height": 500, "sizeInBytes": 47812 }, "thumbnail": { "ext": ".jpeg", "url": "/uploads/thumbnail_beautiful_picture_9d09d9bc5e.jpeg", "hash": "thumbnail_beautiful_picture_99fb88a15c", "mime": "image/jpeg", "name": "thumbnail_beautiful-picture", "path": null, "size": 6.44, "width": 234, "height": 156, "sizeInBytes": 6436 } }, "hash": "beautiful_picture_99fb88a15c", "ext": ".jpeg", "mime": "image/jpeg", "size": 710.28, "url": "/uploads/beautiful_picture_9d09d9bc5e.jpeg", "previewUrl": null, "provider": "local", "provider_metadata": null, "createdAt": "2025-08-30T09:35:23.974Z", "updatedAt": "2025-08-30T09:35:23.974Z", "publishedAt": "2025-08-30T09:35:23.974Z" }, "author": { "id": 2, "documentId": "bjmcens0sqbxb8cn8muo4jbo", "name": "Sarah Baker", "createdAt": "2025-08-30T09:35:21.197Z", "updatedAt": "2025-08-30T09:35:21.197Z", "publishedAt": "2025-08-30T09:35:21.194Z", "email": null }, "category": { "id": 4, "documentId": "lvaftwg3r3ii08lg4db7tav4", "name": "nature", "slug": "nature", "description": "test", "createdAt": "2025-08-30T09:35:20.366Z", "updatedAt": "2025-09-11T17:34:41.403Z", "publishedAt": "2025-09-11T17:34:41.382Z" }, "blocks": [ { "__component": "shared.rich-text", "id": 7, "body": "## Probant \n\nse Lorem markdownum negat. Argo *saxa* videnda cornuaque hunc qui tanta spes teneas! Obliquis est dicenti est salutat ille tamen iuvenum nostrae dolore. - Colores nocituraque comitata eripiunt - Addit quodcunque solum cui et dextram illis - Nulli meus nec extemplo ille ferebat pressit Se blandita fulvae vox gravem Pittheus cesserunt sanguine herbis tu comitum tenuit. Sui in ruunt; Doridaque maculosae fuissem! Et loqui. \n\n## Abit sua\n\nse Lorem markdownum negat. Argo *saxa* videnda cornuaque hunc qui tanta spes teneas! Obliquis est dicenti est salutat ille tamen iuvenum nostrae dolore. - Colores nocituraque comitata eripiunt - Addit quodcunque solum cui et dextram illis - Nulli meus nec extemplo ille ferebat pressit Se blandita fulvae vox gravem Pittheus cesserunt sanguine herbis tu comitum tenuit. Sui in ruunt; Doridaque maculosae fuissem! Et loqui. " }, { "__component": "shared.quote", "id": 4, "title": "Thelonius Monk", "body": "You've got to dig it to dig it, you dig?" }, { "__component": "shared.media", "id": 4 }, { "__component": "shared.rich-text", "id": 8, "body": "## Spatiantia astra \n\nFoeda, medio silva *errandum*: onus formam munere. Mutata bibulis est auxiliare arces etiamnunc verbis virgineo Priamidas illa Thescelus, nam fit locis lucis auras. Exitus hospes gratulor ut pondere [speslimite](http://www.curas.io/figuram); quid habent, Avernales faciente de. Pervenit Ino sonabile supplex cognoscenti vires, Bacchumque errat miserarum venandi dignabere dedisti. Discrimina iuncosaque virgaque tot sine superest [fissus](http://quos.org/sitet.aspx). Non color esset potest non sumit, sed vix arserat. Nisi immo silva tantum pectusque quos pennis quisquam artus!" }, { "__component": "shared.slider", "id": 4 } ], "seo": { "id": 4, "metaTitle": "Next.JS & Strapi & Tailwind CSS 全套网建实战教学", "metaKeyword": "Next.JS,Strapi,Tailwind CSS,Rainy Design Studio,雨点设计,网建,前端,教程", "metaDescription": "使用 Next.JS 与 Tailwind CSS 快速搭建你的网站,并借由Strapi构建你的内容管理系统;本教程举了各种案例进行精心讲解,旨在让各位前端朋友们快速掌握这些技术栈并运用到实际工作中去。" } }, { "updatedAt": "2025-09-06T09:03:23.697Z", "id": 3, "documentId": "n2bt6z6wdhejxhy6uvr0k9g4", "title": "A bug is becoming a meme on the internet", "description": "How a bug on MySQL is becoming a meme on the internet", "slug": "a-bug-is-becoming-a-meme-on-the-internet", "createdAt": "2025-08-30T09:35:23.534Z", "publishedAt": null, "cover": { "id": 7, "documentId": "td0bioj5p41t991wyq2op25x", "name": "a-bug-is-becoming-a-meme-on-the-internet", "alternativeText": "An image uploaded to Strapi called a-bug-is-becoming-a-meme-on-the-internet", "caption": "a-bug-is-becoming-a-meme-on-the-internet", "width": 3628, "height": 2419, "formats": { "large": { "ext": ".jpeg", "url": "/uploads/large_a_bug_is_becoming_a_meme_on_the_internet_1e11e82df1.jpeg", "hash": "large_a_bug_is_becoming_a_meme_on_the_internet_89fca5bad1", "mime": "image/jpeg", "name": "large_a-bug-is-becoming-a-meme-on-the-internet", "path": null, "size": 50.97, "width": 1000, "height": 666, "sizeInBytes": 50972 }, "small": { "ext": ".jpeg", "url": "/uploads/small_a_bug_is_becoming_a_meme_on_the_internet_1e11e82df1.jpeg", "hash": "small_a_bug_is_becoming_a_meme_on_the_internet_89fca5bad1", "mime": "image/jpeg", "name": "small_a-bug-is-becoming-a-meme-on-the-internet", "path": null, "size": 19.25, "width": 500, "height": 333, "sizeInBytes": 19245 }, "medium": { "ext": ".jpeg", "url": "/uploads/medium_a_bug_is_becoming_a_meme_on_the_internet_1e11e82df1.jpeg", "hash": "medium_a_bug_is_becoming_a_meme_on_the_internet_89fca5bad1", "mime": "image/jpeg", "name": "medium_a-bug-is-becoming-a-meme-on-the-internet", "path": null, "size": 33.59, "width": 750, "height": 500, "sizeInBytes": 33590 }, "thumbnail": { "ext": ".jpeg", "url": "/uploads/thumbnail_a_bug_is_becoming_a_meme_on_the_internet_1e11e82df1.jpeg", "hash": "thumbnail_a_bug_is_becoming_a_meme_on_the_internet_89fca5bad1", "mime": "image/jpeg", "name": "thumbnail_a-bug-is-becoming-a-meme-on-the-internet", "path": null, "size": 6.73, "width": 234, "height": 156, "sizeInBytes": 6728 } }, "hash": "a_bug_is_becoming_a_meme_on_the_internet_89fca5bad1", "ext": ".jpeg", "mime": "image/jpeg", "size": 234.02, "url": "/uploads/a_bug_is_becoming_a_meme_on_the_internet_1e11e82df1.jpeg", "previewUrl": null, "provider": "local", "provider_metadata": null, "createdAt": "2025-08-30T09:35:23.522Z", "updatedAt": "2025-08-30T09:35:23.522Z", "publishedAt": "2025-08-30T09:35:23.522Z" }, "author": { "id": 2, "documentId": "bjmcens0sqbxb8cn8muo4jbo", "name": "Sarah Baker", "createdAt": "2025-08-30T09:35:21.197Z", "updatedAt": "2025-08-30T09:35:21.197Z", "publishedAt": "2025-08-30T09:35:21.194Z", "email": null }, "category": { "id": 2, "documentId": "jjvkd5s5x8xva402vof2ry44", "name": "tech", "slug": "tech", "description": "test", "createdAt": "2025-08-30T09:35:20.359Z", "updatedAt": "2025-09-11T17:34:29.293Z", "publishedAt": "2025-09-11T17:34:29.271Z" }, "blocks": [ { "__component": "shared.rich-text", "id": 5, "body": "## Probant \n\nse Lorem markdownum negat. Argo *saxa* videnda cornuaque hunc qui tanta spes teneas! Obliquis est dicenti est salutat ille tamen iuvenum nostrae dolore. - Colores nocituraque comitata eripiunt - Addit quodcunque solum cui et dextram illis - Nulli meus nec extemplo ille ferebat pressit Se blandita fulvae vox gravem Pittheus cesserunt sanguine herbis tu comitum tenuit. Sui in ruunt; Doridaque maculosae fuissem! Et loqui. \n\n## Abit sua\n\nse Lorem markdownum negat. Argo *saxa* videnda cornuaque hunc qui tanta spes teneas! Obliquis est dicenti est salutat ille tamen iuvenum nostrae dolore. - Colores nocituraque comitata eripiunt - Addit quodcunque solum cui et dextram illis - Nulli meus nec extemplo ille ferebat pressit Se blandita fulvae vox gravem Pittheus cesserunt sanguine herbis tu comitum tenuit. Sui in ruunt; Doridaque maculosae fuissem! Et loqui. " }, { "__component": "shared.quote", "id": 3, "title": "Thelonius Monk", "body": "You've got to dig it to dig it, you dig?" }, { "__component": "shared.media", "id": 3 }, { "__component": "shared.rich-text", "id": 6, "body": "## Spatiantia astra \n\nFoeda, medio silva *errandum*: onus formam munere. Mutata bibulis est auxiliare arces etiamnunc verbis virgineo Priamidas illa Thescelus, nam fit locis lucis auras. Exitus hospes gratulor ut pondere [speslimite](http://www.curas.io/figuram); quid habent, Avernales faciente de. Pervenit Ino sonabile supplex cognoscenti vires, Bacchumque errat miserarum venandi dignabere dedisti. Discrimina iuncosaque virgaque tot sine superest [fissus](http://quos.org/sitet.aspx). Non color esset potest non sumit, sed vix arserat. Nisi immo silva tantum pectusque quos pennis quisquam artus!" }, { "__component": "shared.slider", "id": 3 } ], "seo": { "id": 2, "metaTitle": "Next.JS & Strapi & Tailwind CSS 全套网建实战教学", "metaKeyword": "Next.JS,Strapi,Tailwind CSS,Rainy Design Studio,雨点设计,网建,前端,教程", "metaDescription": "使用 Next.JS 与 Tailwind CSS 快速搭建你的网站,并借由Strapi构建你的内容管理系统;本教程举了各种案例进行精心讲解,旨在让各位前端朋友们快速掌握这些技术栈并运用到实际工作中去。" } }, { "updatedAt": "2025-08-30T09:35:24.069Z", "id": 5, "documentId": "rkgn7c8g9xjkprlkge6u8hb9", "title": "What's inside a Black Hole", "description": "Maybe the answer is in this article, or not...", "slug": "what-s-inside-a-black-hole", "createdAt": "2025-08-30T09:35:24.069Z", "publishedAt": null, "cover": { "id": 9, "documentId": "e6nph13wqepty55075xgm6cq", "name": "what-s-inside-a-black-hole", "alternativeText": "An image uploaded to Strapi called what-s-inside-a-black-hole", "caption": "what-s-inside-a-black-hole", "width": 800, "height": 466, "formats": { "small": { "ext": ".jpeg", "url": "/uploads/small_what_s_inside_a_black_hole_fbde111d23.jpeg", "hash": "small_what_s_inside_a_black_hole_ec5138ea84", "mime": "image/jpeg", "name": "small_what-s-inside-a-black-hole", "path": null, "size": 3.87, "width": 500, "height": 291, "sizeInBytes": 3867 }, "medium": { "ext": ".jpeg", "url": "/uploads/medium_what_s_inside_a_black_hole_fbde111d23.jpeg", "hash": "medium_what_s_inside_a_black_hole_ec5138ea84", "mime": "image/jpeg", "name": "medium_what-s-inside-a-black-hole", "path": null, "size": 6.92, "width": 750, "height": 437, "sizeInBytes": 6923 }, "thumbnail": { "ext": ".jpeg", "url": "/uploads/thumbnail_what_s_inside_a_black_hole_fbde111d23.jpeg", "hash": "thumbnail_what_s_inside_a_black_hole_ec5138ea84", "mime": "image/jpeg", "name": "thumbnail_what-s-inside-a-black-hole", "path": null, "size": 1.56, "width": 245, "height": 143, "sizeInBytes": 1556 } }, "hash": "what_s_inside_a_black_hole_ec5138ea84", "ext": ".jpeg", "mime": "image/jpeg", "size": 7.5, "url": "/uploads/what_s_inside_a_black_hole_fbde111d23.jpeg", "previewUrl": null, "provider": "local", "provider_metadata": null, "createdAt": "2025-08-30T09:35:24.055Z", "updatedAt": "2025-08-30T09:35:24.055Z", "publishedAt": "2025-08-30T09:35:24.055Z" }, "author": { "id": 2, "documentId": "bjmcens0sqbxb8cn8muo4jbo", "name": "Sarah Baker", "createdAt": "2025-08-30T09:35:21.197Z", "updatedAt": "2025-08-30T09:35:21.197Z", "publishedAt": "2025-08-30T09:35:21.194Z", "email": null }, "category": { "id": 1, "documentId": "k33z8t7u5ynapq8nv2tkt1p9", "name": "news", "slug": "news", "description": "test", "createdAt": "2025-08-30T09:35:20.353Z", "updatedAt": "2025-09-11T17:34:49.909Z", "publishedAt": "2025-09-11T17:34:49.889Z" }, "blocks": [ { "__component": "shared.rich-text", "id": 9, "body": "## Probant \n\nse Lorem markdownum negat. Argo *saxa* videnda cornuaque hunc qui tanta spes teneas! Obliquis est dicenti est salutat ille tamen iuvenum nostrae dolore. - Colores nocituraque comitata eripiunt - Addit quodcunque solum cui et dextram illis - Nulli meus nec extemplo ille ferebat pressit Se blandita fulvae vox gravem Pittheus cesserunt sanguine herbis tu comitum tenuit. Sui in ruunt; Doridaque maculosae fuissem! Et loqui. \n\n## Abit sua\n\nse Lorem markdownum negat. Argo *saxa* videnda cornuaque hunc qui tanta spes teneas! Obliquis est dicenti est salutat ille tamen iuvenum nostrae dolore. - Colores nocituraque comitata eripiunt - Addit quodcunque solum cui et dextram illis - Nulli meus nec extemplo ille ferebat pressit Se blandita fulvae vox gravem Pittheus cesserunt sanguine herbis tu comitum tenuit. Sui in ruunt; Doridaque maculosae fuissem! Et loqui. " }, { "__component": "shared.quote", "id": 5, "title": "Thelonius Monk", "body": "You've got to dig it to dig it, you dig?" }, { "__component": "shared.media", "id": 5 }, { "__component": "shared.rich-text", "id": 10, "body": "## Spatiantia astra \n\nFoeda, medio silva *errandum*: onus formam munere. Mutata bibulis est auxiliare arces etiamnunc verbis virgineo Priamidas illa Thescelus, nam fit locis lucis auras. Exitus hospes gratulor ut pondere [speslimite](http://www.curas.io/figuram); quid habent, Avernales faciente de. Pervenit Ino sonabile supplex cognoscenti vires, Bacchumque errat miserarum venandi dignabere dedisti. Discrimina iuncosaque virgaque tot sine superest [fissus](http://quos.org/sitet.aspx). Non color esset potest non sumit, sed vix arserat. Nisi immo silva tantum pectusque quos pennis quisquam artus!" }, { "__component": "shared.slider", "id": 5 } ], "seo": null } ], "meta": { "pagination": { "page": 1, "pageSize": 25, "pageCount": 1, "total": 3 } } }

可以看到后者足足有 388 行内容,且包括了没必要显示的 body ,这造成了大量的数据冗余,由此可见合理的数据筛选对于页面性能优化而言是非常有必要的。

URL 编码注意:查询参数中的空格需要编码为 +%20,特殊字符也需要相应编码。实际开发中建议使用 encodeURIComponent() 函数处理。
更多关于 Strapi 适用的 REST API 的范例请翻阅 Strapi 指南 - 常用过滤操作符 以掌握学习。






至此我们已经掌握了 Strapi 的各项常用功能与使用方法,而关于接口数据的进一步处理如 Token、鉴权等将在后续课程于合适的时间点穿插讲述。

2.6 Strapi:章节知识点汇总

本章我们完成了 Strapi 的完整学习,从安装配置到数据管理,再到 API 调用与性能优化;现在我们把章节中的关键点汇总一下,以做知识巩固。

  • 无头内容管理系统
    • 英文:Headless Content Management System,简称 Headless CMS无头 CMS
    • 概念:有别于传统的、自带前台完整网站的管理系统,无头 CMS 仅提供数据管理、资源存储与访问 API ,使得网站的高度自定义与框架自选成为可能,但需要专业的开发人员进行操作
  • Strapi 简介
    • Strapi CMS:一个 MIT 开源免费、且截止本文截稿前活跃更新,在社区也广受欢迎的无头 CMS
    • 适用场景:企业官网、小型商城、个人博客 等 低密集数据存储、主要由站长或管理员运营内容的网站
    • 官网:strapi.io
    • 数据库:PostgreSQL,MySQL,SQLite,MariaDB
    • 运行环境:Node.JS
    • 技术栈:Koa.JS、Knex.JS、React
  • Strapi 功能
    • 全部功能:主页、内容管理器、媒体资源库、内容类型管理器、插件市场、设置
    • 主页:显示 Dashboard
    • 内容管理器:管理你的合集类型(Collection types)与单页类型(Single types)
    • 媒体资源库:管理你的静态资源
    • 内容类型管理器:管理你的表单,包括合集类型、单页类型以及组件库中的表单
    • 插件市场:查找并安装插件(需要在终止项目后于终端安装)
    • 设置:管理 Strapi 的各项设置
  • Strapi 页面构建流程
    1. 访问内容管理器;
    2. 创建全局组件与页面组件;
    3. 创建页面类型,引入组件及表单;
    4. 保存变动;
    5. 点击右上角工具栏按需更改视图;
    6. 保存变动。
  • Strapi 内容管理流程
    1. 访问内容管理器;
    • 如果是合集类型,可选设置管理合集列表的显示排序
    1. 增删改内容;
    2. 保存后发布或归档文档。
  • Strapi API
    1. 打开设置;
    2. 找到 USERS & PERMISSIONS PLUGIN - Roles;
    3. 按需管理用户组权限,如为公开则进入 Public 项设置;
    4. 选择所需 GET 方法的页面,比如首页、博客、关于我们等,勾选 find、findOne;
    5. 选择所需 POST 方法的页面,比如邮件订阅、站内留言等,勾选 create;
    6. 保存变动。



现在让我们休息一下,然后开始下一章——使用 Next.js 进行网站搭建。

课程链接:Next.js:创建项目并管理目录

订阅

解锁深度且前沿的前端技术、设计理念与用户交互探寻之道。