文章目录
一、vue简介
Vue(读音 /vjuː/,类似于 view) 是一套用于构建用户界面的渐进式JavaScript框架。
vue git地址
-
vue的优点
1、轻量级框架
vue是一个轻量级的渐进式JS框架,Vue.js通过简洁的API提供高效的数据绑定和灵活的组件系统。
2、简单易学
由国人开发,中文文档,不存在语言障碍,易于理解和学习
3、组件化开发
组件化开发,可以很好的降低数据之间的耦合度。将常用的代码封装成组件之后,就能高度的复用,提高代码的可重用性。
4、双向数据绑定。
vue.js通过MVVM模型实现数据的双向绑定,数据的改变会驱动视图的自动更新,让开发者不用再操作dom对象。
5、虚拟DOM
浏览器本身处理DOM是有性能瓶颈的,传统开发中,在对DOM进行频繁操作的时候,浏览器要不停的渲染新的DOM树,导致页面看起来非常卡顿。vue.js使用虚拟DOM进行了极大程度的性能优化
6、运行速度更快
相比较与react而言,同样都是操作虚拟dom,就性能而言,vue存在很大的优势 -
vue的两个核心点
1、双向数据绑定。
vue.js通过MVVM模型实现数据的双向绑定,数据的改变会驱动视图的自动更新,让开发者不用再操作dom对象。
2、组件化开发
组件化开发,可以很好的降低数据之间的耦合度。将常用的代码封装成组件之后,就能高度的复用,提高代码的可重用性。
1. vue基础
Vue2.0+Vue3.0最强全家桶教程丨vuejs快速入门
2. vue高级
二、MVVM模式
MVVM模式,全称为Model-View-ViewModel。在MVVM中,View为视图层,ViewModel为业务逻辑层,Model为数据层,可以实现数据双向绑定。
Model和View并无直接关联,而是通过ViewModel来进行联系的,Model中的数据会绑定到viewModel层并自动将数据渲染到页面中,View变化的时候会通知viewModel层更新Model中的数据
MVVM模式概念图:数据双向绑定
- View层:在Vue中是绑定dom对象的HTML
- ViewModel层:在Vue中是vue实例对象vm ----- let vm = new vue({})
- Model层:在Vue中是data、computed、methods等中的数据
三、双向数据绑定的原理
数据双向绑定包含两部分:
- 视图变化更新数据
- 数据变化更新视图
响应式是双向绑定的一环,是指通过数据驱动视图的变化,是单向的过程。
视图变化更新数据
view更新data,通过事件监听即可,比如input元素监听 ‘input’ 事件就可以实现视图变化更新数据
数据变化更新视图
vue2.x是采用数据劫持结合观察者模式的方式实现数据变化更新视图。
- new Vue() 首先执行初始化,对data执行响应化处理,遍历 data 中的所有的属性,为每个属性实例化一个dep实例,并使用Object.defineProperty方法对属性t进行劫持重写添加上getter和setter,在getter中收集依赖,setter中通知依赖更新
- compile 解析模板指令,将模板中的变量替换成数据,然后初始化渲染页面视图,并为每个指令对应的节点,实例化一个监听数据的订阅者watcher
- Watcher在自身实例化时往组件依赖的所有属性的订阅器里面添加自己。当被依赖的属性发生变化,触发setter函数,该属性对应的dep实例调用 notify 方法,遍历 dep.subs 向每个 watcher 发布更新通知,watcher接收到更新通知,调用自身的update()方法,触发render函数,生成新的虚拟 DOM 树
vue 出于性能的考虑,没有用 Object.defineProperty 去监听数组,而是通过一个拦截器,重写了操作数组的7个方法(分别是:push,pop,shift,unshift,splice,sort,reverse),使用object.defineProperty方法将这7个方法遍历逐个进行封装,实现将新增元素转化为响应式数据,并且通知依赖。【Array型数据还是在getter中收集依赖】
vue2.x响应式原理-数组篇
vue2 使用Object.defineProperty()来进行数据劫持有什么特点
只能监听某个属性,不能全对象监听。
【存在问题】:通过下标方式修改数组数据或者给对象新增、删除属性,这都不能触发组件的重新渲染。
【解决方法】:
- 对于对象和数组,都可使用Vue.set、Vue.delete或者vm.$set、vm.$delete等API进行操作。
- 对于数组,使用数组的splice()等api对数组进行操作,避免通过下标方式修改数组数据
vue3 使用proxy进行数据劫持
- vue3为什么使用proxy?
- Object.defineProperty只能监听某个属性,不能全对象监听,使用proxy可以进行全对象监听,省去了for…in 可以提升效率
- 使用proxy可以监听数组,不用去单独对数组进行特异性操作
- 使用proxy可以监听对象动态新增、删除的属性
- 使用proxy不会污染源对象
- 使用proxy唯一的缺点是Proxy 是 ES6 的语法,存在兼容性问题。
四、虚拟DOM
虚拟 DOM
说简单点虚拟 DOM 就是一个普通的 JavaScript 对象,包含了 tag、props、children 三个属性。用js对象模拟DOM节点的好处是,页面的更新可以先全部反映在js对象上,操作js对象的速度比直接操作dom的速度要快。等更新完后,再将最终的js对象映射成真实的DOM,可以提高性能。
<div id="app">
<p class="text">hello world!!!</p>
</div>
//*********************************************
//上面的 HTML 转换为虚拟 DOM 如下:
{
tag: 'div',
props: {
id: 'app'
},
children: [
{
tag: 'p',
props: {
className: 'text'
},
children: [
'hello world!!!'
]
}
]
}
// 手写代码----将真实dom转化为虚拟dom
const dom2tree = (node) => {
const obj = {}
if(node.tagName) {
obj.tag = node.tagName
} else {
// 文本节点
return node.data
}
obj.props = {}
// 获取元素的所有属性attributes ---- node.attributes
let len = node.attributes.length
for(let i=0;i<len;i++) {
obj.props[node.attributes[i].nodeName] = node.attributes[i].nodeValue
}
obj.children = []
node.childNodes.forEach(child => {
obj.children.push(dom2tree(child))
})
return obj
}
浏览器本身处理DOM是有性能瓶颈的,当操作DOM时,浏览器会从构建DOM树开始从头到尾执行一遍渲染流程。在对DOM进行频繁操作的时候,浏览器要不停的渲染新的DOM树,导致页面看起来非常卡顿。vue.js使用虚拟DOM能够进行极大程度的性能优化。虚拟 DOM 提升性能的点在于 DOM 发生频繁变化的时候,通过 diff 算法比对新旧两棵虚拟DOM树,计算出需要变更的 DOM,然后只对变化的 DOM 进行操作,而不是更新整个视图。
- 缺点:
1、 首屏加载时间更长。因为需要根据当前的节点,来生成对应的虚拟dom,所以在项目初始化的时候去生成对应的虚拟节点也是一笔时间上的开销;因此项目的首次加载可能耗费更多时间
2、 极端场景下性能不是最优解。比如,当前页面的节点基本全都改变了,那我们去做了一次diff过程相当于做了无效操作
1、diff 算法 — 比较两棵虚拟 DOM 树的差异;
- 从两边向中间进行同层比较,全部的对比完一整个dom结构,时间复杂度是 O(n^3) ; 同层对比的时间复杂度也是 O(n),使用同层比较的方法去牺牲了精度而提高了时间效率。
- 节点类型改变,直接销毁原节点,挂载新的节点 ,同时原节点的子节点也会被全部销毁。
- 节点类型一样,属性或者属性值发生变化,此时不会触发节点的卸载和挂载,只会触发当前节点的更新
- 删除/新增 节点,直接在newVDom中进行插入/删除。
- 文本变化,只会触发文本的改变
2、patch算法 — 将两个虚拟 DOM 对象的差异应用到真正的 DOM 树。
- patch(也叫做patching算法):虚拟DOM最核心的部分,它可以将vnode渲染成真实的DOM,这个过程是对比新旧虚拟节点之间有哪些不同,然后根据对比结果找出需要更新的的节点进行更新。这点从单词含义就可以看出, patch本身就有补丁、修补的意思,其实际作用是在现有DOM上进行修改来实现更新视图的目的。Vue的Virtual DOM Patching算法是基于Snabbdom的实现,并在些基础上作了很多的调整和改进。
五、axios
1. axios特点
- 从浏览器中创建 XMLHttpRequests
- 从 node.js 创建 http 请求
- 支持 Promise API
- 拦截请求和响应
- 转换请求数据和响应数据
- 取消请求
- 自动转换 JSON 数据
2. vue项目中简单使用axios
-
结合vue-axios使用
vue-axios用于将axios集成到Vuejs的小包装器//1. 安装 /* npm install --save axios npm install --save vue-axios */ //2. 在主入口文件main.js中引用 import axios from 'axios' import VueAxios from 'vue-axios' Vue.use(VueAxios,axios); //3. 使用axios ------- this.axios //例: methods:{ getNewsList(){ this.axios.get('api/getNewsList').then((response)=>{ this.newsList=response.data.data; }).catch((response)=>{ console.log(response); }) } }
-
axios 改写为 Vue 的原型属性
//1. 安装 /* npm install --save axios */ //2. 在主入口文件main.js中引用 import axios from 'axios' //3. axios挂在vue的原型链上 Vue.prototype.$axios= axios //3. 使用axios ------- this.$axios //例: methods:{ getNewsList(){ this.$axios.get('api/getNewsList').then((response)=>{ this.newsList=response.data.data; }).catch((response)=>{ console.log(response); }) } }
3. vue中axios封装以及api接口统一管理
4. axios拦截器[最好能实现一个精简版的]
- axios作用流程
<script>
/*
axios请求响应拦截器语法
// 添加请求拦截器
axios.interceptors.request.use(function (config) {
// 在发送请求之前做些什么
return config;
}, function (error) {
// 对请求错误做些什么
return Promise.reject(error);
});
// 添加响应拦截器
axios.interceptors.response.use(function (response) {
// 对响应数据做点什么
return response;
}, function (error) {
// 对响应错误做点什么
return Promise.reject(error);
});
*/
/*
* 手动实现axios拦截器的大概逻辑
*/
function axios(){
this.interceptors = {
//InterceptorsManager就是拦截器对象构造函数
request:new InterceptorsManager(),
response:new InterceptorsManager()
}
}
axios.prototype.request = function(){
// chain是一个数组,存储整个axios作用流程的所有操作,dispatchRequest是真正的请求操作
var chain = [dispatchRequest, undefined];
var promise = Promise.resolve();
// 请求拦截器处理
this.interceptors.request.handler.forEach((interceptor)=>{
//请求拦截器处理放在真正的请求之前
chain.unshift(interceptor.fulfilled, interceptor.rejected);
});
// 响应拦截器处理
this.interceptors.response.handler.forEach((interceptor)=>{
//响应拦截器处理放在真正的请求之后
chain.push(interceptor.fulfilled, interceptor.rejected);
});
//遍历chain数组,使用promise链式调用依次执行所有操作
while(chain.length){
promise = promise.then(chain.shift(),chain.shift());
}
return promise;
}
function InterceptorsManager(){
//存储拦截器设置的处理
this.handler = [];
}
InterceptorsManager.prototype.use = function(fullfilled,rejected){
this.handler.push({
fullfilled:fullfilled,
rejected:rejected
})
}
/*
* axios请求方法注册
* axios所有请求都是调用request方法来实现的
*/
const methods = ['get','post','delete'];
methods.forEach((method)=>{
axios.prototype[method] = function(){
//调用axios的request方法
this.request(method)
}
})
</script>
六. VueRouter
七. vue SSR
八. Vue的性能优化
- 尽量减少data中的数据,data中的数据都会增加getter和setter,会收集对应的watcher。data层级也不要太深。
- 合理使用v-if和v-show
- 合理使用computed
- 使用v-for时加key,以及避免和v-if同时使用。
- 采用keep-alive缓存组件
- 使用路由懒加载、异步组件
- 使用v-loader在开发环境做模板编译。
- 图片懒加载
- 第三方模块按需导入