解析 URL

在实际的网络应用中,我们希望针对不同的 URL 显示不同的内容

  • /search
  • /search?q=seiza
  • /settings

我们如何实现?我们使用 elm/url 将原始字符串解析为漂亮的 Elm 数据结构。当您只看示例时,就能理解该软件包的点睛之处,因此我们就是这么做的!

示例 1

假设我们有一个艺术网站,其中以下地址应有效

  • /topic/architecture
  • /topic/painting
  • /topic/sculpture
  • /blog/42
  • /blog/123
  • /blog/451
  • /user/tom
  • /user/sue
  • /user/sue/comment/11
  • /user/sue/comment/51

因此,我们可以使用 Url.Parser 模块,针对这些内容编写 URL 解析器如下所示

import Url.Parser exposing (Parser, (</>), int, map, oneOf, s, string)

type Route
  = Topic String
  | Blog Int
  | User String
  | Comment String Int

routeParser : Parser (Route -> a) a
routeParser =
  oneOf
    [ map Topic   (s "topic" </> string)
    , map Blog    (s "blog" </> int)
    , map User    (s "user" </> string)
    , map Comment (s "user" </> string </> s "comment" </> int)
    ]

-- /topic/pottery        ==>  Just (Topic "pottery")
-- /topic/collage        ==>  Just (Topic "collage")
-- /topic/               ==>  Nothing

-- /blog/42              ==>  Just (Blog 42)
-- /blog/123             ==>  Just (Blog 123)
-- /blog/mosaic          ==>  Nothing

-- /user/tom/            ==>  Just (User "tom")
-- /user/sue/            ==>  Just (User "sue")
-- /user/bob/comment/42  ==>  Just (Comment "bob" 42)
-- /user/sam/comment/35  ==>  Just (Comment "sam" 35)
-- /user/sam/comment/    ==>  Nothing
-- /user/                ==>  Nothing

Url.Parser 模块使其十分简洁,可以将有效 URL 完整地转换为漂亮的 Elm 数据!

示例 2

现在,假设我们有一个个人博客,其中以下地址有效

  • /blog/12/the-history-of-chairs
  • /blog/13/the-endless-september
  • /blog/14/whale-facts
  • /blog/
  • /blog?q=whales
  • /blog?q=seiza

在这种情况下,我们有单独的博客文章和一个博客概览,其中包含一个可选查询参数。我们需要添加 Url.Parser.Query 模块,以编写这次的 URL 解析器

import Url.Parser exposing (Parser, (</>), (<?>), int, map, oneOf, s, string)
import Url.Parser.Query as Query

type Route
  = BlogPost Int String
  | BlogQuery (Maybe String)

routeParser : Parser (Route -> a) a
routeParser =
  oneOf
    [ map BlogPost  (s "blog" </> int </> string)
    , map BlogQuery (s "blog" <?> Query.string "q")
    ]

-- /blog/14/whale-facts  ==>  Just (BlogPost 14 "whale-facts")
-- /blog/14              ==>  Nothing
-- /blog/whale-facts     ==>  Nothing
-- /blog/                ==>  Just (BlogQuery Nothing)
-- /blog                 ==>  Just (BlogQuery Nothing)
-- /blog?q=chabudai      ==>  Just (BlogQuery (Just "chabudai"))
-- /blog/?q=whales       ==>  Just (BlogQuery (Just "whales"))
-- /blog/?query=whales   ==>  Just (BlogQuery Nothing)

</><?> 运算符让我们得以编写一些解析器,其颇似我们要解析的实际 URL。添加 Url.Parser.Query 让我们得以处理诸如 ?q=seiza 之类的查询参数。

示例 3

好的,现在我们有一个文档网站,其中地址如下所示

  • /Basics
  • /Maybe
  • /List
  • /List#map
  • /List#filter
  • /List#foldl

我们可以使用 Url.Parser 中的 fragment 解析器,以便如下处理这些地址

type alias Docs =
  (String, Maybe String)

docsParser : Parser (Docs -> a) a
docsParser =
  map Tuple.pair (string </> fragment identity)

-- /Basics     ==>  Just ("Basics", Nothing)
-- /Maybe      ==>  Just ("Maybe", Nothing)
-- /List       ==>  Just ("List", Nothing)
-- /List#map   ==>  Just ("List", Just "map")
-- /List#      ==>  Just ("List", Just "")
-- /List/map   ==>  Nothing
-- /           ==>  Nothing

因此,现在我们也可以处理 URL 片段!

综合

既然我们看到了一些解析器,我们应该看看它们如何适应 Browser.application 程序。与其像上次那样只保存当前 URL,我们能否将其解析为有用的数据并显示出来?

TODO

主要的更新内容如下

  1. 在收到 UrlChanged 消息时,我们的 update 解析 URL。
  2. 我们的 view 函数针对不同的地址显示不同的内容!

这真的没有什么花哨的。不错!

但是,当你拥有 10、20 或 100 个不同的页面时,会发生什么?它们是否都出现在这个 view 函数中?肯定不能都放在一个文件中。它应该放在多少个文件中?应该是什么目录结构?下面我们将讨论这些内容!

与“”匹配的 个结果

    没有与“”匹配的结果