<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>单页面架构 on Last Stand</title><link>https://amatsuzero.github.io/LastStand/tags/%E5%8D%95%E9%A1%B5%E9%9D%A2%E6%9E%B6%E6%9E%84/</link><description>Recent content in 单页面架构 on Last Stand</description><generator>Hugo</generator><language>zh-cn</language><lastBuildDate>Thu, 23 Oct 2025 00:00:00 +0800</lastBuildDate><atom:link href="https://amatsuzero.github.io/LastStand/tags/%E5%8D%95%E9%A1%B5%E9%9D%A2%E6%9E%B6%E6%9E%84/index.xml" rel="self" type="application/rss+xml"/><item><title>单页面架构</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/engineering/engineering-013/</link><pubDate>Thu, 07 Aug 2025 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/engineering/engineering-013/</guid><description>&lt;h3 id="传统的多页面应用构建方式"&gt;传统的多页面应用构建方式：&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;纯服务端渲染，前后端不分离，使用&lt;code&gt;jsp&lt;/code&gt;,&lt;code&gt;jade&lt;/code&gt;,&amp;rsquo;ejs&amp;rsquo;,&amp;rsquo;tempalte&amp;rsquo;等技术在后台先拼接成对应的&lt;code&gt;HTML&lt;/code&gt;结构，然后转换成字符串，在每个对应的路由返回对应的数据（文件）即可&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;Jade&lt;/code&gt;模版服务端渲染，代码实现：&lt;/p&gt;
&lt;/blockquote&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-mysql" data-lang="mysql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;const express&lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;require&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;express&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;const app &lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;express&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;const jade &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;require&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;jade&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;const result &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#f92672"&gt;***&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;const url path &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#f92672"&gt;***&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;const html &lt;span style="color:#f92672"&gt;=&lt;/span&gt; jade.&lt;span style="color:#a6e22e"&gt;renderFile&lt;/span&gt;(url, &lt;span style="color:#960050;background-color:#1e0010"&gt;{&lt;/span&gt; data: result, urlPath &lt;span style="color:#960050;background-color:#1e0010"&gt;}&lt;/span&gt;)&lt;span style="color:#f92672"&gt;//&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;传入数据给模板引擎&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;app.&lt;span style="color:#a6e22e"&gt;get&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;/&amp;#39;&lt;/span&gt;,(req,res)&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; res.&lt;span style="color:#a6e22e"&gt;send&lt;/span&gt;(html)&lt;span style="color:#f92672"&gt;//&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;直接吐渲染好的&lt;/span&gt;&lt;span style="color:#f92672"&gt;`&lt;/span&gt;html&lt;span style="color:#f92672"&gt;`&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;文件拼接成字符串返回给客户端&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;}&lt;/span&gt;) &lt;span style="color:#f92672"&gt;//&lt;/span&gt;RestFul接口
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;app.&lt;span style="color:#a6e22e"&gt;listen&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;3000&lt;/span&gt;,err&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;//&lt;/span&gt;do something
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;}&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;使用&lt;code&gt;jQuery&lt;/code&gt;等传统库绘制的前端页面&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="传统前后端不分离服务端渲染的优缺点"&gt;传统前后端不分离，服务端渲染的优缺点：&lt;/h3&gt;
&lt;h4 id="优点"&gt;优点：&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;SEO&lt;/code&gt;友好，因为返回给前端的是渲染好的&lt;code&gt;HTML&lt;/code&gt;结构，里面的内容都可以被爬虫抓取到。&lt;/li&gt;
&lt;li&gt;对于一些应用性能等要求不高的项目，比如某个公司的静态网页，内容很少的情况下，直接一把梭就好，不用再搭建工程化的环境等&lt;/li&gt;
&lt;li&gt;对于后端程序员（全干工程师）来说，不用去特意学习前端框架，公司也不用特意去招聘前端&lt;/li&gt;
&lt;li&gt;兼容性好，传统服务端渲染多页面应用吐出来的都是字符串，&lt;code&gt;HTML&lt;/code&gt;结构&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="缺点"&gt;缺点：&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;如果项目很大，不利于维护，据我所知，目前很多云计算公司，还有不少都是使用非单页面应用，例如一个几十万行的项目是用&lt;code&gt;jQuery&lt;/code&gt;写的，如果注释和文档不是非常齐全，那么真的会无从下手&lt;/li&gt;
&lt;li&gt;性能和用户体验，不能跟单页面应用相比&lt;/li&gt;
&lt;li&gt;后期迭代，升级空间不大，目前大部分写得比较好的库，都建立&lt;code&gt;vue,react&lt;/code&gt;等框架基础上，他们都有一套自己的运行机制，有自己的生命周期，并且不像传统的应用，还加上了一层虚拟&lt;code&gt;DOM&lt;/code&gt;以及&lt;code&gt;diff&lt;/code&gt;算法&lt;/li&gt;
&lt;li&gt;现在类似&lt;code&gt;Ant-Design-pro&lt;/code&gt;这样的开箱即用的库已经很多，单页面应用的学习和开发成本已经很低很低，如果还在使用传统的技术去开发新的应用，对于开发人员多内心来说也是一种折磨。&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;这里并不是说多页面应用不好，只能说各有各自的好，单页面应用如果通过大量的极致优化手段，是可以从不少方面跟原生一拼。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/engineering/engineering-013/image-01.webp"&gt;&lt;/p&gt;
&lt;h2 id="目前的单页面应用"&gt;目前的单页面应用：&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;只有一张Web页面的应用，是一种从Web服务器加载的富客户端，单页面跳转仅刷新局部资源 ，公共资源(js、css等)仅需加载一次，常用于PC端官网、购物等网站&lt;/li&gt;
&lt;li&gt;其实只有一个空的&lt;code&gt;DIV&lt;/code&gt;标签，其他都是&lt;code&gt;js&lt;/code&gt;动态生态的内容&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="单页面应用实现步骤"&gt;单页面应用实现步骤：&lt;/h3&gt;
&lt;h4 id="代码实现"&gt;代码实现：&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;首先是一个静态模板文件 &lt;code&gt;index.html&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;!DOCTYPE html&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;html lang=&amp;#34;en&amp;#34;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;head&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;meta charset=&amp;#34;UTF-8&amp;#34;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;meta name=&amp;#34;viewport&amp;#34; content=&amp;#34;width=device-width, initial-scale=1.0&amp;#34;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;meta http-equiv=&amp;#34;X-UA-Compatible&amp;#34; content=&amp;#34;ie=edge&amp;#34;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;title&amp;gt;Document&amp;lt;/title&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;/head&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;body&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;div id=&amp;#34;root&amp;#34;&amp;gt;&amp;lt;/div&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;/body&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;script&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;/script&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;/html&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;在&lt;code&gt;vue react&lt;/code&gt;框架的入口文件中指定对应的渲染元素：&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;import React from &amp;#39;react;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;import ReactDOM from &amp;#39;react-dom&amp;#39;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ReactDOM.render(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;App/&amp;gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;document.querySelector(&amp;#34;#root&amp;#34;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;引入&lt;code&gt;react-router或者 react-router-dom，dva&lt;/code&gt;等路由跳转的库&lt;/li&gt;
&lt;li&gt;配置路由跳转&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;HashRouter&amp;gt;//这里使用HashRouter
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;ErrorBoundary&amp;gt;//React错误边界
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;Switch&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;Route path=&amp;#34;/login&amp;#34; component={Login} /&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;Route path=&amp;#34;/home&amp;#34; component={Home} /&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;Route path=&amp;#34;/&amp;#34; component={NotFound} /&amp;gt;//404路由或者重定向都可以
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;/Switch&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;/ErrorBoundary&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;/HashRouter&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="单页面应用所谓路由跳转其实最终结果就是"&gt;单页面应用所谓路由跳转，其实最终结果就是：&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;浏览器的&lt;code&gt;url&lt;/code&gt;地址发生变化，但是其实并没有发送请求，也没有刷新整个页面&lt;/li&gt;
&lt;li&gt;根据我们配置的路由信息，每次点击切换路由，会切换到不同的组件显示，类似于选项卡功能的实现,但是同时&lt;code&gt;url&lt;/code&gt;地址栏会变化&lt;/li&gt;
&lt;li&gt;分为&lt;code&gt;HashRouter&lt;/code&gt;和&lt;code&gt;BrowserRouter&lt;/code&gt;两种模式&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="自己实现一个粗略的路由跳转"&gt;自己实现一个粗略的路由跳转：&lt;/h2&gt;
&lt;h3 id="自己实现传统的hash模式跳转"&gt;自己实现传统的&lt;code&gt;Hash&lt;/code&gt;模式跳转：&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;hash 就是指 url 后的 # 号以及后面的字符。例如&lt;code&gt;www.baidu.com/#segmentfault&lt;/code&gt;,那么&lt;code&gt;#segmentfault&lt;/code&gt;就是&lt;code&gt;hash&lt;/code&gt;值&lt;/p&gt;</description></item></channel></rss>