相同点:v-show和v-if都能控制元素的显示和隐藏
不同点:手段:v-if是动态的向DOM树内添加或者删除DOM元素;
v-show是通过设置DOM元素的display样式属性控制显隐;
编译过程:v-if切换有一个局部编译/卸载的过程,切换过程中合适地销毁和重建内部的事件监听和子组件;
v-show只是简单的基于css切换;编译条件:v-if是惰性的,如果初始条件为假,则什么也不做;只有在条件第一次变为真时才开始局部编译;
v-show是在任何条件下,无论首次条件是否为真,都被编译,然后被缓存,而且DOM元素保留;性能消耗:v-if有更高的切换消耗;
v-show有更高的初始渲染消耗;使用场景:v-if适合运营条件不大可能改变;v-show适合频繁切换。
Vue组件可能存在多个实例,如果使用对象形式定义data,则会导致它们共用一个data对象,那么状态变更将会影响所有组件实例,这是不合理的;采用函数形式定义,在initData时会将其作为工厂函数返回全新data对象,有效规避多实例之间状态污染问题。而在Vue根实例创建过程中则不存在该限制,也是因为根实例只能有一个,不需要担心这种情况。
用法:将回调延迟到下次DOM更新循环之后执行。在修改数据之后立即使用它,然后等待DOM更新。它跟全局方法 Vue.nextTick 一样,不同的是回调的 this 自动绑定到调用它的实例上。
$nextTick() 的应用场景
在vue的生命周期 created() 钩子函数中进行 dom 操作,一定要放在 $nextTick() 函数中执行。在 created() 钩子函数执行的时候 DOM 其实并未进行任何渲染,而此时进行 DOM 操作无异于徒劳,所以此处一定要将 DOM 操作的代码放进 nextTick() 的回调函数中。
mounted() 钩子函数,因为该钩子函数执行时,所有的 DOM 挂载和 渲染都已完成,此时在该钩子函数中进行任何 DOM 操作都不会有问题
在数据变化后要执行某个操作,而这个操作需要随数据改变而改变DOM结构时,这个操作都是需要放置 $nextTick() 的回调函数中。
Vue 数据双向绑定主要是指:数据变化更新视图,视图变化更新数据
实现原理:采用数据监听、解析结合订阅者模式的方式,通过Object.defineProperty()来监听各个属性的setter,getter,在数据变动时发布消息给订阅者,触发相应的监听回调。从而实现数据的双向绑定
主要分为以下几个步骤:
需要observe的数据对象进行递归遍历,包括子属性对象的属性,都加上setter和getter这样的话,给这个对象的某个值赋值,就会触发setter,那么就能监听到了数据变化
compile解析模板指令,将模板中的变量替换成数据,然后初始化渲染页面视图,并将每个指令对应的节点绑定更新函数,添加监听数据的订阅者,一旦数据有变动,收到通知,更新视图
Watcher订阅者是Observer和Compile之间通信的桥梁,主要做的事情是: ①在自身实例化时往属性订阅器(dep)里面添加自己 ②自身必须有一个update()方法 ③待属性变动dep.notice()通知时,能调用自身的update()方法,并触发Compile中绑定的回调,则功成身退。
MVVM作为数据绑定的入口,整合Observer、Compile和Watcher三者,通过Observer来监听自己的model数据变化,通过Compile来解析编译模板指令,最终利用Watcher搭起Observer和Compile之间的通信桥梁,达到数据变化 -> 视图更新;视图交互变化(input) -> 数据model变更的双向绑定效果。
实践中不管是vue2或者vue3都不应该把v-if和v-for放在一起使用。
在 vue 2.x 中,在一个元素上同时使用 v-if 和 v-for 时, v-for 会优先作用。
在 vue 3.x 中, v-if 总是优先于 v-for 生效。
vue2中v-for的优先级是高于v-if的,放在一起,会先执行循环在判断条件,并且如果值渲染列表中一小部分元素,也得再每次重渲染的时候遍历整个列表,比较浪费资源。
vue3中v-if的优先级是高于v-for的,所以v-if执行时,它调用相应的变量如果不存在,就会导致异常
.stop:等同于 JavaScript 中的 event.stopPropagation() ,防止事件冒泡;
.prevent :等同于 JavaScript 中的 event.preventDefault() ,防止执行预设的行为(如果事件可取消,则取消该事件,而不停止事件的进一步传播);作用是阻止默认事件(例如a标签的跳转
.capture :与事件冒泡的方向相反,事件捕获由外到内;
.self :只会触发自己范围内的事件,不包含子元素;
.once :只会触发一次。
.trim修饰符的作用是把v-model绑定的值的首尾空格给去掉。在实际开发中我们一般用于搜索框的内容修饰,过滤掉用户多输入前后空格导致内容查不出来的情况。
.left,.right,.middle这三个修饰符是鼠标的左中右按键触发的事件.
为什么需要自定义指令:因为vue是MVVM模式,只需要关注于数据和业务逻辑,不需要关注DOM的操作,但是有时候面对一些特殊的业务需求时,需要进行DOM的操作,这个时候就需要进行自定义指令。
自定义局部指令:在options api选项中的directives中设置。局部自定义指令是一个对象,对象的属性是自定义指令的名称,对象中属性的值是自定义指令的钩子函数对象
自定义全局指令:在app的directive方法。参数一(name):自定义指令的名称。参数二(hooks):自定义指令的钩子函数对象
slot又名插槽,是Vue的内容分发机制,组件内部的模板引擎使用slot元素作为承载分发内容的出口。插槽slot是子组件的一个模板标签元素,而这一个标签元素是否显示,以及怎么显示是由父组件决定的。slot又分三类,默认插槽,具名插槽和作用域插槽。
默认插槽:又名匿名插槽,当slot没有指定name属性值的时候一个默认显示插槽,一个组件内只有有一个匿名插槽。
具名插槽:带有具体名字的插槽,也就是带有name属性的slot,一个组件可以出现多个具名插槽。
作用域插槽:默认插槽、具名插槽的一个变体,可以是匿名插槽,也可以是具名插槽,该插槽的不同点是在子组件渲染作用域插槽时,可以将子组件内部的数据传递给父组件,让父组件根据子组件的传递过来的数据决定如何渲染该插槽。
实现原理:当子组件vm实例化时,获取到父组件传入的slot标签的内容,存放在vm.$slot中,默认插槽为vm.$slot.default,具名插槽为vm.$slot.xxx,xxx 为插槽名,当组件执行渲染函数时候,遇到slot标签,使用$slot中的内容进行替换,此时可以为插槽传递数据,若存在数据,则可称该插槽为作用域插槽。
在简单项目中,使用 v-cloak 指令是解决屏幕闪动的好方法。但在大型、工程化的项目中(webpack、vue-router)只有一个空的 div 元素,元素中的内容是通过路由挂载来实现的,这时我们就不需要用到 v-cloak 指令了。
Vue.set 响应式新增与修改数据
可以设置对象或数组的值,通过key或数组索引,可以触发视图更新
Vue.delete:删除对象或数组中元素,通过key或数组索引,可以触发视图更新
push() 向数组的末尾添加一个或多个元素,并返回新的长度。
pop() 删除最后一个元素,把数组长度减 1,并且返回它删除的元素的值。
shift() 把数组的第一个元素从其中删除,并返回第一个元素的值。
unshift() 向数组的开头添加一个或更多元素,并返回新的长度。
splice() 向/从数组中添加/删除项目,然后返回被删除的项目。 该方法会改变原始数组。
sort() 对数组的元素进行排序。
reverse() 颠倒数组中元素的顺序。
filter()、concat()、 slice() 这些方法不会改变被操作的数组,返回一个新的数组;
双向绑定更新
vue2 的双向数据绑定是利⽤ES5 的⼀个 API ,Object.defineProperty()对数据进⾏劫持 结合 发布订阅模式的⽅式来实现的。
vue3 中使⽤了 ES6 的 ProxyAPI 对数据代理,通过 reactive() 函数给每⼀个对象都包⼀层 Proxy,通过 Proxy 监听属性的变化,从⽽ 实现对数据的监控。
这⾥是相⽐于vue2版本,使⽤proxy的优势如下
1.defineProperty只能监听某个属性,不能对全对象监听 可以省去for in、闭包等内容来提升效率(直接绑定整个对象即可)
2.可以监听数组,不⽤再去单独的对数组做特异性操作,通过Proxy可以直接拦截所有对象类型数据的操作,完美⽀持对数组的监听。
获取props
vue2在script代码块可以直接获取props,vue3通过setup指令传递
API不同
Vue2使⽤的是选项类型API(Options API),Vue3使⽤的是合成型API(Composition API)
建立数据data
vue2是把数据放入data中,vue3就需要使用一个新的setup()方法,此方法在组件初始化构造得时候触发。
生命周期不同
vue2 -------- vue3
beforeCreate -> setup() 开始创建组件之前,创建的是data和method
created -> setup()
beforeMount -> onBeforeMount 组件挂载到节点上之前执行的函数。
mounted -> onMounted 组件挂载完成后执行的函数
beforeUpdate -> onBeforeUpdate 组件更新之前执行的函数。
updated -> onUpdated 组件更新完成之后执行的函数。
beforeDestroy -> onBeforeUnmount 组件挂载到节点上之前执行的函数。
destroyed -> onUnmounted 组件卸载之前执行的函数。dszhuoyi
activated -> onActivated 组件卸载完成后执行的函数
deactivated -> onDeactivated
关于v-if和v-for的优先级:
vue2 在一个元素上同时使用 v-if 和 v-for v-for会优先执行
vue3 v-if 总会优先于 v-for生效
vue2和vue3的diff算法
vue2
vue2 diff算法就是进行虚拟节点对比,并返回一个patch对象,用来存储两个节点 不同的地方,最后用patch记录的消息去局部更新Dom。
vue2 diff算法会比较每一个vnode,而对于一些不参与更新的元素,进行比较是有 点消耗性能的。
vue3
vue3 diff算法在初始化的时候会给每个虚拟节点添加一个patchFlags,patchFlags 就是优化的标识。
只会比较patchFlags发生变化的vnode,进行更新视图,对于没有变化的元素做静 态标记,在渲染的时候直接复用。
Vue3.0在性能方面比Vue2.x快了1.2~2倍。
重写虚拟DOM的实现
运行时编译
静态提升与事件侦听器缓存
SSR 速度提高
Vue3.x采用TypeScript重写,开发者使用Vue3.x时可以充分体验TS给编码带来的便利。
Composition API:vue2中,我们一般会采用mixin来复用逻辑代码,用倒是挺好用的,不过也存在一些问题:例如代码来源不清晰、方法属性等冲突。基于此在vue3中引入了Composition API(组合API),使用纯函数分隔复用代码。和React中的hooks的概念很相似
Vue3 中的 ref 和 reactive 是 Vue3 中用于数据管理的两种不同的响应式 API。
ref 用于创建一个包装简单值的响应式引用,例如一个数字、字符串或对象。当 ref 创建一个响应式引用时,它返回一个对象,该对象具有一个 value 属性,该属性指向实际值。当 ref 返回的对象中的 value 属性更改时,组件将自动重新渲染。
reactive 用于创建一个响应式对象,该对象可以包含多个属性和嵌套属性。当使用 reactive 创建响应式对象时,返回的对象是一个代理对象,该对象具有与原始对象相同的属性,并且任何对代理对象属性的更改都将触发组件的重新渲染。
综上所述,如果需要对简单值进行响应式处理,则使用 ref,如果需要对对象或嵌套对象进行响应式处理,则使用 reactive。
对于Computed:它支持缓存,只有依赖的数据发生了变化,才会重新计算
不支持异步,当Computed中有异步操作时,无法监听数据的变化
computed的值会默认走缓存,计算属性是基于它们的响应式依赖进行缓存的,也就是基于data声明过,或者父组件传递过来的props中的数据进行计算的。
如果一个属性是由其他属性计算而来的,这个属性依赖其他的属性,一般会使用computed
如果computed属性的属性值是函数,那么默认使用get方法,函数的返回值就是属性的属性值;在computed中,属性有一个get方法和一个set方法,当数据发生变化时,会调用set方法。
对于Watch:它不支持缓存,数据变化时,它就会触发相应的操作
支持异步监听
监听的函数接收两个参数,第一个参数是最新的值,第二个是变化之前的值
当一个属性发生变化时,就需要执行相应的操作监听数据必须是data中声明的或者父组件传递过来的props中的数据,当发生变化时,会触发其他操作,函数
有两个的参数:immediate:组件加载立即触发回调函数 deep:深度监听,发现数据内部的变化,在复杂数据类型中使用,例如数组中的对象发生变化。需要注意的是,deep无法监听到数组和对象内部的变化。
当想要执行异步或者昂贵的操作以响应不断的变化时,就需要使用watch。
$route 是“路由信息对象”,包括 path,params,hash,query,fullPath,matched,name 等路由信息参数
$router 是“路由实例”想要导航到不同URL 对象包括了路由的跳转方法,钩子函数等。
v-model实现双向绑定的语法糖,常用于表单与组件之间的数据双向绑定.
V-model的原理:
v-bind绑定一个value属性
v-on指令给当前元素绑定input事件
可看出v-model绑定在表单上时,v-model其实就是v-bind绑定value和v-on监听input事件的结合体
组件上的双向绑定(原理)
v-model绑定在组件上的时候做了以下步骤
在父组件内给子组件标签添加 v-model ,其实就是给子组件绑定了 value 属性
子组件内使用 prop 创建 创建 value 属性可以拿到父组件传递下来的值,名字必须是 value。
子组件内部更改 value 的时候,必须通过 $emit 派发一个 input 事件,并携最新的值
v-model 会自动监听 input 事件,把接收到的最新的值同步赋值到 v-model 绑定的变量上
可以一个元素绑定多个事件的两种写法,一个事件绑定多个函数的两种写法,修饰符的使用。
在method方法里面分别写两个事件;
根据过滤器的名称,过滤器是用来过滤数据的,在Vue中使用filters来过滤数据,filters不会修改数据,而是过滤数据,改变用户看到的输出(计算属性 computed ,方法 methods 都是通过修改数据来处理数据格式的输出显示)。
使用场景:需要格式化数据的情况,比如需要处理时间、价格等数据格式的输出 / 显示。比如后端返回一个 年月日的日期字符串,前端需要展示为 多少天前 的数据格式,此时就可以用fliters过滤器来处理数据。
过滤器是一个函数,它会把表达式中的值始终当作函数的第一个参数。过滤器用在插值表达式 {{ }} 和 v-bind 表达式 中,然后放在操作符“ | ”后面进行指示。
添加Bus.$off来关闭
beforeDestroy () {
bus.$off('get', this.myhandle)
}
如果想要用bus 来进行页面组件之间的数据传递,需要注意亮点,组件$emit事件应在beforeDestory生命周期内。其次,组件B内的$on记得要销毁。
vuex 是 Vue 配套的 公共数据管理工具,它可以把一些共享的数据,保存到 vuex 中,方便整个程序中的任何组件直接获取或修改我们的公共数据。
有五种,分别是 State、 Getter、Mutation 、Action、 Module
vuex 是 Vue 配套的 公共数据管理工具,它可以把一些共享的数据,保存到 vuex 中,方便整个程序中的任何组件直接获取或修改我们的公共数据。
有五种,分别是 State、 Getter、Mutation 、Action、 Module
state:用来存放多个组件会用到的公共属性
mutations:改变state的规范途径,并且只能同步操作,可以在vue-devtools 追踪到修改记录
getters:作用和computed相似,对state里面的多个属性计算时使用
actions:一些对state的异步操作可以放在actions中,并通过在action提交到mutaions进行状态的修改
modules:当store对象过于庞大时,可以根据具体的业务需求分为多个module
Vue的生命周期就是vue实例从创建到销毁的全过程,也就是new Vue() 开始就是vue生命周期的开始。Vue 实例有⼀个完整的⽣命周期,也就是从开始创建、初始化数据、编译模版、挂载Dom -> 渲染、更新 -> 渲染、卸载 等⼀系列过程,称这是Vue的⽣命周期。
有八个阶段创建前/后,载入前/后,更新前/后,销毁前/后
创建前/后: 在beforeCreate阶段,vue实例的挂载元素el和数据对象data都为undefined,还未初始化。在created阶段,vue实例的数据对象data有了,el还没有
载入前/后:在beforeMount阶段,vue实例的$el和data都初始化了,但还是挂载之前为虚拟的dom节点,data.message还未替换。在mounted阶段,vue实例挂载完成,data.message成功渲染。
更新前/后:当data变化时,会触发beforeUpdate和updated方法
销毁前/后:在执行destroy方法后,对data的改变不会再触发周期函数,说明此时vue实例已经解除了事件监听以及和dom的绑定,但是dom结构依然存在
轻量级框架:只关注视图层,是一个构建数据的视图集合,大小只有几十 kb ;
简单易学:国人开发,中文文档,不存在语言障碍 ,易于理解和学习;
双向数据绑定:保留了 angular 的特点,在数据操作方面更为简单;
组件化:保留了 react 的优点,实现了 html 的封装和重用,在构建单页面应用方面有着独特的优势;
视图,数据,结构分离:使数据的更改更为简单,不需要进行逻辑代码的修改,只需要操作数据就能完成相关操作;
虚拟DOM:dom 操作是非常耗费性能的,不再使用原生的 dom 操作节点,极大解放 dom 操作,但具体操作的还是 dom 不过是换了另一种方式;
运行速度更快:相比较于 react 而言,同样是操作虚拟 dom,就性能而言, vue 存在很大的优势
单页面(Sing Page Application——SPA):顾名思义,只有一个页面。一般是一个主页和多个路由页面组成。
优点:
公共资源不重新加载,局部加载,服务器压力小
切换速度快,用户体验好
前后端分离
缺点:
不利于SEO(可以优化:比如路由懒加载等)
初次加载时耗时多
开发难度较大(相对多页面)
多页面(Multi Page Application——MPA):有多个HTML页面,跳转的时候是从一个html页面跳到另一个页面。
优点:
利于SEO。
更容易扩展。
更易数据分析。
缺点:
开发成本高。
服务器压力大。
用户体验相对较差。
params传参(显示参数)
在url中会显示出传参的值,刷新页面不会失去拿到的参数,使用该方式传值的时候,需要子路由提前配置好参数
params传参(不显示参数)
在url中不会显示出传参的值,但刷新页面会失去拿到的参数,使用该方式 传值 的时候,需要子路由提前配置好name参数
query 传参
query 传过去的参数会拼接在地址栏中(?name=xx),刷新页面数据不会丢失,使用path和name都可以
VUE几种路由跳转几种方式的区别
this.$router.push:跳转到指定url路径,并想history栈中添加一个记录,点击后退会返回到上一个页面
this.$router.replace:跳转到指定url路径,但是history栈中不会有记录,点击返回会跳转到上上个页面 (就是直接替换了当前页面)
this.$router.go(n):向前或者向后跳转n个页面,n可为正整数或负整数
用webpack打包后访问index.html出现资源加载404问题,解决:开发环境的static文件夹是基于根目录的,所以直接用‘/’ 。
vue中,假如,你引入某个样式,然后这个样式里面有引用到图片,如果你的文件中没有这个图片,这时候,即使你没有引用这个图片对应的类名,但是只要你有引入这个css文件,他找不到相应路径图片也会报错!!!
用for循环出来的列表,在设置列表中的元素的动态属性时,需要加bind属性“:”,不然动态属性设置不出来
在vue中的html中的img中的src不可以直接设置为变量,在data里面直接引路径,只能通过import的形式引入,值得注意的是,引用这个方式的时候src是变量需要加“:”,不然会报错!!!!!
在中使用v-for="(item ,index) in list"进行循环时,需要注意加::key=“index”,不然会出现警告!
父组件ajax异步更新数据,子组件props获取不到
应用场景
当父组件 axjos 获取数据,子组件使用 props 接收数据时,执行 mounted 的时候 axjos 还没有返回数据,而且 mounted 只执行一次,这时 props 中接收的数据为空
解决方案:在对应组件中判断数据的长度
封装组件需要注意三点:1. props参数2. slot定制插槽3. event自定义事件
首先,使用Vue.extend()创建一个组件
然后,使用Vue.component()方法注册组件
接着,如果子组件需要数据,可以在props中接受定义
最后,子组件修改好数据之后,想把数据传递给父组件,可以使用emit()方法
父子组件间的数据传递
父组件通过 prop 将数据传递给子组件
子组件通过 emit 事件将子组件数据传递给父组件
子组件不能直接修改 prop 中传给父组件的值
如果请求来的数据是不是要被其他组件公用,仅仅在请求的组件内使用,就不需要放入vuex 的state里。
如果被其他地方复用,这个很大几率上是需要的,如果需要,请将请求放入action里,方便复用,并包装成promise返回,在调用处用async await处理返回的数据。如果不要复用这个请求,那么直接写在vue文件里很方便。
actions类似于mutations,不同在于:Action提交的是mutation,而不是直接变更状态;
Action可以包含任意异步操作,Action函数接受一个与store实例具有相同方法和属性的 context对象,因此你可以调用context.commit提交一个mutation,或者通过context.state 和context.getters来获取state和getters。
Action 通过store.dispatch方法触发:store.dispatch('increment')
原因:因为 store 里的数据是保存在运行内存中的,当页面刷新时,页面会重新加载vue实例,store里面的数据就会被重新赋值初始化。
localStorage 或者就是sessionStorage
下载持久化存储插件。比如使用:vuex-along 的实质也是将 vuex 中的数据存放到 localStorage 或者 sessionStroage 中,只不过这个存取过程组件会帮我们完成,我们只需要用vuex的读取数据方式操作就可以了
vuex的辅助函数有4个
mapState 函数返回的是一个对象。通常,我们需要使用一个工具函数将多个对象合并为一个,以使我们可以将最终对象传给 computed 属性。
mapGetters 辅助函数仅仅是将 store 中的 getter 映射到局部计算属性,因此你可以这样来使用他
mapMutations 辅助函数将组件中的 methods 映射为 store.commit,其原理就是将this.montify 映射为this.$store.commit(‘montify’)
mapActions在组件中使用 this.$store.dispatch('prodect') 分发 action,或者使用 mapActions 辅助函数将组件的 methods 映射为 store.dispatch 调用
Vue插槽是Vue中常见的一种组件间的相互通信方式,作用是让父组件可以向子组件指定位置插入html结构,适用于父组件===>子组件,在要接收数据的组件页面通过
默认插槽是插槽最基本的方式:
首先在父组件App.Vue中引入子组件,并在引入的子组件标签内插入需要的html元素,在子组件中把需要用插槽的地方用
具名插槽就是有名字的插槽。
使用:首先在要插入html的部分需要用一个标签包裹住各个部分其次,当给标签绑定slot=“name” 属性时,需要在子组件中对应每个 给出一个
作用域插槽
数据在组件的自身,但根据数据生成的结构需要组件的使用者来决定,也就是说,作用域插槽的不同之处就在于,数据不在父组件身上,而是在子组件身上,且组件的结构和内容由父组件决定。作用域组件限定了组件内结构和数据的展示范围,以便在开发中我们可以根据一个组件而不断变换其中的内容和结构。
Vue3中无法使用this.$refs的方式获取ref的DOM实例
Vue3提供了getCurrentInstance函数,此函数能返回当前组件的实例对象,也就是当前vue这个实例对象。
通过打印getCurrentInstance获取的对象就可以看见此对象包含页面中的refs。
vue2常用生命周期:
创建前:beforeCreate() 只有一些实例本身的事件和生命周期函数
创建后:Created() 是最早使用data和methods中数据的钩子函数
挂载前:beforeMount() 指令已经解析完毕,内存中已经生成dom树
挂载后:Mounted() dom渲染完毕页面和内存的数据已经同步
更新前:beforeUptate() 当data的数据发生改变会执行这个钩子,内存中的数据是新的,页面是旧的
更新后:Updated() 内存和页面都是新的
销毁前:beforeDestroy() 即将销毁data和methods中的数据此时还是可以使用的,可以做一些释放内存的操作
销毁后:Destroyed() 已经销毁完毕
vue3生命周期做出了一些改动
前面的是vue2的后面是vue3
beforeCreate -> setup() 开始创建组件之前,创建的是data和method
created -> setup()
beforeMount -> onBeforeMount 组件挂载到节点上之前执行的函数。
mounted -> onMounted 组件挂载完成后执行的函数
beforeUpdate -> onBeforeUpdate 组件更新之前执行的函数。
updated -> onUpdated 组件更新完成之后执行的函数。
beforeDestroy -> onBeforeUnmount 组件挂载到节点上之前执行的函数。
diff算法 当data发生改变 会根据新的数据生成一个新的虚拟dom ,新的虚拟dom和旧的虚拟dom进行对比,这个对比的过程就是diff算法。
Vue2 是全量 Diff(当数据发生变化,它就会新生成一个DOM树,并和之前的DOM树进行比较,找到不同的节点然后更新。);Vue3 是静态标记 + 非全量 Diff(Vue 3在创建虚拟DOM树的时候,会根据DOM中的内容会不会发生变化,添加一个静态标记。之后在与上次虚拟节点进行对比的时候,就只会对比这些带有静态标记的节点。)
使用最长递增子序列优化对比流程,可以最大程度的减少 DOM 的移动,达到最少的 DOM 操作
scoped 属性是 style 标签上的一个特殊属性(布尔值)。表示当前style 里的样式只属于当前模块。(作用域、私有化的思想)保证css的作用域不会变成全局 而被其它模块的css污染。
在vue中引入了scoped这个概念,scoped的设计思想就是让当前组件的样式不会修改到其它地方的样式,使用了data-v-hash的方式来使css有了它对应模块的标识,这样写css的时候不需要加太多额外的选择器,方便很多。
首先在main.js里写一个我们要定义的全局变量
app.config.globalProperties.$key = "内容";// 定义全局变量
现在在页面里需要使用这个变量,只需要从vue中引入getCurrentInstance即可
import {getCurrentInstance} from 'vue';
setup(){
const { proxy } = getCurrentInstance();
console.log(proxy.$key);
}
vue2的响应式原理使用的是对象代理去实现的,对象代理中有一个get和set方法,当我们访问对象的时候就会触发get方法,当我们对对象中的值进行修改时会触发set方法。但是当我们给对象添加一个新的属性时对象代理是检测不到的,所以就会出现直接给对象添加属性响应式不生效的问题。
所以在vue中可以使用this.$set(对象名,‘属性名’,属性值)的方法去给对象添加属性,或者使用Vue.set(对象名,‘属性名’,属性值)的方法进行添加,添加之后的属性就带有响应式了
Vue.js 是采用数据劫持结合发布者-订阅者模式的方式,通过Object.defineProperty()来劫持各个属性的setter,getter,在数据变动时发布消息给订阅者,触发相应的监听回调。主要分为以下几个步骤:
需要observe的数据对象进行递归遍历,包括子属性对象的属性,都加上setter和getter这样的话,给这个对象的某个值赋值,就会触发setter,那么就能监听到了数据变化
compile解析模板指令,将模板中的变量替换成数据,然后初始化渲染页面视图,并将每个指令对应的节点绑定更新函数,添加监听数据的订阅者,一旦数据有变动,收到通知,更新视图
Watcher订阅者是Observer和Compile之间通信的桥梁,主要做的事情是: ①在自身实例化时往属性订阅器(dep)里面添加自己 ②自身必须有一个update()方法 ③待属性变动dep.notice()通知时,能调用自身的update()方法,并触发Compile中绑定的回调,则功成身退。
MVVM作为数据绑定的入口,整合Observer、Compile和Watcher三者,通过Observer来监听自己的model数据变化,通过Compile来解析编译模板指令,最终利用Watcher搭起Observer和Compile之间的通信桥梁,达到数据变化 -> 视图更新;视图交互变化(input) -> 数据model变更的双向绑定效果。
Vue 2和Vue 3在设计上有一些重大区别,因此它们的语法和用法也有很大的不同。主要的区别有以下几点:
1.模板编译方式:Vue 2使用基于字符串的模板编译,而Vue 3则采用了基于函数的模板编译方式。
2.响应式系统:Vue 3中通过Proxy实现了更加高效的响应式系统,与Vue 2中的Object.defineProperty有很大不同。
3.组件注册方式:Vue 3中使用了新的API来注册组件,如`createApp`和`defineComponent`,而Vue 2中则是通过`Vue.component`等全局API来注册组件。
由于这些重大区别,Vue 2和Vue 3的语法和用法也有很大的不同。例如,在Vue 3中,使用v-bind指令绑定属性时需要加上冒号(:),而在Vue 2中则不需要。同时,Vue 3中的生命周期钩子函数也发生了变化。如果混用Vue 2和Vue 3的语法,会导致代码无法正常工作或者出现意外的错误,因此不建议混用两个版本的语法。
Props方式是Vue中最常见的一种父传子的一种方式,我们将数据以及对数据的操作定义在父组件,子组件仅做列表的一个渲染,子组件只需要对父组件传递的值进行渲染即可
emit方式也是Vue中最常见的组件通信方式,该方式用于子传父,在子组件中点击【添加】按钮后,emit一个自定义事件,并将添加的值作为参数传递。在父组件中只需要监听子组件自定义的事件,然后执行对应的添加操作
provide和inject是Vue中提供的一对API,该API可以实现父组件向子组件传递数据,无论层级有多深,都可以通过这对API实现。
Vuex 和 Pinia 是 Vue 3 中的状态管理工具,使用这两个工具可以轻松实现组件通信。
Refs有时候想访问 r e f s 绑 定 的 组 件 的 属 性 或 者 方 法 , 我 们 会 使 用 refs绑定的组件的属性或者方法,我们会使用 refs绑定的组件的属性或者方法,我们会使用refs。但是Vue3不同于Vue2,在 Vue3的setup中我们是无法访问到this的,所以我们需要借助一个方法,那就是getCurrentInstance,该方法返回了当前的实例对象。