目录
❣️ SPA: Single Page Application
1. 什么是单页面应用
2. 为什么要使用单页面应用
3. 何时使用单页面应用
4. 单页面应用的缺点
5. 如何实现单页面应用
6. 单页面应用创建后的结果
7. 单页面应用需要强调的注意点
8. 示例: 实现包含两个页面的基本的SPA应用
9. 关于404页面
10. 关于页头组件
11. 路由跳转: 2种
12. 路由传参: 3步
13. 单页面应用项目结构问题
扩展:this判断—8种指向
❣️ 总结:知识点提炼
【前文回顾】 vue中如何实现组件封装、组件化开发及组件间传参_08
单 页面 应用
整个应用程序只有一个唯一完整的HTML页面(有html、head、body)。其它所谓的"页面",其实都是组件而已。所谓的"页面跳转",其实只是在一个HTML中切换不同的组件显示而已。
闲话:关于SPA单页面的理解
单页Web应用(single-page application 简称为 SPA)是一种特殊的Web应用,它将所有的活动局限于一个Web页面中,仅在该Web页面初始化时加载相应的HTML、JavaScript和CSS,一旦页面加载完成了,SPA不会因为用户的操作而进行页面的重新加载或跳转,取而代之的是利用JavaScript动态的变换HTML的内容,从而实现UI与用户的交互,由于避免了页面的重新加载,SPA 可以提供较为流畅的用户体验,得益于ajax,我们可以实现无跳转刷新,又多亏了浏览器的histroy机制,我们用hash的变化从而可以实现推动界面变化,从而模拟元素客户端的单页面切换效果。
多页面 |
单页面 |
|
请求次数 |
每切换一次页面,都要向服务器发送请求,请求次数多 |
首次请求时,就把唯一完整的HTML页面和其他所有组件都下载到客户端本地。今后,无论怎样切换页面,都是在客户端切换不同的组件显示而已,不会像服务器端发送任何请求!请求次数少 |
公共资源的使用 |
每切换一次页面,都要重新请求公共的资源(bootstrap.css, jquery.js等)。请求次数多 |
单页面应用只在首次请求页面时,下载一次公共资源。之后切换页面时,除了组件部分之外,其余部分是保持不变的!所以不会反复请求公共的资源!请求次数少 |
页面加载效率 |
每次切换页面都要废弃旧的DOM树,重建整棵DOM树,所以效率低。 |
只在加载首页时,建立完整DOM树。之后,切换页面时,因为唯一完整的HTML页面是不变的,只更新局部的组件内容。所以,DOM树也不会重建,而是更新部分节点。效率高! |
页面切换动画 |
因为每次切换页面都是先清空前一个页面,再重新请求后一个页面。前后两个页面不可能并存在客户端。所以,几乎不可能实现页面切换动画。 |
因为所有的组件都在客户端了,所以完全有可能同时显示前后两个组件的部分内容,形成动画效果。 |
今后,只要使用框架开发项目,用的都是单页面应用!
首屏加载极慢!!!
(1). 原因: 首屏就要把所有页面组件内容都下载下来!下载内容比较多!
(2). 解决: 懒加载!(留待下一篇详细讲解,请持续关注)
3个主要的步骤
(1). 创建一个唯一完整的HTML文件
a. 标准的支持vue的页面结构
必须有new vue({})以及引入vue.js
b. 必须引入vue-router.js核心组件
c. 在唯一完整的页面内部添加
(2). 创建多个页面组件
a. 为每个页面组件创建独立的js文件
b. 每个页面组件都要创建为子组件的格式(不要用Vue.component())
(3). 在独立的router.js文件中创建路由器对象和路由字典列表:
a. 什么是路由字典: 专门保存地址栏中相对路径与组件对象之间对应关系的一个数组。
var routes=[
{ path:"/", component:Index },
{ path:"/details", component: Details}
... ...
]
path写相对路径,如果用户什么都不写””或是只写”/”的话,默认加载Index首页组件
b. 什么是路由器对象: 专门负责监控地址栏变化,并根据地址栏变化查找对应组件,替换页面中router-view的 核心对象
var router=new VueRouter({ routes })
可以把router看做一个装东西的壳比如地图软件,routes就是装在壳里面的东西比如地图的数据
c. 后续操作:
(1). 将所有页面组件文件和router.js文件都引入到唯一完整的HTML页面中。
强调: 所有页面组件必须先于router.js引入
(2). 将router对象加入到new Vue()中!
new Vue({
el:"#app",
router
})
只要地址栏相对路径一变,router对象会自动获得新的相对地址。自动去routes中查找对应的组件对象。最后用找到的组件对象代替HTML文件中
Vue的路由器采用锚点地址,作为客户端导航的相对地址:
http://127.0.0.1:5500/index.html#/相对路径 // 注意:路由器对象router监控的就是#后的东西
SPA/js/index.js
var Index={
template:`
这里是首页
`
}
SPA/js/details.js
var Details={
template:`
这里是详情页
`
}
SPA/js/router.js
//路由字典: 包含多对儿相对路径与组件对象间对应关系
var routes=[
{path:"/", component:Index},
{path:"/details", component:Details}
//强调: component后的组件对象名必须和组件.js文件中的组件对象名一致!
];
//路由器对象
var router=new VueRouter({
routes
})
SPA/index.html
Document
运行结果:
(1). 除了所有正确的路径之外,其余所有任意不正确的路径,都要跳转到404。
(2). 如何:
a. 在独立的js文件中创建一个NotFound组件
b. 在router.js中添加路由字典项: (列表的最后)
{ path:"*", component:NotFound } // 或是{ path:"/*", component:NotFound }
c. 在唯一完整的html页面中提前引入notFound.js文件。
(1). 因为页头可以用在任何一个页面中,不受限制,所以应该是一个全局组件。
(2). 如何: 4步:
a. 在独立的js文件中,先创建一个普通的子组件,包含页头的部分内容
b. 在唯一完整的HTML页面中引入页头.js文件,同时就引入了页头组件对象——暂时还不是全局组件!
强调: 页头组件不用加入router.js中。因为页头组件绝对不会单独展示!总是和别的页面配合一起展示。所以页头没有专门的路径与之对应!
c. 在new Vue()之前,外部,使用Vue.component()将页头子组件,转化为全局组件。
d. 使用页头组件: 2种:
1). 所有页面都需要页头,无一例外:
应该将页头组件写在
2). 有的页面需要页头,有的页面不需要页头
i. 不能放在
ii. 哪个页面需要页头,就在哪个页面组件的内部添加页头组件。那些不需要页头的组件,就不写。
(2). js中: this.$router.push("/相对路径")
(1). 修改router.js中路由字典中的路由地址,允许传参
{path:"/details/:变量名", component:Details, props:true},
(2). 跳转时,路径: /details/变量值,如下
或 如果动态绑定,to前面需要加冒号 例如: (3). 下个页面中如何获得地址栏中的参数值: a. router.js中的props:true,意为让地址栏中的参数值自动变成当前页面组件的props中的一个属性值 b. 下一个页面中就可以用: props:[ "变量名" ] (4). 坑: 一旦一个路径配置/:变量名,则必须携带参数才能进入该路径。如果不带参数,将被禁止进入! 那么多js文件都放在同一个js文件夹下,非常乱 解决: 建立专门的文件夹,分别保存不同的组件: views/文件夹,专门保存所有页面组件 components/文件夹,专门保存所有全局组件 router/文件夹,专门保存router.js文件。 扩展:route, routes, router 小结:SPA的概念以及优缺点 1. 优点: 1). 初次加载耗时多:为实现单页 Web 应用功能及显示效果,需要在加载页面的时候将 JavaScript、CSS 统一加载,部分页面按需加载。效果和性能确实和原生的有较大差距 闲话:web2.0名词解释 this 8种指向: 判断this, ➡️ 1. obj.fun() this->obj ➡️ 2. fun() 或 (function(){ ... })() 或 多数回调函数 或 定时器函数 this->window ➡️ 3. new Fun() this->new正在创建的新对象 ➡️ 4. 类型名.prototype.共有方法=function(){ ... } this->将来谁调用指谁,同第一种情况 ➡️ 5. DOM或jq中事件处理函数中的this->当前正在触发事件的DOM元素对象 如果需要使用简化版函数,必须$(this) ➡️ 6. 箭头函数中的this->箭头函数外部作用域中的this ➡️ 7. jQuery.fn.自定义函数=function(){ ... } this->将来调用这个自定义函数的.前的jQuery子对象, ➡️ 8. new Vue()中methods中的函数中的this->当前new Vue()对象 1. MVVM: 界面View+模型Model+视图模型ViewModel 2. Vue绑定原理: 访问器属性+虚拟DOM树 变量被修改时: 访问器属性发出通知,虚拟DOM树扫描并仅更新受影响的元素 3. 虚拟DOM树优点: (1). 小: 只包含可能变化的元素。 (2). 遍历查找快 (3). 修改效率高: 只修改受影响的元素。 (4). 避免重复编码: 已封装DOM增删改查代码 4. Vue功能3步: (1). 先创建增强版的界面: a. 整个界面必须包含在一个唯一的父元素下: 通常是 c. 触发事件的元素用@click="自定义处理函数名"标记 (2). 再创建new Vue()对象,其中el:指向new Vue()要监控的页面区域 (3). 在new Vue()对象内定义模型对象data和methods a.界面所需的所有变量都放在data中 b.界面所需的所有事件处理函数都放在methods中 5. 总结: 绑定语法+13种指令 (1). 如果元素的内容需要随变量自动变化: {{}} (2). 如果元素的属性值需要随变量自动变化: : (3). 控制一个元素显示隐藏: v-show //使用display:none隐藏元素 (4). 控制两个元素二选一显示: v-if v-else //使用删除元素方式隐藏元素 (5). 多个元素多选一显示: v-if v-else-if v-else (6). 只要反复生成多个相同结构的元素组成列表时: v-for :key="唯一标识" 强调: 为什么必须加:key="i"?给每个元素副本添加唯一标识。修改数组中某个元素值时,避免重建整个列表,只需要修改一个DOM元素副本即可!提高修改效率。 (7). 只要绑定事件: @ $event (8). 防止用户短暂看到{{}}: v-cloak和v-text (9). 只要绑定原始HTML代码片段内容: v-html (10). 如果元素的内容只在首次加载时绑定一次,之后都不会改变: v-once 优化: 减少虚拟DOM树中元素个数。 (11). 保护内容中的{{}}不被编译: v-pre (12). 今后只要想获得表单元素的值或状态: v-model 6. 绑定样式: (1). 需要精确修改某一个css属性,就绑定style: a. <元素 style="固定样式" :style="{css属性:变量名, ...}" data:{ ... : ... } b. <元素 style="固定样式" :style="变量名" data:{ css属性名: 属性值, ... : ... } } (2). 只要批量修改一个元素的多个css属性就绑定class a. <元素 class="固定class" :class="{class名:变量名, ...}" data:{ ... : ... } data:{ ... : ... } } 7. 只要希望在页面加载时自动对元素执行一些初始化操作时就用自定义指令: (1). 添加自定义指令: Vue.directive("自定义指令名",{ inserted(domElem){ } }) (2). 使用自定义指令: <元素 v-自定义指令名> 8. 今后只要根据其他变量的值动态计算出一个属性值就用计算属性: <元素>{{计算属性}} new Vue({ el:"#app", data:{...}, methods:{...}, computed:{ 计算过程 return 计算结果 } }) 9. 希望将变量的原始值先加工后再显示给用户看时就用过滤器: Vue.filter("过滤器名",function(oldVal, 自定义形参,...){ return 加工后的新值 }) <元素>{{ 变量 | 过滤器(实参值, ...) | ... }} 10. 只要在vue中发送ajax请求,就用axios axios.defaults.baseURL="服务器端接口的公共基础地址部分" axios.get( { params:{ 参数名: 参数值, ... } } ... result.data... }) 或 axios.post( "参数名1=参数值1&参数名2=参数值2&..." ... result.data... }) 强调: 在vue内使用axios,then中必须用箭头函数,保持then内this与外部this一致,都指向当前new Vue()对象 11. vue生命周期4个阶段 8个钩子函数 beforeCreate(){ ... } (1). 创建(create) created(){ ... } beforeMount(){ ... } (2). 挂载(mount) mounted(){ ... 经常在这里发送ajax请求 ... } beforeUpdate(){ ... } (3). 更新(update) updated(){ ... } beforeDestroy(){ ... } (4). 销毁(destroy) destroyed(){ ... } 12. 只要希望重用一块独立的功能区域就用组件: (1). 定义组件 Vue.component(`组件标签名`,{ template:`HTML内容片段`, data(){ return { 变量 } }, //其余和new Vue()完全相同 }) (2). 在HTML中使用自定义组件 <组件标签名/>或双标记也行 (3). 原理: new Vue()扫描到自定义组件标签, a.组件的template中的HTML内容代替页面中<组件标签>位置。 b. 并为这个小区域专门创建一个缩微版的vue类型对象。 1). 调用组件的data()函数为当前组件副本创建一个专属数据对象副本。 2). 引入组件对象中的methods等其他内容到当前组件对象副本中 13. 组件化开发: 1). 从上到下,按功能不同划分区域 2). 按是否重用划分 b. 为每个组件创建独立的.js文件,其中包含一个组件对象及其内容 c. 将所有组件引入唯一完整的html页面中,并在 a. new Vue()扫描 b. 父组件扫描自己内部的template内容,创建并替换子组件 (3). 三种组件: a. 根组件: new Vue() b. 全局组件: Vue.component(...) c. 子组件: 3步 1). var 子组件对象名={ 内容必须符合组件的要求 } 子组件对象名必须是驼峰命名 2). 父组件对象中:{ ... ... components{ 子组件对象名, ... ,... } } 子组件对象名必须是驼峰命名 3). 父组件template中用<子组件标签名/>引入子组件内容 components会将子组件对象名的驼峰命名自动翻译为-分隔 所以, 使用子组件标签时,要用-分隔多个单词 (2). 组件间传参: 父给子 a. 父组件给: <子组件 :自定义属性名="父组件变量"> b. 子组件取: props:["自定义属性名"] 结果: 在子组件内,props中的"自定义属性名"与子组件自己data中的变量用法完全相同! 14. SPA——单页面应用 (1). 3步: a. 先创建唯一完整的HTML页面 1). 包含vue基本的页面结构 2). 引入所有必要的文件和组件 vue-router.js, 其它页面或组件文件, router.js路由器对象所在文件 3). b. 再为每个页面组件创建独立的文件。每个页面组件其实都是一个子组件 c. 创建router.js文件,创建路由器对象 1). 创建路由字典对象: var routes=[ {path:"/", component:首页组件对象名}, {path:"/相对路径" , component: 其它页面组件对象名}, {path:"*", component: 404页面组件对象 } ] 2). 创建路由器对象,并将路由字典对象转入路由器对象中 3). 将router对象加入到new Vue()中 回到唯一完整的HTML页面中: new Vue({ el:"#app", router }) (2). 页头等全局组件: a. 创建独立的文件保存页头组件的内容 b. 使用Vue.component("my-header",{ ... })将页头创建为全局组件 c. 在唯一完整的HTML页面中引入页头组件文件 d. 使用页头组件标签 1). 如果所有页面都有统一的页头: 就放在唯一完整的html页面中 2). 如果有的页面有页头,有的页面没有页头: 就只放在需要页头的组件中的template中 (3). 路由跳转: 2种: a. html中: b. js中: this.$router.push("/相对路径") (4). 路由传参: a. 修改路由字典: {path:"/相对路径/:自定义参数名", component:页面组件对象, props:true} b. 跳转时: 或 this.$router.push("/相对路径/参数值") c. 下一个页面接: 1). props:[ '自定义参数名' ] 2). 可将"自定义参数名"用作绑定或程序中都行 【后文传送门】 如何安装vue 脚手架以及创建脚手架项目_10 如果这篇【文章】有帮助到你,希望可以给【青春木鱼】点个赞,创作不易,相比官方的陈述,我更喜欢用【通俗易懂】的文笔去讲解每一个知识点,如果有对【前端技术】感兴趣的小可爱,也欢迎关注❤️❤️❤️【青春木鱼】❤️❤️❤️,我将会给你带来巨大的【收获与惊喜】!
this.$router.push("/相对路径/参数值")
13. 单页面应用项目结构问题
1. router: 用new VueRouter()创建出的路由器对象
a. 监视地址栏变化
b. 还可以执行跳转动作!
2. routes: 一个路由字典数组,包含当前网站中所有路径与组件的对应关系列表。routes会被装入new VueRouter()即路由器对象router中,和router对象一起发挥作用!
3. route: 一个路由地址,代表当前地址栏中的url信息,像BOM中的location。地址栏:http://127.0.0.1:5500/index.html#/details
SPA( single page application )仅在 Web 页面初始化时加载相应的 HTML、JavaScript 和 CSS。一旦页面加载完成,SPA 不会因为用户的操作而进行页面的重新加载或跳转;取而代之的是利用路由机制实现 HTML 内容的变换,UI 与用户的交互,避免页面的重新加载。所以,基于以上SPA的特性,对单页应用来说模块化的开发和设计显得相当重要。
接下来,我们来总结、剖析一下SPA单页面应用都有哪些优缺点
1). 用户体验好、快,内容的改变不需要重新加载整个页面,避免了不必要的跳转和重复渲染。即无刷新界面,给用户体验原生的应用感觉
良好的交互体验,不刷新,减少服务端请求,ajax异步获取数据。另外,前端进行的是局部的渲染,所以可以规避不必要的跳转和重复渲染
2). 基于上面一点,SPA 相对对服务器压力小。
服务器只需要提供数据,不需要管前端的展示逻辑和页面合成,提高了性能。SPA应用中服务器可以先将一份包含静态资源(HTML CSS JS等)的静荷数据(payload)发送给客户端,之后客户端只需要获取渲染页面或视图数据即可。
3). 前后端职责分离,架构清晰,前端进行交互逻辑,后端负责数据处理。
前端负责view,后端负责model,各司其职
4). 共用一套后端程序代码,设配多端。
不用修改后端程序代码就可以同时适配用于web界面、手机、平板等多种客户端;无需考虑兼容性
5). 可以缓存较多数据,减少服务器压力。
6). 节省原生(android和ios)app开发成本
7). 提高发布效率,无需每次安装更新包
8). 符合web2.0的趋势
Web2.0 是相对Web1.0 的新的一类互联网应用的统称。Web2.0 更注重用户的交互作用,用户既是网站内容的浏览者,也是网站内容的制造者。
2. 缺点:
2). 前进后退路由管理:由于单页应用在一个页面中显示所有的内容,所以不能使用浏览器的前进后退功能,所有的页面切换需要自己建立堆栈管理。
3). SEO 难度较大:由于所有的内容都在一个页面中动态替换显示,正因为这样的特性,导致整个页面中没有html,所以在 SEO 上其有着天然的弱势, 不利于 SEO搜索引擎抓取,SEO(搜索引擎优化)难度高。
4). 页面复杂度提高很多,复杂逻辑难度成倍,开发难度较高
由于后端只提供数据而不再管前端的展示逻辑和页面合成,所以这些展示逻辑和页面合成都需要在前端进行编写(前进、后退等),所以会大大提高页面的复杂性和逻辑的难度,且业务随着代码量增加而增加,不利于首屏优化。
解决办法1 ⬇️
VUE SSR ——SSR服务器渲染,只是解决SEO问题;
解决方法2 ⬇️vue 首屏渲染优化有哪些
图片压缩 / 懒加载、js按需加载、使用cdn(cdn 引入公共库)、js放在body后边、压缩代码、移除console 、debugger、禁止生成 .map 文件、路由懒加载;
异步组件(const aa=resolve =>require(['../xxx/xx']),resolve);
修改webpack配置 、添加登录专用的router配置;
Web2.0 是相对Web1.0 的新的一类互联网应用的统称。
Web2.0 更注重用户的交互作用,用户既是网站内容的浏览者,也是网站内容的制造者。
每一个用户不再仅仅是互联网的读者,同时也成为互联网的作者;在模式上由单纯的“读”向“写”以及“共同建设”发展;由被动地接收互联网信息向主动创造互联网信息发展,从而更加人性化!
从工具上,是由互联网浏览器向各类浏览器、rss阅读器等内容发展;运行机制上,由“Client Server”向“Web Services”转变。
总之,Web2.0是以 Flickr、Craigslist、Linkedin、Tribes、Ryze、 Friendster、Del.icio.us、43Things.com等网站为代表,以Blog、TAG、SNS、RSS、wiki等应用为核心,依据六度分隔、xml、ajax等新理论和技术实现的互联网新一代模式。
闲话:web3.0是何物?
Web3.0只是由业内人员制造出来的概念词语,最常见的解释是,网站内的信息可以直接和其他网站相关信息进行交互,能通过第三方信息平台同时对多家网站的信息进行整合使用;用户在互联网上拥有自己的数据,并能在不同网站上使用;完全基于web,用浏览器即可实现复杂系统程序才能实现的系统功能;用户数据审计后,同步于网络数据。
产生背景
web2.0虽然只是互联网发展阶段的过渡产物,但正是由于2.0的产生,让人们可以更多地参与到互联网的创造劳动中,特别是在内容上的创造,在这一点上,web2.0是具有革命性意义的。人们在这个创造劳动中将获得更多的荣誉、认同,包括财富和地位。正是因为更多的人参与到了有价值的创造劳动,那么 “要求互联网价值的的重新分配”将是一种必然趋势,因而必然催成新一代互联网的产生,这就是web3.0。
互联网的技术日新月异,互联网不断深入人们的生活,web3.0将是彻底改变人们生活的互联网形式。web3.0使所有网上公民不再受到现有资源积累的限制,具有更加平等地获得财富和声誉的机会。
web3.0会从哪里开始呢?事实上,已经有了web3.0,只不过还没有得到足够多的了解。那就是电子商务领域和在线游戏。不管是B2C还是C2C,网民利用互联网提供的平台进行交易,在这个过程中,他们通过互联网进行劳动,并获得了财富。在线游戏通过积分的方式,角色扮演者通过攻城掠寨、不断地修炼、花费大量的时间,他们在那里可以获得声誉和财富,而这个财富通过一定的方式可以在现实中兑换,正所谓人生如同一场游戏,互联网会让人们的生活变得更像游戏一样。
当前的论坛也提供积分,但由于缺乏个性,这个不会成为未来的主流,最有代表性的blog,却在积分方面做得很少,劳动价值没有体现,也因为这样,好的bloger将另起炉灶,以便得到更多,这是在追求一种更加均衡的分配方式。
当这个2.0的参与者有足够力量和筹码的时候,他们就会要求一种对他们更公平合理的分配方式。在bloger个人力量不够的时候,可以通过联合的方式来争取自己的利益。
到来前提
web3.0到来的三个前提:
1、博客技术为代表,围绕网民互动及个性体验的互联网应用技术的完善和发展。
2、虚拟货币的普及和普遍,以及虚拟货币的兑换成为现实。
3、大家对网络财富的认同,以及网络财务安全的解决方案。
web3.0跟web2.0一样,仍然不是技术的创新,而是思想的创新,进而指导技术的发展和应用。web3.0之后将催生新的王国,这个王国不再以地域和疆界进行划分,而是以兴趣、语言、主题、职业、专业进行聚集和管理的王国。到时候真可谓是“皇帝轮流做,明年到我家”,你有机会打造出一个新的互联网王国而成为一个国王,也有可能会在互联网王国的民主竞选中成为总统,到时,你将拥有来自地球各个角落的网络公民。
其实说到这里,很多人应该已经看出来,没有什么所谓的2.0、3.0,因为你没法准确的界定他是什么样的应用,也没法界定它是什么时候开始的,什么时候结束,它只是互联网本身发展的一种趋势。
——内容来源于网络,仅供参考 扩展:this判断—8种指向
一定不要看定义在哪儿!只看调用时!不用再$(this)❣️ 总结:知识点提炼
b. 可能变化的元素内容用{{自定义变量名}}标记
变量名:css属性值
变量名:{
变量名:true或false,
b. <元素 class="固定class" :class="变量名"
变量名:{
class名:true或false,
对domElem执行DOM操作
计算属性名(){
}
"服务器端接口地址的相对路径",
).then(result=>{
"服务器端接口地址的相对路径",
).then(result=>{
(1). 步骤:
a. 拿到页面先划分功能区域
(2). 运行时:
var router=new VueRouter({ routes })