一旦页面加载完成,SPA 不会因为用户的操作而进行页面的重新加载或跳转;取而代之的是利用路由机制实现 HTML 内容的变换。所有的逻辑操作都在这个页完成
优点:用户体验号,运行速度快,对服务器压力小,最重要的是可以做到前后端分离
缺点:seo不友好、首次加载数据多
v-if是真正意义上的条件渲染;而v-show只是显示隐藏,元素总是会被渲染,并且只是简单地基于 CSS 的 “display” 属性进行切换。
v-if 适用于在运行时很少改变条件,不需要频繁切换条件的场景;v-show 则适用于需要非常频繁切换条件的场景。
Class 可以结合data定义属性值,通过对象语法和数组语法进行动态绑定。
所谓的单项数据流是指,父组件的prop只能流向子组件,而子组件的prop不能流向父组件,父组件prop值改变子组件也会跟着变,子组件想要改变父组件的prop,只能通过 $emit 派发一个自定义事件,父组件接收到后,由父组件修改。
computed是计算属性,依赖于其他属性值,而且computed存在缓存,其依赖属性不改变时他也 不会改变
Vue完整的生命周期,开始创建-初始化数据-模板编译-挂载DOM-渲染、更新-渲染-销毁
beforeCreate:组件实例被创建之初,组件的属性生效之前
created:组件实例已经完全创建,属性也绑定,但真实 dom 还没有生成, e l 还 不 可 用 b e f o r e M o u n t : 在 挂 载 开 始 之 前 被 调 用 : 相 关 的 r e n d e r 函 数 首 次 被 调 用 m o u n t e d : e l 被 新 创 建 的 v m . el 还不可用 beforeMount:在挂载开始之前被调用:相关的 render 函数首次被调用 mounted:el 被新创建的 vm. el还不可用beforeMount:在挂载开始之前被调用:相关的render函数首次被调用mounted:el被新创建的vm.el 替换,并挂载到实例上去之后调用该钩子
beforeUpdate:组件数据更新之前调用,发生在虚拟 DOM 打补丁之前
update:组件数据更新之后
activited:keep-alive 专属,组件被激活时调用
deactivated:keep-alive 专属,组件被销毁时调用
beforeDestory:组件销毁前调用
destoryed:组件销毁后调用
可以在钩子函数 created、beforeMount、mounted 中进行调用,因为在这三个钩子函数中,data 已经创建,可以将服务端端返回的数据进行赋值。但是本人推荐在 created 钩子函数中调用异步请求,因为在 created 钩子函数中调用异步请求有以下优点:1、能更快获取到服务端数据,减少页面 loading 时间;2、ssr 不支持 beforeMount 、mounted 钩子函数,所以放在 created 中有助于一致性。
在钩子函数 mounted 被调用前,Vue 已经将编译好的模板挂载到页面上,所以在 mounted 中可以访问操作 DOM。
1、子组件可以通过 KaTeX parse error: Expected '}', got 'EOF' at end of input: …ted() { this.emit(“mounted”);
}
2、可以在父组件引用子组件时通过 @hook 来监听
// Parent.vue
doSomething() {
console.log(‘父组件监听到 mounted 钩子函数 …’);
},
// Child.vue
mounted(){
console.log(‘子组件触发 mounted 钩子函数 …’);
},
// 以上输出顺序为:
// 子组件触发 mounted 钩子函数 …
// 父组件监听到 mounted 钩子函数 …
@hook 方法不仅仅是可以监听 mounted,其它的生命周期事件,例如:created,updated 等都可以监听。
因为组件可能被用来创建多个实例。如果 data 仍然是一个纯粹的对象,则所有的实例将共享引用同一个数据对象!通过提供 data 函数,每次创建一个新实例后,我们能够调用 data 函数,从而返回初始数据的一个全新副本数据对象。
v-model 本质上不过是语法糖。它负责监听用户的输入事件以更新数据,并对一些极端场景进行一些特殊处理。主要使用 v-model 指令在表单 input、textarea、select 等元素上创建双向数据绑定
1、props / $emit 适用父子组件通信
2、Vuex 适用于父子、隔代、兄弟组件通信
3、ref 如果在普通的 DOM 元素上使用,引用指向的就是 DOM 元素;如果用在子组件上,引用就指向组件实例
4、 $parent / $children 适用 父子组件通信
1、State:定义了应用状态的数据结构,可以在这里设置默认的初始状态。
2、Getter:允许组件从 Store 中获取数据,mapGetters 辅助函数仅仅是将 store 中的 getter 映射到局部计算属性。
3、Mutation:是唯一更改 store 中状态的方法,且必须是同步函数。
4、Action:用于提交 mutation,而不是直接变更状态,可以包含任意异步操作。
5、Module:允许将单一的 Store 拆分为多个 store 且同时保存在单一的状态树中。
1、服务端渲染的优点:
更好的 SEO: 因为 SPA 页面的内容是通过 Ajax 获取,而搜索引擎爬取工具并不会等待 Ajax 异步完成后再抓取页面内容,所以在 SPA 中是抓取不到页面通过 Ajax 获取到的内容;而 SSR 是直接由服务端返回已经渲染好的页面(数据已经包含在页面中),所以搜索引擎爬取工具可以抓取渲染好的页面。
更快的内容到达时间(首屏加载更快): SPA 会等待所有 Vue 编译后的 js 文件都下载完成后,才开始进行页面的渲染,文件下载等需要一定的时间等,所以首屏渲染需要一定的时间;SSR 直接由服务端渲染好页面直接返回显示,无需等待下载 js 文件及再去渲染等,所以 SSR 有更快的内容到达时间。
2、服务端渲染的缺点:
更多的开发条件限制: 例如服务端渲染只支持 beforCreate 和 created 两个钩子函数,这会导致一些外部扩展库需要特殊处理,才能在服务端渲染应用程序中运行;并且与可以部署在任何静态文件服务器上的完全静态单页面应用程序 SPA 不同,服务端渲染应用程序,需要处于 Node.js server 运行环境;
更多的服务器负载:在 Node.js 中渲染完整的应用程序,显然会比仅仅提供静态文件的 server 更加大量占用CPU 资源 (CPU-intensive - CPU 密集),因此如果你预料在高流量环境 ( high traffic ) 下使用,请准备相应的服务器负载,并明智地采用缓存策略。
vue-router 有 3 种路由模式:hash、history、abstract
hash: 使用 URL hash 值来作路由。支持所有浏览器,包括不支持 HTML5 History Api 的浏览器;
history : 依赖 HTML5 History API 和服务器配置。具体可以查看 HTML5 History
模式;
abstract : 支持所有 JavaScript 运行环境,如 Node.js 服务器端。如果发现没有浏览器的 API,路由会自动强制进入这个模式
hash 路由模式的实现主要是基于下面几个特性:
1、URL 中 hash 值只是客户端的一种状态,也就是说当向服务器端发出请求时,hash 部分不会被发送;
2、hash 值的改变,都会在浏览器的访问历史中增加一个记录。因此我们能通过浏览器的回退、前进按钮控制hash 的切换;
3、可以通过 a 标签,并设置 href 属性,当用户点击这个标签后,URL 的 hash 值会发生改变;或者使用 JavaScript 来对 loaction.hash 进行赋值,改变 URL 的 hash 值;
4、我们可以使用 hashchange 事件来监听 hash 值的变化,从而对页面进行跳转(渲染)。
history 路由模式的实现主要基于存在下面几个特性:
1、pushState 和 repalceState 两个 API 来操作实现 URL 的变化 ;
2、我们可以使用 popstate 事件来监听 url 的变化,从而对页面进行跳转(渲染);
3、history.pushState() 或 history.replaceState() 不会触发 popstate 事件,这时我们需要手动触发页面跳转(渲染)。
Model–View–ViewModel (MVVM) 是一个软件架构设计模式,MVVM 框架实现了双向绑定,这样 ViewModel 的内容会实时展现在 View 层,前端开发者再也不必低效又麻烦地通过操纵 DOM 去更新视图,MVVM 框架已经把最脏最累的一块做好了,我们开发者只需要处理和维护 ViewModel,更新数据视图就会自动得到相应更新。这样 View 层展现的不是 Model 层的数据,而是 ViewModel 的数据,由 ViewModel 负责与 Model 层交互,这就完全解耦了 View 层和 Model 层,这个解耦是至关重要的,它是前后端分离方案实施的重要一环。
1、View 层
View 是视图层,也就是用户界面。前端主要由 HTML 和 CSS 来构建 。
2、Model 层
Model 是指数据模型,泛指后端进行的各种业务逻辑处理和数据操控,对于前端来说就是后端提供的 api 接口。
3、ViewModel 层
ViewModel 是由前端开发人员组织生成和维护的视图数据层。在这一层,前端开发者对从后端获取的 Model 数据进行转换处理,做二次封装,以生成符合 View 层使用预期的视图数据模型。需要注意的是 ViewModel 所封装出来的数据模型包括视图的状态和行为两部分,而 Model 层的数据模型是只包含状态的,比如页面的这一块展示什么,而页面加载进来时发生什么,点击这一块发生什么,这一块滚动时发生什么这些都属于视图行为(交互),视图状态和行为都封装在了 ViewModel 里。这样的封装使得 ViewModel 可以完整地去描述 View 层。
Vue 数据双向绑定主要是指:数据变化更新视图,视图变化更新数据
首先理解下Vue的设计模式MVVM,详细见17
原理:Vue 内部通过 Object.defineProperty方法属性拦截的方式,把 data 对象里每个数据的读写转化成 getter/setter,当数据变化时通知视图更新。
Vue 主要通过以下 4 个步骤来实现数据双向绑定的:
1、实现一个监听器 Observer:对数据对象进行遍历,包括子属性对象的属性,利用 Object.defineProperty() 对属性都加上 setter 和 getter。这样的话,给这个对象的某个值赋值,就会触发 setter,那么就能监听到了数据变化。
2、实现一个解析器 Compile:解析 Vue 模板指令,将模板中的变量都替换成数据,然后初始化渲染页面视图,并将每个指令对应的节点绑定更新函数,添加监听数据的订阅者,一旦数据有变动,收到通知,调用更新函数进行数据更新。
3、实现一个订阅者 Watcher:Watcher 订阅者是 Observer 和 Compile 之间通信的桥梁 ,主要的任务是订阅 Observer 中的属性值变化的消息,当收到属性值变化的消息时,触发解析器 Compile 中对应的更新函数。
4、实现一个订阅器 Dep:订阅器采用 发布-订阅 设计模式,用来收集订阅者 Watcher,对监听器 Observer 和 订阅者 Watcher 进行统一管理。
参考《0 到 1 掌握:Vue 核心之数据双向绑定》
Vue 框架是通过遍历数组 和递归遍历对象,从而达到利用 Object.defineProperty() 也能对对象和数组(部分方法的操作)进行监听。
vm.$set 的实现原理是:
如果目标是数组,直接使用数组的 splice 方法触发相应式;
如果目标是对象,会先判读属性是否存在、对象是否是响应式,最终如果要对属性进行响应式处理,则是通过调用 defineReactive 方法进行响应式处理( defineReactive 方法就是 Vue 在初始化对象时,给对象属性采用 Object.de