Day01
一、响应式原理
vue2响应式的原理是借助数据劫持和发布订阅者模式
①数据劫持:
目的:能够感知到数据的改变。
数据劫持是:使用ES5的Object.defineProperty()。把data配置项中的所有数据进行遍历,转成setter和getter(或者说,给每个属性增加set和get函数)既就是:访问器属性。
②发布订阅者模式:
目的:当数据改变时,(直接和间接)使用该数据的模板处都会有相应的改变(模板会重新渲染)。
可能对方会进一步追问:能不能说的详细点。怎么回答?
1)、在vue构造函数里,循环变量data中所有属性。首先,保存属性的值,再利用Object.defineProperty()给每个属性增加set和get方法。然后,每个属性需要一个订阅对象,遍历dom树,让所有使用该属性的dom元素都订阅该属性。
2)、当修改某个属性的值时,该属性的set函数就被调用,同时会调用所有订阅该属性的订阅者(函数)
class Vue {
constructor(obj) {
this.$el = obj.el;
this.$data = obj.data;
// 2.1、订阅(暂时写死,只订阅msg的变化)
let observer1 = new Observer();
observer1.addSubscribe(function (newVal) {
document.getElementById("p01").innerHTML = newVal;
document.getElementById("p02").innerHTML = newVal;
document.getElementById("p03").innerHTML = newVal;
console.log(newVal);
});
// 把data中的属性赋给this对象
for (let key in obj.data) {
// 保存数据(data中的每个属性的数据)。
let value = obj.data[key];
// 2.1、订阅(应该放在此处)
// 1、数据劫持。
Object.defineProperty(this, key, {
set: function (val) {
console.log("val", val);
if (value == val) {
return;
}
value = val;
// 2.2、发布(更新使用key的dom元素)
observer1.publish(val);
},
get: function () {
return value
}
})
}
console.log("this", this);
this.render();
}
render() {
// this.$el
let htmlStr = document.querySelector(this.$el).innerHTML;
for (let key in this.$data) {
htmlStr = htmlStr.replaceAll("{{" + key + "}}", this.$data[key]);
}
document.querySelector(this.$el).innerHTML = htmlStr;
}
}
// 发布订阅模式的代码。
class Observer {
constructor() {
// 存放所有的订阅
this.arr = [];
}
// (添加)订阅
addSubscribe(cb) {
this.arr.push(cb);
}
// 发布
publish(what) {
this.arr.forEach(cb => {
(typeof cb === "function") && cb(what);
})
}
}
二、v-if和v-show区别
相同点:
( 都是控制 dom元素的显示和隐藏的)
不同点:
①原理不同:
v-if是通过dom元素的删除和添加,来完成显示和隐藏,
v-show是通过修改样式属性display的值,来完成显示和隐藏。
②性能消耗的不同
v-if:性能损耗主要体现在频繁切换时
v-show:性能损耗主要体现在首次
③使用场景的不同
v-if:用于切换不频繁的场景
v-show:用于切换频繁的场景。
④安全性的不同
v-if:安全性好(如果dom元素不显示时,在elements里根本看不到)
v-show:安全性不好。(如果dom元素不显示时,在elements里依然可以看到,那么,懂程序 的人,即可以修改)
三、为什么不建议v-for与v-if连用
①原因:
v-for的优先级比v-if优先级高,如果满足条件的数据相对(原始数据)较少,那么会造成大量性能浪费
②解决方案:
在computed里,先把满足条件的数据过滤出来。然后,v-for直接循环过滤出来的数据。而computed是有缓存的,所以,在原始数据没有变化时,不会多次过滤数据,这样,就提高了效率
//所以可以采取以下做法,先判断v-if
<div id="app">
<ul v-if="flag">
<li v-for="(item,index) in arr">{{index}}---{{item}}</li>
</ul>
</div>
<script>
var app = new Vue({
el: '#app',
data: {
flag: true,
arr: ['h', 'e', 'l', 'l', 'o']
}
})
</script>
Day02
一、双向的绑定原理
1、双向:M---->V V---->M
2、利用事件和属性完成的。
3、v-model是个语法糖。本质就是事件和属性的结合。
1)、针对文本框(单行和多行): value属性和input事件。如果加上修饰符lazy。事件变成了change事件。
2)、针对radio:使用的checked属性和change事件,同时需要给radio加上value属性
3)、针对checkbox:使用的checked属性和change事件
3.1)、如果应用在多选时,需要给checkbox加上value属性
3.2)、如果应用在单选时,不需要加
4)、针对select:使用value属性和change事件
v-model用在radio上的本质
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
</style>
</head>
<body>
<div id="app">
性别:
<input type="radio" v-bind:checked="sex=='女'" @change="changeSex" value="女" >女
<input type="radio" v-bind:checked="sex=='男'" @change="changeSex" value="男" >男
<hr/>
性别:
<input type="radio" v-model="sex" value="女" >女
<input type="radio" v-model="sex" value="男">男
<p>已选择的性别:{{sex}}</p>
</div>
</body>
</html>
<script src="./js/vue2.js"></script>
<script>
let vm = new Vue({
el: "#app",
data: {
sex:"女"
},
methods: {
changeSex(e){
this.sex = e.target.value;
}
}
});
</script>
v-model用在checkbox上的本质
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div id="app">
爱好:
<input type="checkbox" :checked="hobbys.includes('篮球')" @change="changeHobby" value="篮球">篮球
<input type="checkbox" :checked="hobbys.includes('足球')" @change="changeHobby" value="足球">足球
<input type="checkbox" :checked="hobbys.includes('乒乓球')" @change="changeHobby" value="乒乓球">乒乓球
<hr />
<input type="checkbox" v-model="hobbys" value="篮球">篮球
<input type="checkbox" v-model="hobbys" value="足球">足球
<input type="checkbox" v-model="hobbys" value="乒乓球">乒乓球
<p>爱好:{{hobbys}}</p>
</div>
</body>
</html>
<script src="./js/vue2.js"></script>
<script>
let vm = new Vue({
el: "#app",
data: {
hobbys: ['足球']
},
methods: {
changeHobby(e) {
// if(this.hobbys.includes(e.target.value)){
// this.hobbys = this.hobbys.filter(item=>item!=e.target.value);
// }else{
// this.hobbys.push(e.target.value);
// }
let idx = this.hobbys.indexOf(e.target.value);
if (idx == -1) {
this.hobbys.push(e.target.value);
} else {
this.hobbys.splice(idx, 1);
}
}
}
});
</script>
v-model在checkbox上使用(单个复选框)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div id="app">
<input type="checkbox" :checked="isRead" @change="changeRead">已阅读协议;
<hr />
<input type="checkbox" v-model="isRead">已阅读协议;
<p>阅读协议:{{isRead}}</p>
<hr />
<input type="checkbox" :checked="isRead2=='yes'" @change="changeRead2" true-value="yes" false-value="no">已阅读协议;
<input type="checkbox" v-model="isRead2" true-value="yes" false-value="no">已阅读协议;
<p>阅读协议:{{isRead2}}</p>
</div>
</body>
</html>
<script src="./js/vue2.js"></script>
<script>
let vm = new Vue({
el: "#app",
data: {
isRead: false,
isRead2: "no",
},
methods: {
changeRead() {
this.isRead = !this.isRead;
},
changeRead2(e) {
// this.isRead2 = (this.isRead2=='yes'?'no':'yes')
this.isRead2 = (this.isRead2 == e.target.getAttribute("true-value") ? e.target.getAttribute("false-value") : e.target.getAttribute("true-value"))
}
}
});
</script>
Day03
一、computed和watch的区别
①相同点:都可以监听数据
②不同点:
1)、概念:
computed: 是计算属性,依赖其它属性值,并且 computed 的值有缓存,当依赖的属性值发生改变时,才会重新计算 computed 的值,默认是只读的(相当于getter函数),它也可以设置getter和setter函数来完成读和写。
watch:更多的是观察的作用,每当监听的数据变化时都会执行回调进行后续操作,它只能设置getter。watch默认只监听一层。如果要深度监听,让deep属性为true。
2)、作用:
computed:是为了显示而用,降低了模板上代码复杂度。
watch:属性变化的检测(相当于事件),当属性的值发生变化时,可以调用函数。
3)、依赖模板调用:
computed:只能在模板上使用。
watch:不能在模板上使用。
4)、是否异步:
computed:不能有异步,只能同步。
watch:可以有异步。
二、什么是虚拟dom
所谓的虚拟 dom,也就是我们常说的虚拟节点,它是通过IS的Obiect对象模拟DOM中的节点,然后再通过特定的render (渲染) 方法将其演染成真实的DOM的节点。
三、如何实现深度监听
①首先,新建一个html项目,并在项目中引入vue
②引入wue后,在项目中定义一个监听对象
③监听对象定义好后,使用watch方法对整个对象进行监听
④最后,监听事件设置好后,在事件中添加一个deep属性,并设置为true,即可实现深度监听
(先定义监听对象,使用watch方法对整个对象进行监听,在事件中添加一个deep属性,并设置为true,即可实现深度监听)
四、过滤器怎么理解
过滤器是用来专门做数据格式转换的。如:文本的格式化
①定义指令
1)、全局定义:Vue.filter(“过滤器名”,过滤器函数(原始数据,))
2)、局部定义:在Vue对象里的filters配置项里写
②使用指令:
在模板上使用,用管道符。管道符前面 弓原始数据,管道符后面是过滤器的调用(就是 函数的调用)
过滤器的应用场景:平常在开发中,过滤器的应用场景有很多,比如单位转换、文本格式化、时间
格式化之类的等
五、this的理解?
①是什么?
this是函数的内置对象。this是代名词。this代表谁,需要看场景(上下文),在js中函数就是this的场景。所以,this一般都是出现在函数内部(其实这个本质是作用域)。
②this的几种情况(静态的描述) 以下情况所说的函数是非箭头函数。
1)、当this所在函数是事件处理函数时,this表示事件源。
2)、当this所在函数是构造函数时,this表示new出来的对象。
3)、当this所在函数是实例(对象)的方法时,this表示调用该方法的对象。
4)、当this所在函数是全局声明的函数时,
4.1)、非严格模式下:this表示window。(其实这个点和第三点一样)。因为,全局函数都是window对象的方法
4.2)、严格模式下:this是undefined。
5)、this在script标签里,表示window。
③真正的this,需要看调用(深深的知道就行,面试时,可以不用回答这个)。
1)、call,apply,bind是可以改变this指向的。
2)、所谓的构造函数,我也可以不用new调用把。
3)、所谓的全局函数,我也可以把它赋给事件属性。
④箭头函数是没有this的。
既就是:在判断this指向时,不要把箭头函数当函数看待。
一般人我不告诉他:箭头函数在编译的原理里是词法分析域
Day04
一、请问你怎么理解虚拟DOM和diff算法
所谓的虚拟 dom,也就是我们常说的虚拟节点,它是通过JS的Object对象模拟DOM 中的节点,然后再通过特定的render(渲染)方法将其渲染成真实的DOM节点
①什么是虚拟dom和diff算法:
虚拟DOM: 用JSON对象模拟的真实dom,用来提升性能(减少重绘回流)
diff算法:用来比较两个虚拟dom的不同之处。
②步骤(思路,流程)
2.1)、产生两个虚拟DOM树:newVDom,oldVDom。
2.2)、oldVDom和真实DOM保持一致
2.3)、数据变化时,影响的是(操作的是)newVDom
2.4)、操作newVDom后,通过diff算法对比newVDom和oldVDom的差异,并在oldVDom标注哪些节点要删除,哪些节点要增加,修改
2.5)、根据oldVDom操作真实的DOM,让真实Dom和oldVDom保持一致
③diff算法的解释:
逐步解析newVdom的节点,找到它在oldVdom中的位置,如果找到了就移动到下一个的DOM元素,如果没找到说明是新增节点,则新建一个节点插入。遍历完成之后如果oldVdom中还 有 没处理过的节点,则说明这些节点在newVdom中被删除了,删除它们即可。
二、单向数据流
父----->子 的数据传递是可以的。反之不行。
Prop(property的简写) 是单向绑定的:当父组件的属性(数据)变化时,将传导给子组件,但是反过来不会。这是为了防止子组件无意间修改了父组件的状态,来避免应用的数据流变得难以理解。 另外,每次父组件更新时,子组件的所有 prop 都会更新为最新值。这意味着你不应该在子组件内部改变 prop。如果你这么做了,Vue 会在控制台给出警告。
总结:
组件就是标签,prop是标签的属性。
prop是外部传入的数据,data是组件内部的数据。
三、data是个函数,vue组件的data为什么是个函数
一个组件的 data 选项必须是一个函数,且要有返回object(就是vue对象的data),只有这样,每个实例(vue组件对象)就可以维护一份被返回对象的独立的拷贝,否则,组件复用时,数据相互影响。即:组件的作用域(应该)是独立的。
简单回答:如果不是函数,那么,复用的组件的data共享同一块内存空间。
Day06
一、组件间通信:
①父子组件传值
1)、父--->子传:props,ref
ref:引用,通过ref可以找到子组件对象。ref跟原生中获得dom(如:getElementById)是一样的道理.需要品一段文字:自定义标签就是标签,js中获取dom就是在获取标签。组件就是dom对象
this.$refs.sonRef;// 等价于 document.getElementById("sonId");
通过this.$refs.sonRef,获取了dom对象,也就是相当于获取了子组件对象。
this.$refs.sonRef 就等价于子组件里的this【这句话一定要理解】
2)、子--->父传:emit
②兄弟组件
1)、子1--->父--->子2
2)、事件总线(event-bus)
原理:使用vue对象的$on和$emit完成。
具体做法:假设SonA给SonB传递数据。新建一个空的vue对象。在SonA里和SonB引入该vue对象。
$emit:触发事件(在SonA)
$on:绑定事件(在SonB)
二、ajax中的readyState和status
①readyState是什么意思:
readyState:是表示请求和响应过程中的状态(进行到了哪一步)。
0:未初始化,【XMLHttpRequest对象创建完毕】
1:初始化,【调用open完毕】
2:后端接收到请求,
3:后端正在处理
4:后端响应回来。
②status是什么意思:
status:表示响应结果的描述
200:(成功) 服务器已成功处理了请求这表示服务器提供了请求的网页。
400:(错误请求) 服务器不理解请求的语法
401:(未授权) 请求要求身份验证。
403:(禁止) 服务器拒绝请求
404:(未找到) 服务器找不到请求的网页
408:(请求超时) 服务器等候请求时发生超时
500:(服务器内部错误) 服务器遇到错误,无法完成请求
502:(错误网关) 服务器作为网关或代理,从上游服务器收到无效响应
503:(服务不可用)服务器目前无法使用 (由于超载或停机维护) 。通常,这只是暂时状态
504:(网关超时) 服务器作为网关或代理,但是没有及时从上游服务器收到请求
505:(HTTP 版本不受支持) 服务器不支持请求中所用的 HTTP 协议版本
三、原型和原型链
①原型:
1)、每个构造函数(类)都会有一个原型属性(prototype)。
2)、原型属性的目的:
让所有实例共享属性和方法,共享的是构造函数(类)的原型属性(prototype)上的属性和方法。由此,节约了内存。实例是通过 __proto__
属性找到构造函数(类)的prototype属性的。
3)、原型属性里还有一个constructor属性,指向构造函数(类)本身。
②原型链:
当使用对象访问属性或者方法时,先从对象本身的内存中寻找,如果找不到,就去 __proto__
(原型)指向的内存中(类的prototype)寻找,如果找不到,则在类的原型的 __proto__
(父类的prototype)寻找,以此类推,一直找到Object,如果没有找到,则显示出错(如: is not defined,或者 is not a function等等)。
这种一直沿着属性 __proto__
朝上寻找,就是原型链的寻找。也就是原型链的意思。
Day07
一、对MVC,MVP,MVVM的理解
三者都是项目的架构模式(不是类的设计模式),即:一个项目的结构,如果分层,不同层负责不同的职责。
①MVC:
MVC的出现是用在后端(全栈时代)
M:model,模型:
主要完成业务功能,在数据库相关的项目中,数据库的增删改查属于模型(重点)。(nodeJS中的db文件夹),没有页面,是纯粹的逻辑
V:view,视图:
主要负责数据的显示(HTML+CSS,动态网页(jsp,含有html的php文件))页面的展示和用户的交互。
C:controller,控制器:
主要负责每个业务的核心流程,在项目中体现在路由以及中间件上(nodeJS中的routes文件夹)
②MVP
MVP是把MVC中的C改成了P。主要限制了M和V之间不能直接通信(互相调用,传递数据)。M和V之间的通信必须经过P。
P:Presenter,表示器
主要用于连接M层、V层,完成Model层与View层的交互,还可以进行业务逻辑的处理。
③MVVM:
MVVM是把MVP中P改成了VM。主要体现的是MV之间和双向绑定。View的变动可以同步响应在Model,反之亦然。Vue就是一个MVVM的框架。准确来说,使用Vue框架完成项目时,使用的是MVVM模式。
VM:ViewModel
主要完成MV的数据通信,并且是双向绑定。而 View 和 Model 之间的同步工作完全是自动的,无需人为干涉,因此开发者只需关注业务逻辑,不需要手动操作 DOM, 不需要关注数据状态的同步问题,复杂的数据状态维护完全由 MVVM 来统一管理。
二、vue2,vue3的(组件对象的)生命周期【第四点不同】
①什么是生命周期
vue对象(组件)的生命周期,就是从创建,挂载,渲染,更新,到销毁的一系列过程。就是生命周期。
②vue2的生命周期有四个阶段和八个钩子函数
第一个阶段:数据挂载阶段。数据挂载阶段是把data配置项的属性挂载到vue对象本身。并做劫持
前后分别有一个钩子函数: beforeCreate,created
第二个阶段:模板渲染阶段:把数据渲染(显示)在模板上。
前后分别有一个钩子函数: beforeMount,mounted
第三个阶段:模板更新阶段:当数据(在模板上使用的数据)发生改变时,会把新的数据渲染到模板上。
前后分别有一个钩子函数:beforeUpdate,updated
vue2:
第四个阶段:组件销毁:前后分别有一个钩子函数:beforeDestroy 和 destroyed
vue3:
第四个阶段:组件销毁:【只有这一点和vue2不一样】
前后分别有一个钩子函数:beforeUnmount 和 unmounted
Day08
一、keep-alive
keep-alive 可以缓存组件及其状态 (数据),避免了组件的频警创建和销毁所带来的性能损耗。
它有三个特性:
①用于缓存组件,一般结合路由和动态组件一起使用。
②提供 include 和 exclude 属性。两者都支持字符中或正则表达式,include 表示只有名称匹配的组件会被缓存,exclude 表示任何名称匹配的组件都不会被缓存,其中 exclude 的优先级比 include 高
这两个 prop 的值都可以是一个以英文过号分隔的字符串、一个正则表达式,或是包含这两种类型的一个数组:它会根据组件的 name 选项进行匹配,所以组件如果想要条件性地破 Keeplive 级存,就必须显式声明一个 name选项。
中
③对应两个钩子函数 activated 和 deactivated,当组件被激活时,触发钩子函数 activated,当组件被移除时,触发钩了函数 deactivated。
二、Vue 的父组件和子组件生命周期钩子函数执行顺序?
Vue 的父子组件钩子函数的执行顶序可以归类为4个 部分:
第一部分:首次加载渲染
父 beforeCreate ->父 created > 父 beforeMount -> 子 beforeCreate -> 子 created >子
beforeMount -> 子mounted -> 父mounted.
第二部分: 父组件修改子组件的props值时
父 beforeUpdate -> 子 beforeUpdate -> 子updated -> 父 updated
第三部分:父组件修政的数据跟子组件没有关系时
不会影响了组件 父 beforeUpdate ->父 updated
第四部分:销毁过程
beforeDestroy ->子beforeDestroy ->子destroyed -> 父 destroyed
Day09
一、axios的拦截器
①axios拦截器是什么?
拦截器是在前后端交互(请求和响应)到达对方之前调用的回调函数。所有的请求都会调用该回调函数
②拦截器分为:
请求拦截器:请求到达后端前调用的回调函数
响应拦截器:响应到达前端前调用的回调函数
③拦截器解决的问题:
1)、请求拦截器: 能够处理所有请求(到达后端前)的公共业务,如: 携带token,loading的显示,请求体加验证、设置请求头等等。针对不同请求类型做不同类型的处理等等。
2)、响应拦截器:能够处理所有响应(到达前端的then 或 catch) 的公共业务,如:数据统一处理,响应的错误状态码,loading的隐藏等等。
Day10
一、$router和$route的区别
①$router是vue-router对象,是创建的vue-router对象,该对象具有路由相关api,如: push( ),
replace ( ) go(), back(), forward()
②$route是匹配到的路由对象。当地址栏的路径发生变化时,会匹配某个路由配置。然后,vue-router对象就会在组件上去产生一个$route对象,来保存匹配到的路由的相关信息,包括:传递的参数,路由元信息等(如:path,params,query等等)
二、两种路由模式的区别
①外观上的区别: 1)、hash有# 2)、history没有#
②原理上的区别:
1)、hash用的是锚点连接。背后使用location.href和window.hashchange事件。锚点连接自带历史记录。
2)、history背后用的是history.pushState 来记录页面的历史记录。
③跟后端有关的区别:
1)、hash和后端没有关系
2)、history和后端有关系。当地址栏发生变化后,浏览器默认会发送请求给服务器(服务器上的资源html,css,js,api接口,后端渲染的页面,等等),所以,当前后端不分离时: 需要保证前端路径和后端的api或者后端渲染的页面不要重名。另外,前后端分离,前端服务器需要配置一个针对404页面时,返回index.html.
三、路由传参
①vue-router有两种传参方式:params和query。
②params
首先,需要在路由配置中使用动态路由匹配{path:“/路径/:参数名”,name:"路由名”}
1)、传(跳转时传,编程式和声明市相同)
//声明式:
1)、字符串写法
<router-link to="/路径/参数的值"></router-link>
//编程式:
this.$router.push("/user /01001");
2、对象写法
<router-link :to="{name:路由名,params:{参数名:参数值}}"></router-link>
//编程
this.$router.push({ name: user', params: { id: 01001' }})
2)、接[路由的组件内部接收]
this,$route.params,参数名
③queny
1)、传
//声明式
//1)、字符串写法:
<router-link to=路径?参数名1=参数值&参数名2=参数值2”></router-link>
//2) 对象写法:
<router-link :to="{path路径?参数名1=参数值&参数名2=参数价2}}"></router-link>
//编程式
同上
2)、接
this.$route.query.参数名
Day11
一、路由懒加载(按需加载)
①为什么要用
减轻服务器压力,加快页面呈现速度,对象的实例化在getter方法中,各司其职,降低耦合性.
②什么是
懒加载其实就是延时加载,即当对象需要用到的时候再去加载相关的对象
③解决方案
-
vue异步组件
-
es 的 import()
-
webpack的require.ensure()
二、路由守卫
①什么是路由守卫
控制组件的跳转,对是否能够进入某个路径对应组件做限制。根据业务逻辑来判定是否可以进入某个组件。
②路由守卫有哪些分类
1)、全局守卫
1.1)、前置钩子 : beforeEach
1.2)、后置钩子:afterEach
2)、路由独享守卫
2.1)、只有前置: beforeEnter
3)、组件内部守卫
3.1)、前置 : beforeRouteEnter
3.2)、路径更新,组件复用 :beforeRouteUpdate
3.3)、离开:beforeRouteLeave
③路由钩子函数的参数:
to:要跳转到的路由(路由对象信息)目标
from:从哪里跳转的路由 (路由对象信息)来源
next: 函数体必须要next()才会让路由正常地跳转和切换,next(false)在原地停留,next(“强制修改到另一个路由路径上”
Day12
一、vuex
①vuex是什么
vuex是一个状态(数据)管理工具,它能够完成组件之间的数据共享(组件的通信)
②vuex的作用
1)、vuex能够保存全局数据(数据仓库),供整个应用使用
2)、vuex保存的数据是响应式的
3)、vuex保存的数据可以跟踪状态的变化
③vuex的(核心概念)配置项:
1)、state : 数据仓库 ,存储所有的 共享数据 ,相当于vue组件里的data
2)、Getters : 在state的基础上 派生的数据, 相当于vue组件里 computed
3)、Mutations:修改state的数据时,用mutation,这与跟踪状态 有关系,只能有同步代码
4)、Action:解决mutation里只能有同步代码的问题,action里可以有异步代码
5)、modules:模块化
④vuex的数据流转
vue组件 派发(dispatch)action。action里提交(commit)mutation,mutation里修改(mutate)state的数据,state的数修改后,会响应式渲染到模板上。
⑤模块化怎么使用
1)、当项目比较大时,所有的全局数据存放在state里,会非常混乱,怎么办?使用module,把数据分门别类的进行处理,即:模块化。 每个模块是一个独立的store。然后由总体的store引入所有的分模块store。
2)、怎么解决(getters,mutations,actions)的重名
2.1)、namespaced:true
2.2)、使用模块中getters,mutations,actions时,前面需要加上模块名:
格式:
模块名/getters或者mutations或者actions的名字
⑥辅助函数:
mapState, mapGetters,mapMutations, mapActions
1)、作用:
简化代码:在组件里不需要使用$store 了。
2)、具体使用:
mapState, mapGetters 会映射到组件的computed上
mapMutations, mapActions 会映射到组件的methods里。
Day13
$nextTick的实现原理:
①为什么用Vue.nextTick()
首先,JS是单线程的,那么,它如何处理异步操作。
所有同步任务都在主线程上执行,形成一个执行栈。
主线程之外,会存在一个任务队列,只要异步任务有了结果,就在任务队列中放置一个事件(所以,也叫事件队列),进行排队(处于等待状态)。
当执行栈中的所有同步任务执行完后,就会读取任务队列(事件队列)中的任务(事件)。即:任务队列中的任务就结束了等待状态,进入执行栈。
主线程不断重复第三步。直到任务队列和执行栈里的代码执行完毕。
了解一个事件循环: javascript的事件循环(event loop)_jiang7701037的博客-CSDN博客
其次,vue更新DOM的思路。使用的就是异步更新队列,所以,就使用了事件循环。目的是提高性能,避免无效的重复的DOM更新。即:vue中更新数据后,并不会立即更新DOM,而是把数据引起的DOM更新放入到异步更新队列里。等待下次事件循环(tick),并在两个tick之间进行UI渲染。这样程序员就不能在更改数据后,立即获取更新后的DOM,也不知道什么时候DOM能够更新。基于此,vue提供了nextTick函数。程序员把操作更新后DOM的代码放入到nextTick的回调函数里。由nextTick内部,在更新完DOM后,调用回调函数。 示例代码:
this.msg = "hello"
this.$nextTick(()=>{
操作更新后DOM的代码。
});
②什么是Vue.nextTick()
Vue.nextTick的代码思路示意
function nextTick(cb){
//DOM 更新
cb();
}
那么,vue是如何知道DOM更新了?
MutationObserver:这是HTML5新增的API。用于监视DOM变动的接口,它可以监听一个DOM对象上发生的子节点删除、属性修改、文本内容修改等
另外,考虑到,微任务比宏任务耗时少,浏览器的兼容性。所以,vue中延迟调用优先级如下: Promise > MutationObserver > setImmediate > setTimeout
③应用场景:
答:当需要操作 ”数据更新影响的(新的)dom时“,就使用$nextTick()。而且,必须在数据更新后立即调用$nextTick();
换种说法:当需要操作dom,而且这个dom是由于数据更新(修改)后引起重新渲染的dom。
你可以这么认为,$nextTick(cb); 是updated,是某个数据引起的updated,而不是所有数据引起的updated
SPA的理解
①单页面应用的概念
SPA:single page application,单页面应用。
就是整个项目就只有一个html页面(文件),首次加载时,把所有的html,css,js全部加载下来。通过操作dom的删除和创建(添加)来完成页面的切换。
②单页面应用优缺点
优点:
1)、单页应用相对服务器压力小。【因为:首次、或者只要HTML,CSS和JS加载完毕后,切换页面是不用再去服务器请求HTML,CSS和JS】
2)、局部刷新,所以,用户体验好。【通过删除、添加、修改DOM的方式】
3)、前后端分离
4)、页面效果会比较炫酷(比如切换页面内容时的转场动画)
缺点:
1)、不利于SEO(Search Engine Optimization)。如:百度,360等搜索引擎收录。
2)、初次加载时耗时多(可以使用路由懒加载解决)
3)、导航不可用,如果一定要导航需要自行实现前进、后退(vue-router做好了)。页面复杂度提高很多
4)、容易造成CSS命名冲突。【用scoped或者BEM的方式解决】