50 个知识点
王思惠
-
盒子模型
盒子模型分为W3C标准盒子模型、IE 盒子模型。一般在代码中使用 box-sizing 属性进行定义。
box-sizing:content-box 代表标准盒子模型
box-sizing:border-box 代表怪异盒子模型
box-sizing 默认值为content-box
标准盒子模型与 IE 盒子模型的核心差异在于:IE 盒子模型的 content 部分包含了 border 和 padding. 即 IE 盒子宽高固定的情况下,修改 border 和 padding 值,该盒子的大小不会改变。 -
BFC (Block Fromatting Context) (块级格式化上下文)
BFC 是一个独立的布局环境,其中的元素布局不受外界影响。
BFC 的应用: -
给两个盒子的父元素加上 BFC 布局避免垂直盒子排列的 margin 折叠问题。
-
给父块加上 BFC 布局避免父块和子块的 margin-top 一起坍塌问题。
-
给元素加上 BFC 布局避免它和浮动元素重叠。
-
清浮动。
如何触发 BFC 布局: -
Float 的值不是 none.
-
Position 的值不是 static 或者 relative.
-
Display 的值是 inline-block,table-cell,flex,table-caption 或者 inline-flex
-
Overflow 的值不是 visible
-
H5 新增了的新特性
-
语义化标签(语义化标签的出现是为了简化编程,并不意味着有了语义化就有什么特殊性,本质还是div)
Header(头部),nav(导航),main(主体),article(文章),aside(侧边栏),footer(底部) -
表单新增的 type 属性
Email,tel,url,number,search,range,color,time,date,datetime,datetime-local,month,week -
表单的其他属性
Placeholder,autofocus,required,pattern,multiple,datalist -
h5 新增表单事件
Oninput:内容改变即触发
Onkeyup:键盘弹起时触发
Oninvalid:验证不通过时触发
全屏接口,上传图片实时预览+进度条 -
伪类 :before 和 :after 的使用|伪类和伪元素有什么区别|常见伪类有哪些
:before 和 :after 的作用就是在指定的元素内容(非元素本身)之前或者之后插入一个包含 content 的属性指定内容的行内元素。
:after 也常用于清除浮动。
伪类:用于向某些选择器添加特殊的效果。例如:a 标签的 :link,:visited,:hover 等。
伪元素:是 html 中不存在的元素,用于将特殊效果添加到某些选择器。
一般来说,双冒号代表伪元素。如 ::before,::after 等,单冒号用于表示伪类。
常见的伪类:
链接伪类选择器:a:link,a:visited,a:hover,a:active
结构伪类选择器:li:first-child,li:last-child,li:nth-child(n),li:nth-child(odd),li:nth-child(even),li:nth-child(2n/3n/4n)
目标伪类选择器: :target 选择该文档中特定 “id” 元素 -
块水平居中的方法有哪些
父元素不添加样式|子元素不知道宽高 水平居中
Margin:0 auto;
Position:relative;left:50%;transform:translate(-50%)
父元素可以添加样式|子元素水平居中
父元素设置:display:flex;flex-direction:column; 子元素设置:align-self:center -
b 和 strong 的区别 | I 和 em 的区别
两者在网页中显示效果一样,单实际目的不同。b 标签对应 bold,即文本加粗,其目的仅仅是为了加粗显示文本,是一种样式/风格需求;strong 这个标签意思是加强,表示该文本比较重要,提醒读者注意。
还有一种说法:盲人朋友使用阅读设备阅读网络时,strong 会重读,b 不会。
I 是为了显示样式斜体而斜体,em 为了标明重点而斜体。 -
link 和 @import 的区别
link 属于 XHTML 标签,@import 则是 css 提供的一种方式。
link 标签除了可以加载 css 外,还可以做很多其他事情,比如定义 RSS, 定义 rel 连接属性等,@import 只能加载 CSS.
当一个界面被加载的时候,link 引用的 css 会同事加载,而 @import 引用的 css 会等到页面全部被下载才加载。
@import 只有在 ie5 以上才识别,link 无兼容性问题。
可以通过 JS 添加 link 标签来控制样式加载位置,覆盖等。@import 无法做到。 -
label 标签的作用
label 标签不会向用户呈现任何特殊效果,不过它为鼠标用户改进了可用性。如果在 label 元素内点击文本,就会触发此控件。就是说,当用户选择该标签时,浏览器就会自动将焦点转到和标签相关的表单控件上。
应用场景一:当需要做一个图片上传功能时,可以将 input 标签放到 lable 中,并在lable 中放置需要的图片或者文字。当用户点击 label 时,就相当于点击了 input。
应用场景二:当有一个原型单选框时,使用 lable 作为提示文字,这样点击文字就相当于点击了单选框,优化用户体验。 -
$(document).ready 和 window.onload 异同
$(document).ready 和 window.onload 都是在页面加载完执行的函数,大多数情况下差别不大,但也有区别。
$(document).ready 是 DOM 结构绘制完毕后就执行,不必等到加载完毕,不必等到页面中图片或者其他外部文件都加载完毕。并且可以写多个 .ready。
Window.onload 是页面所有元素都加载完毕,包括图片等所有元素。只能执行一次。
$(document).ready 先执行完毕。 -
事件冒泡|阻止事件冒泡|事件委托
事件冒泡:事件按照从最特定的事件目标到最不特定的事件目标(document)的顺序触发。
事件委托:事件从最不精确的对象开始触发,然后到最精确。
事件捕获和事件冒泡属于两个相反的过程。假设有这样一个文档结构: h5>div>body>html>document
如果给 h5 和 div 都设置点击事件。当 h5 点击时,不仅会触发自身的点击事件,还会向上冒泡/扩散,触发 div 的点击事件。基于这样一个原理,我们可以使用事件委托来减少代理子元素的点击事件。即 如果有多个元素需要设定点击事件,且它们属于同一个父块,那么给父块绑定一个点击事件,对绑定的子元素进行判断、添加执行语句即可。
阻止事件冒泡的两种方式:在子元素的点击事件中添加 return false;/event.stopPropagation()
值得注意的是,return false 不仅组织了事件往上冒泡,也阻止了事件本身。Event.stopPropagation()则只阻止事件往上冒泡,不阻止事件本身。、 -
自适应实现方式 | em 和 rem 简介
自适用实现方式主要有两种:
根据屏幕大小不同引入不同的 css 文件
使用 rem 单位实现自适应布局
rem 是指相对于根元素的字体大小的单位。简单来说,它是一个相对单位。em 是指相对于父元素的字体大小的单位。使用的时候,rem 是以页面 font-size 作为基准单位进行换算,即 假设界面 font-size=16px,那么 1rem = 16px,如果我们将界面 font-size 设置为32 px,那么 1rem = 32px.因此,当展示不同大小的界面时,分情况设定界面的 font-size 值即可。 -
浏览器组成
浏览器主要由以下八个部分组成。
用户界面
用户界面主要包括工具栏,地址栏,前进/后退按钮,数千菜单,可视化页面接在进度等等。
浏览器引擎
用来查询及操作渲染引擎的接口
渲染引擎
用来显示请求的内容,例如,如果请求内容为 html,它负责解析 html 及 css,并将解析后的结果显示出来。
网络
用来完成网络调用,例如 http 请求,它具有平台无关的接口,可以在不同平台上工作。
JavaScript 解释器
用于解释执行 js 代码
XML 解析器
将 XML 文档解析成文档对象模型树。
显示后端
用力啊绘制类似组合选择框及对话框等基本组件
数据持久层
数据持久层将与浏览绘画相关联的各种数据存储在硬盘上。这些数据可能是注入:书签、工具栏设置等这样的高级数据,也可能是诸如:Cookie,安全证书,缓存这样的低级数据 -
http keep-alive 相关知识点
http 协议采用“请求-应答”模式,当使用非 Keep-Alive 模式时,每个 请求/应答,客户端和服务端都要新建一个连接,完成之后断开连接。当使用 Keep-Alive 模式时,Keep-Alive 功能使客户端到服务端的连接持续有效,当出现对服务器的后继请求时,Keep-Alive 功能避免了建立或者重新建立连接。
目前大部分浏览器都是默认发起 Keep-Alive 请求,加入 Connection:close 才关闭
开启 Keep-Alive 模式更加高效,避免了连接建立和释放开销。但长时间的 Tcp 连接也容易导致系统资源无效占用,浪费系统资源。 -
http 缓存
前端发送请求需要经历 请求-处理-相应三个过程。如果用户重复请求统一资源的话,会对服务器资源造成浪费,服务器会重复读取资源,发送给浏览器后浏览器重复下载。造成不必要的等待。因此,请求之前会进行缓存读取,即浏览器在向服务器请求资源之前,先查询一下本地缓存中是否存在需要的资源,如果存在,就从缓存中读取。当缓存不存在或者过期,再向服务器发送请求。
缓存分为强制缓存和协商缓存。强制缓存判断 HTTP 首部字段:cache-control,Expires.
协商缓存又称对比缓存,对比缓存通过 HTTP 的 last-modified,Etag 字段进行判断 -
HTML5 的离线储存工作原理及作用
HTML5 的离线存储时基于一个新建的 .appcache 文件,通过这个文件上的解析清单离线存储资源,这些资源就会像 cookie 一样被存储了下俩,之后当网络在处于离线状态下时,浏览器会通过被离线存储的时数据进行页面展示。
使用该离线缓存辑置能够让用户在离线时使用它们,还能够让已经缓存的资源加载得更快,也减少了服务器的负载。 -
HTML 和 XHTML 关系和区别
XHTML 是 HTML 向 XML 的一个过渡语言,它比 HTML 更加严谨,但基本语言都还是沿用 HTML 标签。它与 HTML 不同主要表现在以下几个方面。 -
XHTML 的标记名称和属性名称必须小写。
-
XHTML 必须严格嵌套,标签的顺序必须一一对应。
-
XHTML 的标记和空元素也必须封闭,且 XHTML 中属性值必须用引号。
-
XHTML 中,属性值必须用完整形式,如 checked = “checked”,不能简写成 checked
-
介绍微格式
由于 HTML 中缺少相应的元素,很难突出显示人、地点或日期等类型的信息。为了i二觉这个问题,有一组开发人员决定开发一套标准的命名约定盒标记模式来表示这些数据。这些命名约定基于 vCard 和 iCalendar 等现有的数据格式,现称为微格式。 -
Src 和 href 区别
Src 是 source 的缩写,指向外部资源的位置,指向的内容将会嵌入到文档中当前标签所在位置;在请求 src 资源时会将其指向的资源下载并应用到文档内,例如 js 脚本,img 图片和 frame 等元素。
当浏览器解析到该元素时,会暂停其他资源的下载和处理,知道将该资源加载、编辑、执行完毕,图片和框架元素也如此,类似于将所指向资源嵌入当前标签内,这也是为什么将 js 脚本放在底部而不是头部。
Href 是 Hypertext Reference 的缩写,指向网络资源所在位置,建立和当前元素或者当前文档之间的连接。如果我们在文档中添加 ,那么浏览器就会识别该文档为css文档,就会并行下载资源并且不会停止对当前文档的处理。 -
Iframe 框架的作用
Iframe 是用来在网页中插入第三方页面,早期的页面使用 iframe 主要是用于导航栏这种很多页面都相同的部分,这样在切换页面的时候避免重复下载。
优点:便于修改,模拟分离,减少代码重复
缺点:加载比较慢,对 SEO 很不友好。 -
如何用 css 创建一个三角形
如果想将该块设定为三角形,则将该块宽高置0,然后设置块的 border 值。如果想要一个向下的三角形,则将 boder-top 加上颜色,其他颜色置为 transparent .向左则给 border-right 加上颜色,其他方向置为 transparent. -
Png、jpg、gif、svg、webp 图片格式异同
Png: 位图,支持透明,不支持动画。半透明的 png8 在 ie6 以下的浏览器显示为全透明,alpha 透明的全色 PNG 在 ie6 中会出现背景颜色。
Jpg: 全名 JPEG,不支持透明,不支持动画
Gif: 支持全透明和全不透明,不支持半透明。支持动画,无损耗。只支持 256 种颜色,不适合照片。
Svg: 矢量图,图像改变尺寸时不会损耗图形质量。
WebP:谷歌开发的一种新图片格式,同事支持有损和无损压缩,相比同质量的图片,webP 具有更小的文件体积。 -
Float 定位工作原理
浮动元素是脱离文档流的,遇到块时不占据空间,但是遇到内容时,内容会环绕浮动元素。
浮动元素碰到包含它的元素的边框或者其他浮动元素的边框会停下来。 -
Translate 使用
Translate() 函数可以将元素向指定的方向移动,类似于 position 中的 relative。或以简单的理解为,使用 translate() 函数,可以把元素从原来的位置移动,而不影响在 X,Y 轴上的任何web 组件。
Translate(x,y) 水平方向垂直方向同时移动。
TranslateX(x) 仅水平方向移动。
TranslateY(y) 仅垂直方向移动。
元素移动是以元素的中心点为基准进行移动的。 -
渐进式渲染
渐进式渲染适用于提高网页性能,以尽快呈现页面的技术。
懒加载:页面上的图片不会一次性全部加载。当用户滚动页面到图片部分是,JavaScript 将加载并显示图像。
分层次渲染:页面只包含基本的最少量的 CSS、脚本和内容,然后可以使用延迟加载脚本或建通 DOMContentLoaded/load 时间加载其它资源和内容。
异步加载 HTML 片段-当页面通过后台渲染时,把 HTML 拆分,通过异步请求,分块发送给浏览器。 -
状态码及其代表状态
200-成功。服务器已成功处理了请求。
202-接收请求但尚未处理
301-永久移动。请求的网页已永久移动到新的位置。
400-服务器无法理解请求语法
403-服务器拒绝请求
404-服务器找不到请求的网页
500-服务器内部错误
503-服务器暂时无法使用
504-服务器作为网关或代理,没有及时从上游服务器收到请求 -
从输入一个 url 到获取界面过程
浏览器的地址栏输入 URL 并按下回车
浏览器查找当前的 URL 是否存在缓存,并比较缓存是否过期
DNS 解析 URL 对应的 IP
根据 IP 建立 TCP 连接(三次握手)
HTTP 发起请求
服务器处理请求,浏览器接收 HTTP 响应
渲染界面,构建 DOM 树
关闭 TCP 连接(四次挥手) -
TCP 是如何发起连接和关闭连接的
发起连接:三次握手 -
客户端发送一个 SYN 段,并指明客户端的初始序列号,即 ISN©
-
服务端发送自己的 SYN 段作为应答,同样智能自己的 ISN(s).为了确认客户端的 SYN,将 ISN©+1 作为 ACK 数值。这样,每发一个 SYN,序列号就会加 1,如有丢失的情况,则会重传。
-
为了确认服务端的 SYN,客户端将 ISN(s)+1作为返回的 ACK 数值。
关闭连接:四次挥手 -
客户端发送完数据之后,向服务器发送一个 FIN 数据段,
-
服务器收到 FIN(i) 后,返回确认段 ACK,序列号为 i+1 ,关闭服务器都通道。客户端收到 ACK(i+1)后,关闭客户端写通道。
-
服务器发送完数据之后,向客户机发送一个 FIN 数据段,序列号为 J,关闭客户端读通道
-
服务器收到 ACK(j+1)后,关闭服务器写通道。
-
SEO 优化概念及做法
SEO ,全称 搜索引擎优化(search engine optimization),是一种透过了解搜索引擎的运作规则来调整网站,以提高目的网站在有关搜索引擎内排名的方式。
做法如下:
合理的title,description,keywords:title 值强调重点即可;description 把页面内容高度概括,不可过分堆砌关键词;keywords 列举重要关键词。
语义化的 HTML 代码,符合 W3C 规范:语义化代码让搜索引擎容易理解网页
非装饰性的图片必须加 alt
友情链接,外链,向各大搜索引擎登录入口提交尚未收录站点
重要内容 HTML 放在前面,少用 iframe,提高网站响应速度 -
Get 和 post 区别
Post 后退刷新,数据会被重新提交。
Get 可以被收藏为书签,可能被缓存,参数会保留在浏览器历史记录中。Post 不会。
Get 产生一个 TCP 数据包,post 产生两个 TCP 数据包。(注意,不是所有浏览器都会在 POST 中发送两次包,FireFox 就只发送一次) -
Bom的对象
Window 对象方法
alert(),confirm(),prompt(),open(),close(),setInterval(),clearInterval(),setTimeout(),clearTimeout(
Location
Location.reload() location.assign() location.href() location.replace()
History 对象
History.forward() history.back() -
遇到的跨域问题及其解决方法
同源策略为了保证用户信息的安全,防止恶意的网站窃取数据,禁止不同域之间的 js 进行交互。因此,只要协议,域名,端口有任何一个的不同,就会出现跨域问题。
解决跨域问题的方法: -
跨域资源共享(CORS):在后台中加上响应头来允许域请求即可。
-
通过 jsonp 跨域:通过 script 标签引入一个 js 文件,这个 js 文件载入成功后会执行我们在 url 参数中指定的函数,并且会把我们需要的 json 数据作为参数传入。
-
通过 document.domain,document.name 来跨子域
-
Json 和 jsonp 定义及用法
Json:js 对象的字符串形式.前后端交互常用数据格式。
JsonP:json with padding(填充式 JSON 或参数式 JSON ) 的简写,是应用 JSON 的一种新方法,常用于服务器域客户端跨源通信,在后来的 Web 服务中非常流行。 -
如何优化前端界面
页面级优化 -
减少 HTTP 请求数:从设计实现层面简化页面,合理设置 HTTP 缓存,资源合并与压缩,使用 CSS Sprites,使用懒加载。
-
将外部脚本置底。
-
减少不必要的 HTTP 跳转
-
避免重复的资源请求
代码级优化 -
减少 DOM 操作,减少重排
-
缓存已获取的内容,避免反复获取节点
-
减少选择符的查找范围
-
图片压缩
-
雪碧图 和 base64字符串优劣
雪碧图,即 CSS sprites 精灵图,通俗来说,就是有很多小图标合成一张大的图片就叫做雪碧图。
雪碧图优点:减少了 http 请求的次数,缓解了请求压力
雪碧图缺点:在高清屏幕上可能会失真,频繁的使用定位会占用比较多的 CPU.
Base 64 优点:把大量的图片请求合并在了 css 文件中,容易更新,
Base 64 缺点:会增加 25% 的图片资源大小,使用了 gzip 后,只增加 10%,不支持 IE6 和 IE7 -
== 和 === 的区别
===:等同符,两边值类型相同时,直接比较值,若类型不同,直接返回 false;
==:等值符,当等号两边类型相同时,直接比较值是否相等。若不相同,则先转化为类型相同的值,再进行比较。如果等号两边是 Boolean,string,number 三者中任意两者进行比较,优先转换为数字进行比较。
如果等号两边出现了 null 或者 undefined,null 和 undefined 除了和自己相等,就彼此相等
注意:NaN == NaN 返回 false -
Localstorage|sessionstorage|cookie 区别
存储大小 有效期 服务端通信 作用域 操作
LocalStorage 5M 永久有效 不参与 同源界面 Get.set
sessionStorage 5M 当前会话有效 不参与 当前界面 Get,set
Cookie 4K 设置有效期 http头信息中 同源界面 自己实现 -
Call,apply,bind 异同| callee 和 caller 作用
Call,apply,bind 都是改变函数运行时 this 的指向的,但 call 的参数是直接放进去的,而 apply 的参数则是以数组的形式放进去的。Call,apply 改变指向后可直接执行,bind 方法返回的是一个改变了上下文 this 后的函数,原函数中的 this 没有改变。因此 bind 需要手动执行,如下:obj.myFun.bind(db,param)().
Caller 返回一个函数的引用,这个函数调用了当前的函数。
Calle 放回正在执行的函数本身的引用。 -
Js 内置对象|数组常用接口
Js 内置对象: Object,Boolean,String,Number,Function,Array,RegExp,Date,Error
数组常用接口:forEach,every,some,sort,map,filter,slice,indexof,lastIndexOf -
Typeof 和 instanceof 区别
Typeof 返回值是一个字符串,用来说明变量的数据类型,字符串共有六种,undefined,Boolean,string,number,object,function.它对于 null 返回 object,对 NaN 返回 number,对对象、数组、正则的操作都返回 object.
Instanceof 用于判断一个变量是否属于某个对象的实例。 -
Var,let,const 异同
-
Var 声明的变量会挂载在 window 上,而 let 和 const 不会。
-
Var 声明变量存在变量提升,let 和 const 不存在变量提升。
-
Let 和 const 声明形成块作用域。
-
同一作用域下,let 和 const 不能声明同名变量,而 var 可以
-
Const 声明变量后,变量不可以再修改。
-
浅拷贝和深拷贝区别
如何区分深拷贝与浅拷贝,简单点来说,就是假设B复制了A,当修改A时,看B是否会发生变化,如果B也跟着变了,说明这是浅拷贝,拿人手短,如果B没变,那就是深拷贝,自食其力。。
基本类型的名字和值都存储在栈内存中,当复制的时候,栈内存会开辟一个内存。
引用类型(对象,数组,函数)数据名存在栈内存中,值存在堆内存中,栈只是提供要给引用的地址指向对内存的值。当进行拷贝时,复制的是该对象的引用地址,并被里面的值。
可以使用递归赋值/parse/stringfy 来完成深拷贝。 -
New 一个对象的过程中发生了什么?
-
创建了一个空对象。
-
将构造函数中的 this 指向新创建的对象。
-
将新创建的对象的 proto 属性指向构造函数的 prototype,创建对象和原型间的关系。
-
执行构造函数内的代码。
-
创建函数几种方式 | 函数和构造函数之间的区别
创建函数主要有三种方式:function sum(){},var sum = function(){},var sum = new Function()
只要通过 new 操作符来调用,那就是作为构造函数使用,此时 this 指向 new 出的实例。
如果不通过 new 操作符来调用,那就是作为普通函数使用,在非严格模式下,this 指向 window.且构造函数默认不需要 return 显式返回值。 -
实例化对象的返回值问题
构造函数里没有显式调用 return 时,默认是返回 this 对象,也就是新创建的实例对象。
当构造函数里调用 return 时,分两种情况。
如果 return 的是五种简单数据类型: String,Number,Boolean,Null,Undefined,这种情况下,构造函数依然返回 this 值。
如果 return 是 Object,则不在返回 this 对象,而是返回 return 语句的返回值。 -
闭包
闭包是指有权访问另一个函数作用域中变量的函数。创建闭包常见方式,就是在一个函数内部创建另一个函数。
Var 关键字在函数中声明变量,这个时候变量是局部变量,只有在该函数内部才能访问到这个变量,在函数外面是访问不到的。在普通函数中,如果定义一个变量,每次执行完该函数后,变量都会销毁,再次调用时会重新定义值,无法保留上次操作痕迹。但在闭包中,变量一直在某个地方生存,每次调用,都可以获取到上次调用的痕迹。
作用:闭包能够封装变量,把一些不需要包路在全局的变量封装成“私有变量”。 -
Prototype 和 proto 关系是什么
每个对象(包括函数、函数的 prototype 对象)都有一个 proto 属性,她指向创建该对象的函数的 prototype 属性。
每个函数都有一个 prototype 对象,而只有 prototype 对象才有 constructor 属性,其指向该函数本身。 -
箭头函数中的 this 与 一般函数中的 this 异同
箭头函数里是没有 this 的,普通函数是有 this 的。
箭头函数的 this 是在定义函数时绑定,普通函数是在执行函数时绑定。
箭头函数中,this 指向其定义环境,任何方法都改变不了其指向,如 call(),bind() 等。 -
For….in 迭代和 for……of 迭代的区别
For in 是遍历数组、对象的 key, 主要用来遍历对象。如果遍历数组,则输出数组下标,如果遍历对象,则输出对象的 key 值。
For of 遍历的是数组的 value.主要用来遍历数组。 -
原型|原型链|作用域链
在 javascript 中,每当定义一个函数数据类型,都会天生自带一个 prototype 属性,这个属性指向函数的原型对象,并且这个属性是要给对象数据类型的值。原型对象就相当于一个公共的区域,所有同一个类的实例都可以访问到这个原型对象,我们可以将对象中的共有内容,统一设置到原型对象中。
在 js 中,万物都是对象,对象和对象之间也有关系,并不是孤立存在的。对象之间的继承关系,在 JavaScript 中是通过 prototype 对象指向父类对象,直到指向 Object 对象为止,这样就形成了一个原型指向的链条,专业术语称之为原型链。 -
SPA 理解
SPA 即单页应用。传统的一个页面映射一个 .html,.css,.js 模式,切换界面需从服务器下载对应的 html ,css 和 js 文件,这就造成了页面加载速度的缓慢,影响了用户体验。
因此出现了一个新模式,就是组件化。组件化将不同的页面视为组件的不同排列组合,html 作为包裹这组合后的组建的容器,整个页面只有一个 html, 当也买你需要切换时,浏览器从服务器加载相应的组件。因此叫做单页应用,因为它只有一个 html 文件。