【4】单页面应用
#翻译转载#Web应用101
随着2010年后单页面应用(SPAs)的发展,JavaScript逐渐变得受欢迎了起来。但在这之前,网站一般只包含HTML,CSS和少量的JS代码。这些JS代码一般只是用来制作一些网页动画,或者操作DOM树(比如移动、增加、删除、修改HTML元素)。Jquery就是一个实现相关操作的库(用Web原生API麻烦),这个库非常受欢迎,现在仍然有不少企业再用。
但是谁能想到整个网页程序都由JS构建会是什么样的?早期的JS单页面框架/库有Knockout.js,Ember.js和Angular.js等,后来又发布了React.js和Vue.js。这些框架现在被大规模地用于网页程序开发。
在单页面应用程序出现之前,一个浏览器回向服务器请求HTML文件以及HTML上面链接的文件。如果用户在当前域名上从一个页面跳转到另一个页面上时(比如/home到/about),浏览器会发送新的请求来获取该页面的内容。(见图)
与之不同的是,一个单页面应用将大多数网页内容写在JS文件里,JS文件包含了网页内容以及渲染样式。单页面的应用程序最基础的一个特点是,浏览器在同一个域名下只向服务器请求1次HTML文件以及HTML上链接的JS文件(见图)。
在单页面应用程序中,浏览器请求的HTML文件只是作为JS文件的中介,本身并无网页的内容,只是一个框架,当浏览器获取到这个JS文件(在下面的React例子中的bundle.js)后,就会在HTML框架中渲染内容(在这里网页内容会在 <div id="app"></div>里渲染)。
<!DOCTYPE html>
<html>
<head>
<title>Hello HTML File which executes a React Application</title>
</head>
<body>
<div id="app"></div>
<script src="./bundle.js"></script>
</body>
</html>
在这个React例子中,网页的内容被写在./bundle.js
文件中
import * as React from 'react';
import ReactDOM from 'react-dom';
const title = 'Hello React';
ReactDOM.render(
<div>{title}</div>,
document.getElementById('app')
);
这个应用程序中,我们用了一种特别的语法在HTML的div元素里放置了一个叫title
的变量,当页面渲染时,{title}
就会被Hello React
代替。基本上所有在div元素中能写的东西,在React都能用React组件和React特有的模板语法JSX编写,这样在HTML中只需要写一个div就行。
import * as React from 'react';
import ReactDOM from 'react-dom';
const App = () => {
const [counter, setCounter] = React.useState(42);
return (
<div>
<button onClick={() => setCounter(counter + 1)}>
Increase
</button>
<button onClick={() => setCounter(counter - 1)}>
Decrease
</button>
{counter}
</div>
);
};
ReactDOM.render(
<App />,
document.getElementById('app')
);
这和早期的模板语法框架类似,但不同的是这些代码在客户端运行,而不是服务端,这会给服务端减少不小的压力。
const App = () => {
const [books, setBooks] = React.useState([
'The Road to JavaScript',
'The Road to React',
]);
const [text, setText] = React.useState('');
const handleAdd = () => {
setBooks(books.concat(text));
setText('');
};
return (
<div>
<input
type="text"
value={text}
onChange={(event) => setText(event.target.value)}
/>
<button
type="button"
onClick={handleAdd}
>
Add
</button>
<List list={books} />
</div>
);
};
const List = ({ list }) => (
<ul>
{list.map((item, index) => (
<li key={index}>{item}</li>
))}
</ul>
);
也正因为如此,我们不再叫它服务端渲染,而是客户端渲染。意思是:服务端不再提供渲染好的HTML文件,而是发送JS文件,并由JS渲染页面。客户端渲染应用和单页面应用通常指的是同一个东西。
读到这里有些人就要问了,单页面应用程序只访问1次HTML文件和JS文件,那么我在跳转页面时(比如/home到/about)它如何在不请求HTML和JS的情况下显示新的页面?
这时前端路由就发挥作用了,当使用单页面应用程序时,我们会将后端路由移动到前端,而那个用于渲染页面的JS文件里打包了一个网站的所有页面。当你跳转页面时,浏览器不会产生新的请求,取而代之的是一个客户端路由(比如Vue的Vue-Router)会工作,并将新页面的内容渲染在你的浏览器上,路由和网页内容都包含在最初的JS文件里。
总得来说,一个单页面应用程序会使用前端路由和前端渲染代替后端路由和后端渲染,使用一个的请求提供整个网页程序服务(译者:当然图片这些一般不会直接存在js文件里,而是浏览器去访问),只访问了一次HTML文件及其JS文件,这个JS文件能在客户端渲染并展示所有的网页内容。这也是为什么它叫单页面应用。
可以说在单页面应用出现前,我们会单独制作每个页面,每个页面也会有单独的请求。不过在单页面应用出现之前,“多页面应用”的概念也没出现过,因为在那时这时默认的做法。
拓展资料:
学习Vue:Vue.js - 渐进式 JavaScript 框架 | Vue.js (vuejs.org)
原文
SINGLE-PAGE APPLICATIONS
The rise of single-page applications (SPAs) after 2010 made JavaScript popular. But I am getting ahead of myself. Prior to this era, websites were mainly made with HTML plus CSS and only a sprinkle of JavaScript. The little JavaScript was used for animations or DOM manipulations (e.g. removing, adding, modifying of HTML elements), but not much beyond this. And jQuery was one of the most popular libraries to perform such tasks.
But who would have thought that entire applications could be built with JavaScript? A few of the earlier libraries/frameworks to write single-page applications in JavaScript were Knockout.js, Ember.js, and Angular.js; while React.js and Vue.js were released later. Most of them are still very active to this day in modern web applications.
Prior to single-page applications, a browser would request the HTML file and all linked files from a web server for a website. If a user happens to navigate from page (e.g. /home) to page (e.g. /about) within the same domain (e.g. mywebsite.com), there would be a new request to the web server for every navigation.
In contrast, a single-page application encapsulates the entire application in mostly JavaScript which has all the knowledge about how and what to render with HTML (and CSS) inside it. For the most basic usage of a single-page application, the browser would request only once a HTML file with one linked JavaScript file for a domain.
The requested HTML for a single-page application (here a React application) is just a middleman to request the JavaScript application (here bundle.js) which, after it has been requested and resolved on the client, will be rendered in the HTML (here id="app"
):
<!DOCTYPE html>
<html>
<head>
<title>Hello HTML File which executes a React Application</title>
</head>
<body>
<div id="app"></div>
<script src="./bundle.js"></script>
</body>
</html>
From there, React takes over with this little JavaScript from a ./bundle.js:
import * as React from 'react';
import ReactDOM from 'react-dom';
const title = 'Hello React';
ReactDOM.render(
<div>{title}</div>,
document.getElementById('app')
);
In this little React application, only a variable called title
is displayed in an HTML div
element. However, everything between the HTML div
element can be replaced with an entire HTML structure built with React components and its templating syntax JSX.
import * as React from 'react';
import ReactDOM from 'react-dom';
const App = () => {
const [counter, setCounter] = React.useState(42);
return (
<div>
<button onClick={() => setCounter(counter + 1)}>
Increase
</button>
<button onClick={() => setCounter(counter - 1)}>
Decrease
</button>
{counter}
</div>
);
};
ReactDOM.render(
<App />,
document.getElementById('app')
);
【案例】
This is essentially a templating engine from earlier, but just executed on the client instead of the server and therefore this isn't server-side rendering anymore.
const App = () => {
const [books, setBooks] = React.useState([
'The Road to JavaScript',
'The Road to React',
]);
const [text, setText] = React.useState('');
const handleAdd = () => {
setBooks(books.concat(text));
setText('');
};
return (
<div>
<input
type="text"
value={text}
onChange={(event) => setText(event.target.value)}
/>
<button
type="button"
onClick={handleAdd}
>
Add
</button>
<List list={books} />
</div>
);
};
const List = ({ list }) => (
<ul>
{list.map((item, index) => (
<li key={index}>{item}</li>
))}
</ul>
);
【案例】
Because of this change from server to client execution of the rendering, we call it client-side rendering now. In other words: Instead of serving the pre-rendered HTML directly from the web server, we serve mainly JavaScript from the web server which executes on the client and only then renders the HTML. Often the term SPA can be used synonymously with the term client-side rendered application.
If the SPA is requested only once from a web server, how does it work when a user navigates from one page to another page within the same domain (e.g. mywebsite.com/about to mywebsite.com/home) without requesting another HTML?
With the usage of a traditional SPAs, we also moved from server-side routing to client-side routing. The initially requested JavaScript file for the basic SPA has all the pages of a website encapsulated. Navigating from one page (e.g. /about) to another page (e.g. /home) wouldn't perform any request to the web server. Instead, a client-side router (e.g. React Router for React) takes over to render the appropriate page from the initially requested JavaScript file.
In a nutshell: A basic single-page application uses client-side rendering/routing over server-side rendering/routing while retrieving the entire application only once from a web server. It's a single page, because there is only one request made for the entire application, which is a single HTML page which links to one JavaScript file; which has all the actual UI pages encapsulated and executes on the client-side.
One could say that before we had single-page applications, we have been working with multi-page applications, because for every page (e.g. /about) a new request is made to the web server to retrieve all the necessary files for it. However, the term multi-page application isn't really a thing, because it was the default before single-page applications became popular.
Exercises:
- Learn how to use React for single-page application development.
- Learn how to set up a React with Webpack application from scratch.
生词
ahead
- *adv.*在前面,朝前面;领先,占优势;提前,预先;在将来,今后;(数量或价值上)更多,更高;取得进步,获得成功;超出预期地,超前地
- *adj.*在前的,提前的
prior
- *adj.*先前的,事先的;<正式>优先的,更重要的;<正式>在前面的(prior to)
- n.<美,非正式>犯罪前科;小修道院院长;大修道院副院长;托钵会会长
sprinkle
- *v.*撒,洒;用……点缀,在……中随意穿插;零星分布;下小雨
- *n.*少量,一点;稀疏小雨;(撒在糕饼上作装饰用的)彩糖,糖屑(sprinkles)
animation
- *n.*活力,生气,热烈;动画片,动画游戏;动画制作
manipulation
- *n.*操纵;推拿;(熟练的)控制,使用;(对账目等的)伪造,篡改;(对储存在计算机上的信息的)操作,处理
perform
- *v.*演出,表演;执行,履行(尤指复杂的任务或行动);运行,表现;起…...作用,有…...功能
contrast
- *n.*差异,对比;对照物,明显不同的事物;(摄影或绘画中的)颜色反差,明暗对比;(电视屏幕的)图像明暗对比度,反差
- *v.*对比,对照;显出明显的差异,形成对比
encapsulate
- *vt.*简要描述,概括;用胶囊(或囊状物)装,封装;封装(信息,信号);为(软件,硬件)提供接口(或界面)
middleman
- *n.*中间人;经纪人;调解人
variable
- *adj.*易变的,多变的;时好时坏的;可变的,可调节的;(数)(数字)变量的;(植,动)变异的,变型的;(齿轮)变速的
- *n.*可变性,可变因素;(数学中的)变量,变元;(计算机)变量(元);(天文)变星的简称;(东北信风带以北或南半球的东南信风带与西风带之间的)变风区
structure
- *n.*结构,构造;结构体,(尤指)大型建筑物;周密安排,精心组织;机构,组织,体系
- *v.*计划,组织,安排
component
- *n.*组成部份,成分,部件
- *adj.*组成的,构成的
templating
- *n.*模板;制模;放样
syntax
- *n.*句法,句法规则;(计算机语言的)句法,语构;句子结构分析法;句法学
essentially
- *adv.*本质上,根本上;大体上,基本上
executed
- *v.*处决;实施;完成(动作);执行(execute 的过去式与过去分词)
pre-rendered
好的
徐新逸(民 85)提出四个阶脑绘图,是预先绘制好的(Pre-rendered) ,内 段的模式及其步骤,如表一所示。容无法互动,也就是一般的动画 (animation)
directly
- *adv.*直接地,径直地;坦率地;恰好,正好;立即,很快地
- *conj.*一……就……
term
- n.(某人做某事或某事发生的)时期,期限,任期;学期,开庭期;到期,期满;术语,专有名词;措辞,说话的方式(terms);方面,角度(terms);(人们之间的)关系(terms);条件,条款(terms);付款条件,购买(出售)条件(terms);(结束战争,解决争端的)条件(terms);(数学运算中的)项;(逻)(三段论中的)项;(尤指苏格兰的)法定结账日(term day);<法律> 有限期租用的地产;(建筑)界标
- *v.*把……称为,把……叫做
synonymously
- 同义
encapsulated
- *adj.*密封的;包在荚膜内的
- *v.*压缩(encapsulate 的过去分词);封进内部;装入胶囊
nutshell
- *n.*坚果外壳;简要地说,概括地说(in a nutshell);(生存于冷海水中的)双壳类软体动物(nut shell);小的东西
retrieve
- *v.*找回,收回;检索(储存于计算机的信息);(狗等)衔回(物品、猎物);挽救,挽回;回忆,追忆;收绕钓鱼线
- n.(尤指中枪猎物的)找回;收绕钓鱼线;<古> 恢复的可能性;检索
actual
- *adj.*真实的,实际的,现实的;(用于对比主次方面)真正的;现存的,当前的
default
- *n.*不履行,违约;默认,系统设定值;缺席,弃权
- *v.*违约,不履行义务;默认,预设;弃权,未到场
- *adj.*默认的