全部分类页 封面
Vapor 大型教程

全部分类页

本章实现网站上的「分类」相关页面:一个列出所有分类的列表页,以及点进去查看某分类下全部缩略语的详情页。

上下文与路由

WebsiteController.swift 中定义两个上下文:AllCategoriesContext 用于列表页;CategoryConext(源站原文如此命名)用于单个分类详情页,内部用一个 Future<[Acronym]> 承载该分类下的缩略语。

struct AllCategoriesContext: Encodable {
    let title = "All Categories"
    let categories: Future<[Category]>
}
struct CategoryConext: Encodable {
    let title: String
    let category: Category
    let acronyms: Future<[Acronym]>
}

注册两条路由:/categories 显示全部分类,/category/:id 显示某个分类。

router.get("categories", use: allCategoriesHandler)
router.get("category", Category.parameter, use: categoryHandler)

列表页处理方法

allCategoriesHandlerCategory.query(on: req).all() 取出所有分类,渲染 allCategories 模板。

func allCategoriesHandler(_ req: Request) throws -> Future<View> {
    let categories = Category.query(on: req).all()
    let context = AllCategoriesContext(categories: categories)
    return try req.view().render("allCategories", context)
}

categoryHandler 先取出目标 Category,再通过 category.acronyms.query(on: req).all() 拿到它的关联缩略语,并渲染 category 模板。

func categoryHandler(_ req: Request) throws -> Future<View> {
    return try req.parameters.next(Category.self)
        .flatMap(to: View.self) { category in
            let acronyms = try category.acronyms.query(on: req).all()
            let context = CategoryConext(title: category.name, category: category, acronyms: acronyms)
            return try req.view().render("category", context)
    }
}

allCategories.leaf 模板

用表格展示分类名,每个名字链接到对应分类详情页;若还没有任何分类则显示提示文案。

#set("content"){
    <h1>All Categories</h1>
    #if(count(categories) > 0) {
    <table class="table table-bordered table-hover">
        <thead class="thead-light">
            <tr>
                <th>
                    Name
                </th>
            </tr>
        <thead>
        <tbody>
            #for(category in categories) {
                <tr>
                    <td>
                        <a href="/category/#(category.id)">
                            #(category.name)
                        </a>
                    </td>
                </tr>
            }
        </tbody>
    </table>
    } else {
    <h2>There aren't any categories yet!</h2>
    }
}

#embed("base")

category.leaf 模板

展示分类名称,并用表格列出该分类下每个缩略语的简称与全称。

#set("content") {
    <h1>#(category.name)</h1>
    #if(count(acronyms) > 0) {
        <table class="table table-bordered table-hover">
            <thead class="thead-light">
                <tr>
                    <th>
                        Short
                    </th>
                    <th>
                        Long
                    </th>
                </tr>
            </thead>
            <tbody>
                #for(acronym in acronyms) {
                    <tr>
                        <td>
                            <a href="/acronyms/#(acronym.id)">
                                #(acronym.short)
                            </a>
                        </td>
                        <td>
                            #(acronym.long)
                        </td>
                    </tr>
                }
            </tbody>
        </table>
    } else {
        <h2>There aren't any acronyms yet!</h2>
    }
}
#embed("base")

导航入口

base.leaf 加入「All Categories」导航项,访问本页时高亮。

<li class="nav-item #if(title=="All Categories"){active}">
    <a href="/categories" class="nav-link">All Categories</a>
</li>

本系列其他文章