【问题标题】:Single page application routing w/ Crossroads & Hasher, by example带 Crossroads 和 Hasher 的单页应用程序路由,例如
【发布时间】:2014-05-31 11:00:48
【问题描述】:

我正在尝试编写我的第一个单页应用程序。这个想法是有 1 个包含许多 <div> 标记的 HTML 文件;其中每个<div> 代表一个网页“页面”。然后应用程序一次只显示 1 个<div>,并隐藏其他。这样,当用户浏览我的应用程序时,我实际上只是显示/隐藏不同的“页面”div,并给人一种单页应用程序的错觉。

其他要求是:

  • 这是一个 HTML5 应用程序
  • 每个页面 div 也必须映射其自己的可收藏 URL(http://myapp.example.com/#fizzhttp://myapp.example.com/#buzz 等)
  • 单个页面 div 是可收藏的,应用必须使用 HTML5 历史 API

我决定使用 Crossroads 进行路由,使用 Hasher 进行历史记录。另一个主要竞争者是 AngularJS,但最后我决定不使用 AngularJS,因为它对于我在这里尝试做的事情来说太重了,而且似乎有一个更陡峭的学习曲线与之相关。

到目前为止,我的项目目录结构如下:

myapp/
    index.html
    myapp.js
    myapp.css
    signals.min.js          <-- Required by both Crossroads and Hasher
    crossroads.min.js
    hasher.min.js

包含我的 index.htmlmyapp.cssmyapp.js 文件的 JSFiddle 在这里:

http://jsfiddle.net/Sxfms/2/

这个想法是,用户可以单击“导航栏”中的链接之一(“主页”、“关于”、“联系方式”)并被带到代表该特定页面的“页面”(div)。 如您所见,默认的“页面”应该是HOME,这意味着这是您应该能够看到的唯一 div。但是所有的页面 div 都是可见的,没有一个是隐藏的。在我能够正确显示/隐藏页面 div 之前,我无法真正测试路由/历史功能。我是否以某种方式错误地配置了 Crossroads/Hasher?

【问题讨论】:

  • 多页抽象是你的事。你必须实施它。 Crossroads 只是提供路由功能。默认情况下,它不会执行您所要求的操作。您应该尝试制作更多 HTML5/CSS3 页面。 CSS 可以处理可见性。它也很基本。如果您在这里搜索过,您会找到很多关于如何操作的答案。
  • 感谢@user568109 (+1):有几件事:(1) 我的理解是 Crossroads 处理路由,而 Hasher 处理历史。如果这就是他们所做的一切,那么有人只需要调整我的代码以展示如何将路由和历史记录合并到我的应用程序中,我将奖励他们全部赏金。 (2) 我做了研究。实际上,如果您查看我的 JS,您将能够找到与 Crossroads 文档中几乎完全相同的函数/代码。你说有很多关于如何做我所问的答案;你能给我提供其中 2 个或 3 个的链接吗?再次感谢。
  • 如果您的实际单页将包含多页。这些页面将如何加载?加载主页时会全部加载(来自相同的 url)。还是这些是其他网址的远程页面/链接?
  • 再次感谢@user568109 (+1)。这个想法是用一个 HTML 文件/请求来拉下一切。然后只需显示/隐藏用户应该查看的正确“页面”(&lt;div&gt;)。我需要每个“页面”对应于一个可添加书签的 URL(即“Fizz”页面,它可能对应于 &lt;div id="fizz"&gt; 元素,并且可能与 http://myapp.example.com/#fizz URL 等相关联)。最重要的是,当用户导航到多个“页面”时,每个可收藏的 URL 都需要被推送到 HTML5 历史机制,以便前进/后退按钮起作用。
  • 如果满足所有其他条件,是否需要 Crossroads 和 Hasher 才能获得全部赏金?

标签: javascript html routing single-page-application crossroadsjs


【解决方案1】:

我认为有一个解决方案可以满足您的要求。这是一种非常简单、轻量级的方法,不需要任何 JavaScript,只需借助 CSS 的强大功能。 ;-)

整个方法的关键是CSS伪类选择器:target

所以我先解释一下:target的概念:伪选择器匹配URL中的片段标识符(或哈希,例如#content)和HTML的id元素是一样的。如果我们有一个像 http://www.example.com/hallo.html#content 这样的 URL 和一个带有 id="content" 的元素,那么选择器 #content:target { ... } 就会匹配。

您无法真正看到此 fiddel 中的 URL,但在另一个示例中您会看到。她是小提琴的密码:

HTML:

<a href="#content">content</a>
<div id="content">
    Markup is poetry!
</div>

CSS:

#content {
    border: 1px solid black;
    padding: 20px;
}

#content:target {
    background: lightblue;
}

:target 方法导致了这个简化的示例来解释 page-navigation-ideahttp://jsfiddle.net/Cxr73/1/ 同样,您无法真正看到带有片段标识符的 URL。

HTML:

<a href="#div1">div1</a>
<a href="#div2">div2</a>
<a href="#div3">div3</a>

<div id="div2">
    <div id="div3">
        <div class="div1Inner">content div1</div>
        <div class="div2Inner">content div2</div>
        <div class="div3Inner">content div3</div>
    </div>
</div>

CSS:

.div2Inner, .div3Inner, 
#div2:target .div1Inner, #div3:target .div1Inner {
    display: none;
}

#div2:target .div2Inner, #div3:target .div3Inner {
    display: block;
}

隐藏所有最初不应显示的divs:.div2Inner, .div3Inner { display: none;}。所以只有&lt;div class="div1Inner"&gt;content div1&lt;/div&gt; 是可见的。当片段标识符是 URL 的一部分时,显示相应的 div#div2:target .div2Inner, #div3:target .div3Inner {display: block;}。最后,当div2div3 可见时,您必须隐藏div1#div2:target .div1Inner, #div3:target .div1Inner { display: none; }。结合第一个和最后一个 CSS 选择器,就得到了上面显示的 CSS。


关于您的标记的一些建议:

  • 按照the HTML5 spec(4.2.5.5 指定文档的字符编码)的建议,尽早添加字符集声明以避免在 IE 中出现潜在的encoding-related security issue。它应该出现在前 1024 个字节中。
  • &lt;center&gt; 元素已被弃用,因为它定义了其内容的呈现方式。为此,我们有 CSS。
  • 您正在编写一个 HTML5 应用程序,因此请添加一些语义标记,例如:navheadersectionfooter 等元素。

这里你有我的想法的最终方法,你的 CSS 加上 :target 选择器(从第 600 行开始)和我认为干净的标记:

小提琴:http://jsfiddle.net/Cxr73/2/ 最终看到片段标识符加上:target 的实际作用并出于测试目的使用另一个 URL:DEMO ...此演示将在几天后消失,但小提琴将继续存在。

我认为这几乎可以满足您的所有需求。玩得开心!

【讨论】:

  • 感谢@Fabian Mebus (+1) - 这是您精心设计的出色且非常优雅的解决方案 - 谢谢! 三个后续项目:(1)在你DEMO链接中,我看到你有几个新的HTML5标签(&lt;header&gt;用于所有页面,&lt;header&gt;用于每个页面,&lt;section&gt;标签等.)。这些是您的解决方案工作所必需的,还是因为它们是 HTML5 标准而将它们添加到那里?换句话说:你的基于 CSS 的解决方案可以在 HTML5 之外工作吗?
  • 那么 (2) 沿着同样的思路,由于它需要 CSS 技巧,是否有任何主要的浏览器版本不会能够利用它解决方案?
  • 最后 (3) 您能否简要介绍一下为什么 Crossroads.js 和路由通常不适合这个问题?我问这个是因为我似乎误解了路由是什么,我不明白为什么没有人能够解决我的 Crossroads 问题。再次(非常感谢)这个出色的答案 - 你快到了!
  • 给你:(1) HTML5 元素对于该方法不是必要的。 (2) 伪类选择器:target 已经存在很长时间了。所以浏览器支持真的很好:CSS3 selectors
  • (3) 我想您已经了解了路由。从我的角度来看,Crossroads.js 通常对您的问题来说并不是一个坏主意。它可能有更好的文档,但是为什么你要使用需要另一个库和另一个插件库(哈希器)来获得你需要的功能的 js 库,当你已经在浏览器中默认烘焙了所有你需要的东西时几行 CSS?
猜你喜欢
  • 2014-10-08
  • 2019-03-05
  • 2015-12-08
  • 1970-01-01
  • 2012-09-22
  • 2018-12-30
  • 2014-11-12
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多