文章目录
- 1.简述MVVM
- 2.Vue底层实现原理/Vue响应式原理?(全文背诵)
- 3.谈谈对vue生命周期的理解?
- 4.computed与watch
- 5.组件中的data为什么是一个函数?
- 6.为什么v-for和v-if不建议用在一起
- 7.React/Vue 项目中 key 的作用
- 8.vue组件的通信方式
- 9.nextTick的实现
- 10.Vue 中指令有哪些
- 11.对 vue 中 keep-alive 的理解
- 12.Vue 数据绑定的几种方式
- 13.Vue 的路由钩子函数/路由守卫有哪些
- 14. 请简述插槽
- 15.Vue 中如何进行动态路由设置?有哪些方式?怎么获取传递过来的数据?
- 16.Route 与 router 区别
- 17. Vue 单页面的优缺点
- 18.vue 跨域的解决方式
- vue的七大属性
- 19. 谈谈你对Vuex的理解?(硬背)
- 20.vuex 的优势
- 21.Vue3.0 是如何变得更快的?(底层,源码)
- 22.谈谈你对组件的看法
- 23.(组件的)状态(state)和属性(props)之间有何不同?
- State 与 props 区别
- 24.ref和$el的区别?
1.简述MVVM
什么是MVVM?
视图模型双向绑定,是Model-View-ViewModel的缩写,也就是把MVC中的Controller演变成ViewModel。Model层代表数据模型,View代表UI组件,ViewModel是View和Model层的桥梁,数据会绑定到viewModel层并自动将数据渲染到页面中,视图变化的时候会通知viewModel层更新数据。以前是操作DOM结构更新视图,现在是数据驱动视图。
MVVM的优点:
- 低耦合。视图(View)可以独立于Model变化和修改,一个Model可以绑定到不同的View上,当View变化的时候Model可以不变化,当Model变化的时候View也可以不变;
- 可重用性。你可以把一些视图逻辑放在一个Model里面,让很多View重用这段视图逻辑。
- 独立开发。开发人员可以专注于业务逻辑和数据的开发(ViewModel),设计人员可以专注于页面设计。
- 可测试。
Mvvm 与 mvc 的区别
MVC是包括view视图层、controller控制层、model数据层。各部分之间的通信都是单向的。
View 传送指令到 ControllerController 完成业务逻辑后,要求 Model 改变状态Model 将新的数据发送到 View,用户得到反馈。
MVC模型侧重于模型的不变性,因此在MVC模型中,模型不依赖于视图,但视图依赖于模型。不仅如此,由于某些业务逻辑是在View中实现的,因此很难更改View,至少那些业务逻辑无法重用。
2.Vue底层实现原理/Vue响应式原理?(全文背诵)
vue.js是采用数据劫持结合发布者-订阅者模式的方式,通过Object.defineProperty()
来劫持各个属性的setter
和getter
,在数据变动时发布消息给订阅者,触发相应的监听回调。
Vue是一个典型的MVVM框架,模型(Model)只是普通的javascript对象,修改它则试图(View)会自动更新。这种设计让状态管理变得非常简单而直观
数据劫持:defineProperty或者proxy’,给data里的数据添加get、set才能及时获取数据改变
Observer(数据监听器) :
Observer的核心是通过Object.defineProprtty()
来监听数据的变动,这个函数内部可以定义setter和getter,每当数据发生变化,就会触发setter。这时候Observer就要通知订阅者,订阅者就是Watcher
Watcher(订阅者) :
Watcher订阅者作为Observer和Compile之间通信的桥梁,主要做的事情是:
- 在自身实例化时往属性订阅器(dep)里面添加自己
- 自身必须有一个update()方法
- 待属性变动
dep.notice()
通知时,能调用自身的update()方法,并触发Compile中绑定的回调
Compile(指令解析器) :
Compile主要做的事情是解析模板指令,将模板中变量替换成数据,然后初始化渲染页面视图,并将每个指令对应的节点绑定更新函数,添加鉴定数据的订阅者,一旦数据有变动,收到通知,更新试图
响应式原理
- 首先通过监听器observer对data数据的所有属性进行遍历以及劫持监听,通过
object.defineProperty
的set方法可以监听数据的改变,通过get方法获取数据的对应的值; - 接着通过发布者(dep)订阅者(watcher)模式,将每个属性的get方法调用者添加进对应的dep数组里,当相应属性发生改动时,在set方法里通过调用dep通知所有
watcher
调用updata方法进行页面数据更新; - 此外还有个解析器Compile对页面指令进行解析,将相关指令初始化成一个watcher,并替换模板数据和绑定相应的函数,以上就是响应式原理。
首先我们需要通过Object.defineProperty()方法把数据(data)设置为getter和setter的访问形式,这样我们就可以在数据被修改时在setter方法设置监视修改页面信息,也就是说每当数据被修改,就会触发对应的set方法,然后我们可以在set方法中去调用操作dom的方法。
此外,如果页面有input用v-model绑定数据,我们需要在这种绑定了data的input元素上添加监听,添加input事件监听,每当input事件被触发时,就修改对应的data。
3.谈谈对vue生命周期的理解?
每个Vue实例在创建时都会经过一系列的初始化过程,vue的生命周期钩子,就是说在达到某一阶段或条件时去触发的函数,目的就是为了完成一些动作或者事件
- create阶段:vue实例被创建
beforeCreate: 创建前,此时data和methods中的数据都还没有初始化
created: 创建完毕,data中有值,未挂载 - mount阶段: vue实例被挂载到真实DOM节点
beforeMount:可以发起服务端请求,去数据
mounted: 此时可以操作DOM - update阶段:当vue实例里面的data数据变化时,触发组件的重新渲染
beforeUpdate :更新前
updated:更新后 - destroy阶段:vue实例被销毁
beforeDestroy:实例被销毁前,此时可以手动销毁一些方法
destroyed:销毁后
组件生命周期(父子)
生命周期(父子组件)
父组件beforeCreate --> 父组件created --> 父组件beforeMount -->
子组件beforeCreate–> 子组件created --> 子组件beforeMount -->
子组件 mounted --> 父组件mounted -->父组件beforeUpdate -->
子组件beforeDestroy–> 子组件destroyed --> 父组件updated
加载渲染过程
父beforeCreate->父created->父beforeMount->子beforeCreate->子created->子beforeMount->子mounted->父mounted
挂载阶段
父created->子created->子mounted->父mounted
父组件更新阶段
父beforeUpdate->父updated
子组件更新阶段
父beforeUpdate->子beforeUpdate->子updated->父updated
销毁阶段
父beforeDestroy->子beforeDestroy->子destroyed->父destroyed
4.computed与watch
计算属性computed :
- 支持缓存,只有依赖数据发生改变,才会重新进行计算,计算属性可用于快速计算视图(View)中显示的属性。这些计算将被缓存,并且只在需要时更新。
- 不支持异步,当computed内有异步操作时无效,无法监听数据的变化。
- computed属性值会默认走缓存,计算属性是基于它们的响应式依赖进行缓存的,也就是基于data中声明过或者父组件传递的props中的数据通过计算得到的值。
- 如果一个属性是由其他属性计算而来的,这个属性依赖其他属性,是一个多对一或者一对一,一般用computed
- 如果computed属性属性值是函数,那么默认会走get方法;函数的返回值就是属性的属性值;在computed中的,属性都有一个get和一个set方法,当数据变化时,调用set方法。
- computed 是基于响应性依赖来进行缓存的。只有在响应式依赖发生改变时它们才会重新求值, 也就是说, 当msg属性值没有发生改变时,多次访问 reversedMsg 计算属性会立即返回之前缓存的计算结果,而不会再次执行computed中的函数。但是methods方法中是每次调用, 都会执行函数的, methods它不是响应式的。
侦听属性watch:
1.watch它是一个对data的数据监听回调, 当依赖的data的数据变化时, 会执行回调。Vue实列将会在实例化时调用$watch()
, 他会遍历watch对象的每一个属性。
2.watch里面有一个属性为deep,含义是:是否深度监听某个对象的值, 该值默认为false。watch支持异步;
3.监听的函数接收两个参数,第一个参数是最新的值;第二个参数是输入之前的值;
4.当一个属性发生变化时,需要执行对应的操作;一对多;
5.监听数据必须是data中声明过或者父组件传递过来的props中的数据,当数据变化时,触发其他操作,函数有两个参数,
immediate
:组件加载立即触发回调函数执行,
deep
: 深度监听,为了发现对象内部值的变化,复杂类型的数据时使用,例如数组中的对象内容的改变,注意监听数组的变动不需要这么做。注意:deep无法监听到数组的变动和对象的新增,参考vue数组变异,只有以响应式的方式触发才会被监听到。
使用场景
-
computed:当一个属性受多个属性影响的时候使用,例:购物车商品结算功能
watch:当一条数据影响多条数据的时候使用,例:搜索数据 -
computed适用于一些重复使用数据或复杂及费时的运算。我们可以把它放入computed中进行计算, 然后会在computed中缓存起来, 下次就可以直接获取了。
-
watch的使用场景是:当在data中的某个数据发生变化时, 我们需要做一些操作, 或者当需要在数据变化时执行异步或开销较大的操作时. 我们就可以使用watch来进行监听。watch普通监听和深度监听不支持缓存,数据变,直接会触发相应的操作;
5.组件中的data为什么是一个函数?
- 一个组件被复用多次的话,也就会创建多个实例。本质上,这些实例用的都是同一个构造函数
- 如果data是对象的话,在多次使用该组件时,改变其中一个组件的值会影响全部该组件的值。
- 组件每复用一次,data数据就应该被复制一次,之后,当某一处复用的地方组件内data数据被改变时,其他复用地方组件的data数据不受影响。而如果是通过函数的形式返回出一个对象的话,在每次使用该组件时返回出的对象的地址指向都是不一样的,这样就能让各个组件的数据独立。
所以为了保证组件不同的实例之间data不冲突,data必须是一个函数。
6.为什么v-for和v-if不建议用在一起
- 当 v-for 和 v-if 处于同一个节点时,v-for 的优先级比 v-if 更高,这意味着 v-if 将分别重复运行于每个 v-for 循环中。如果要遍历的数组很大,而真正要展示的数据很少时,这将造成很大的性能浪费(Vue2.x)
- 这种场景建议使用 computed,先对数据进行过滤
注意:3.x 版本中 v-if 总是优先于 v-for 生效。由于语法上存在歧义,建议避免在同一元素上同时使用两者。比起在模板层面管理相关逻辑,更好的办法是通过创建计算属性筛选出列表,并以此创建可见元素。
7.React/Vue 项目中 key 的作用
简单地说:key是虚拟DOM对象的标识,在更新显示时key起着重要的作用。
详细的说:当状态中的数据发生改变时,react/vue会根据“新数据”生成“新的虚拟DOM”,
随后react/vue进行“新虚拟DOM”与“旧虚拟DOM”的diff比较,比较规则如下:
-
旧虚拟DOM中找到了与新虚拟DOM相同的key:
(1)若虚拟DOM中内容没变,直接使用之前真实的DOM。
(2)若虚拟DOM中内容变了,则生成新的真实DOM,随后替换掉页面中之前真实DOM。
-
旧虚拟DOM中未找到与新虚拟DOM相同的key:
根据数据创建新的真实DOM,随后渲染到页面
-
而如果没有key,那么就会采用遍历查找的方式去找到对应的旧节点。
- key的作用是为了在diff算法执行时更快的找到对应的节点,提高diff速度,更高效的更新虚拟DOM;
- 为了在数据变化时强制更新组件,以避免“就地复用”带来的副作用。
当 Vue.js 用 v-for 更新已渲染过的元素列表时,它默认用“就地复用”策略。如果数据项的顺序被改变,Vue 将不会移动 DOM 元素来匹配数据项的顺序,而是简单复用此处每个元素,并且确保它在特定索引下显示已被渲染过的每个元素。重复的key会造成渲染错误。
diff算法
可以看作是一种对比算法,对比的对象是新旧虚拟Dom。顾名思义,diff算法可以找到新旧虚拟Dom之间的差异,但diff算法中其实并不是只有对比虚拟Dom,还有根据对比后的结果更新真实Dom。
就地复用
当 Vue 正在更新使用 v-for 渲染的元素列表时,它默认使用“就地更新”的策略。如果数据项的顺序被改变,Vue 将不会移动 DOM 元素来匹配数据项的顺序,而是就地更新每个元素,并且确保它们在每个索引位置正确渲染。
虚拟dom
虚拟DOM也就是常说的虚拟节点,它是通过js的object对象模拟DOM 中的节点,然后再通过特定的渲染方法将其渲染成真实的DOM节点。 频繁的操作 DOM,或大量造成页面的重绘和回流。
8.vue组件的通信方式
-
props/$emit 父子组件通信
父组件A通过props的方式向子组件B传递,B to A 通过在 B 组件中 $emit, A 组件中 v-on 的方式实现。
子组件向父组件传值(通过事件形式) -
$emit/$on
自定义事件 兄弟组件通信
Event Bus 实现跨组件通信 Vue.prototype.$bus = new Vue() 自定义事件 -
vuex 跨级组件通信
Vuex、 a t t r s 、 attrs、 attrs、listeners Provide、inject
9.nextTick的实现
为什么会有nextTick这个东西的存在?
因为 vue 采用的异步更新策略,当监听到数据发生变化的时候不会立即去更新DOM,
而是开启一个任务队列,并缓存在同一事件循环中发生的所有数据变更;
这种做法带来的好处就是可以将多次数据更新合并成一次,减少操作DOM的次数,
如果不采用这种方法,假设数据改变100次就要去更新100次DOM,而频繁的DOM更新是很耗性能的;
nexTick 的作用?
nextTick 接收一个回调函数作为参数,并将这个回调函数延迟到DOM更新后才执行;
使用场景:想要操作基于最新数据的生成DOM 时,就将这个操作放在 nextTick 的回调中;
nextTick的实现原理是什么?
在下次 DOM 更新循环结束之后执行延迟回调,在修改数据之后立即使用 nextTick
来获取更新后的 DOM。
将传入的回调函数包装成异步任务,异步任务又分微任务和宏任务,为了尽快执行所以优先选择微任务;
根据执行环境分别尝试采用Promise、MutationObserver、setImmediate,
如果以上都不行则采用setTimeout
定义了一个异步方法,多次调用nextTick会将方法存入队列中,通过这个异步方法清空当前队列。
10.Vue 中指令有哪些
v-for
:循环数组,对象,字符串,数字
v-on
:绑定事件监听
v-bind
:动态绑定一个或者多个属性
v-model
:表单控件或者组件上创建双向绑定
v-if v-else v-else-if
条件渲染
v-show
根据表达式真假,切换元素的 display
v-html
更新元素的 innerhtml
v-text
更新元素的 textcontent v-pre 跳过这个元素和子元素的编译过程
v-clock
这个指令保持在元素上知道关联实例结束编译
v-once
只渲染一次
11.对 vue 中 keep-alive 的理解
概念:keep-alive 是 vue 的内置组件,当它动态包裹组件时,会缓存不活动的组件实例,它自身不会渲染成一个 DOM 元素,也不会出现在父组件链中
作用:在组件切换过程中将状态保留在内存中,防止重复渲染 DOM,减少加载时间以及性能消耗,提高用户体验。
生命周期函数:Activated 在 keep-alive 组件激活时调用,deactivated 在 keep-alive 组件停用时调用。
- keep-alive 是vue 中的内置缓存组件 能在组件切换过程中将状态保留在内存中,防止重复渲染DOM
- keep-alive包裹的动态组件会缓存不活动的组件实例
- keep-alive 是一个抽象组件:它自身不会渲染一个 DOM元素,也不会出现在组件的父组件链中。
- keep-alive 先匹配被包含组件的 name 字段,如果 name 不可用,则匹配当前组件 components 配置中的注册名称。
- keep-alive 主要用于保留组件状态或避免重新熏染
- 设置了keep-alive 缓存的组件 会多两个生命周期 ( activated 和 deactivated)
12.Vue 数据绑定的几种方式
1.单向绑定 双大括号 {{}} html 内字符串绑定
2.v-bind 绑定 html 属性绑定 数据只能从data流回页面(单向传递)
3.双向绑定 v-model 数据不仅可以从data流向页面,还可以从页面流向data
4.一次性绑定 v-once 依赖于 v-model
Vue 双向绑定的原理
Vue 双向绑定就是:数据变化更新视图,视图变化更新数据
Vue 数据双向绑定是通过数据劫持和观察者模式来实现的,
- 数据劫持,object.defineproperty 它的目的是:当给属性赋值的时候, 程序可以感知到,就可以控制改变属性值。
- 观察者模式 当属性发生改变的时候,使用该数据的地方也发生改变。
13.Vue 的路由钩子函数/路由守卫有哪些
全局守卫:beforeEach(to,from,next), afterEach(to,from)
全局前置守卫beforeEach(to,from,next)
当一个导航触发时,全局前置守卫(在进入组件之前)按照创建顺序调用。
to:即将要进入的目标路由对象 from:当前导航正要离开的路由 next:下一步执行
全局后置钩子 afterEach(to,from)
当一个导航触发时,全局后置钩子(在进入组件之后)调用。
to:即将要进入的目标路由对象
from:当前导航正要离开的路由
router.afterEach((to,from)=>{
console.log("我是全局后置钩子");
})
路由独享守卫:beforeEnter
与全局前置守卫相比路由独享守卫只是对当前路由进行单一控制参数和全局
前置守卫相同
在路由配置上直接定义 beforeEnter 进行路由独享守卫定义
组件内的守卫(只对当前组件生效)
beforeRouteEnter 在进入组件前调用(不常用)
在组件中使用 beforeRouteEnter(to,from,next){}来进行进入组建前的钩子
beforeRouteLeave 离开路由之前(常用)
在组件中使用 beforeRouteLeave(to,from,next){}来进行离开组件的钩子
14. 请简述插槽
插槽的关键字slot,默认情况下,组件中的模板会覆盖组件中的原始内容(即自定义标签对内部的内容会不显示),解决办法就是使用插槽。
作用:让父组件可以向子组件指定位置插入html结构(任意内容),也是一种组件间通信方式,适用于父组件===>子组件
,可以在父组件中使用 slot-scope
从子组件获取数据
组件的原始内容: 即在vue实例范围之内,因此可以调用实例的data和methods
插槽共分为三种:
匿名插槽:<slot></slot>
具名插槽:<slot name=top></slot>
简写:把参数之前的所有内容(v-slot:) 替换为字符#。例如v-slot:header可以被重写为#header:
作用域插槽:<slot title='标题' :num=count></slot>
插槽和props区别:
slot 与 props 的区别:通过props属性,父组件可以向子组件传递属性、方法,可是父组件不能通过属性传递带标签的内容、甚至是组件,而插槽可以。
15.Vue 中如何进行动态路由设置?有哪些方式?怎么获取传递过来的数据?
动态路由:就是把匹配某种模式下的路由映射到同一个组件中,其实本质就是通过url
进行传参,比如说:有一个商品Goods的组件,我们需要让不同的商品id都映射到这个组件中,都要使用这个组件来渲染,那么我们可以在vue-router的路由路径中使用 “动态路由参数” 来达到这个效果。
- 动态路径参数,使用 “冒号” 开头,一个路径参数,使用冒号标记,当匹配到一个路由时,参数会被设置到
this.$router.params
中,并且可以在每个组件中使用
this.$router.push({
name:"路由地址",
params:{
name:'要发送的数据',
}
});
//读取 路由参数接收
this.name = this.$route.params.name;
query 和 params 之间的区别是什么?
-
query 要用 path 来引入,params 需要用 name 来引入
-
接收参数时,分别是
this.$route.query.name
和this.$route.params.name
(注意:是$route
而不是$router
) -
query 更加类似于我们 ajax 中 get 传参,params 则类似于 post,前者在浏览器的地址中显示,params 不显示
-
params 传值一刷新就没了,query 传值刷新还存在
16.Route 与 router 区别
- router 是 VueRouter 的一个对象,通过
Vue.use(VueRouter)
和VueRouter
构造函数得到一个 router 的实例对象,这个对象中是一个全局的对象,他包含了所有的路由包含了许多关键的对象和属性,例如 history 对象,经常使用的跳转链接就可以用 this.router.push 会往 history 栈中添加一个新的记录,返回上一个 history 也是使用 $router.go 方法。 - route 是一个跳转的路由对象,每一个路由都会有一个 route 对象,是 一个局部的对象,可以获取对应的 name,path,params,query 等
17. Vue 单页面的优缺点
单页面 spa
优点:前后端分离 用户体验好 一个字 快 内容改变不需要重新加载整个页面
缺点:不利于 seo, 初次加载时耗长(浏览器一开始就要加载 html css js ,所有的页面内容都包含在主页面中) ,页面复杂度提高了,导航不 可用
18.vue 跨域的解决方式
1.后台更改 header
2.使用 jq 提供 jsonp
3.用 http-proxy-middleware(配置代理服务器的中间件)
vue的七大属性
1. el属性
获取Vue实例关联的DOM元素;
表明我们要将当前vue组件生成的实例插入到页面的哪个元素中。
2. data属性
可以说将view视图的数据抽象出来存放在data中。
3. template属性
用来设置模板,会替换页面元素,包括占位符。
Vue.component()
组件中会用到,其实很多地方都会用到
4.methods属性
放置页面中的业务逻辑,js方法一般都放置在methods中,用来写方法。
computed和methods是有区别的:computed是在值发生改变的时候才会触发效果,而methods只要刷新执行了就会触发,能用computed的尽量使用
5.render属性
创建真正的虚拟数Virtual Dom
6.computed属性
用来计算根据已经存在的属性计算出新的属性,对于同样的数据,会缓存。当其依赖属性的值发生变化是,这个属性的值会自动更新,与之相关的DOM部份也会同步自动更新。
7.watch侦听属性
watch:function(new,old){}
监听data中数据的变化
两个参数,一个返回新值,一个返回旧值
当你有一些数据需要随着其它数据变动而变动时或者执行异步操作或开销较大操作时,建议使用watch
computed和watch是有区别的:
watch: 监视,能够监听到数据的变化,只要数据变化的时候,都会自定执行对应的方法,其中可以检测的数据来源分为三部分 data , computed , props
computed: 计算属性,存在一个计算缓存的特性,每一次计算之后,只要里面的逻辑不发生变化,每一次重复调用,都会使用上一次执行的结果,能够节省计算的时间
19. 谈谈你对Vuex的理解?(硬背)
- Vuex是一个专门为Vue.js开发的状态管理模式,vuex的应用核心就是store仓库,Store基本上就是个容器,包含着应用中大部分的state状态;
- Vuex的状态存储是响应式的,改变store中的状态的唯一途径就是通过commit mutation,方便跟踪每一个状态的变化;
- Vuex有几个模块
- State:定义了应用状态的数据结构,可以在这里设置默认的初始状态;
- Getter:允许组件从store中获取数据,mapGetters辅助函数仅仅将store中的getter映射到计算属性;
- Mutation:唯一更改store中状态的方法,且必须是同步函数;
- Action:用于提交mutation,而不是直接更改状态,包含异步操作;
- Module:允许将单一的store拆分为多个store且同时保存在单一的状态树。
Vuex 使用流程:
下载 vuex
在 src 下创建 store 以及 index.js
引入 vue 和 vuex, 使用 vuex ,导出实例对象
在 main.js 中引入,在.vue 文件中使用
49.vuex 的 State 特性是? State 就是数据源的存放地 State 里面的数据是响应式的,state 中的数据改变,对应这个数据的组 件也会发生改变 State 通过 mapstate 把全局的 state 和 getters 映射到当前组件的计算 属性中 50.vuex 的 Getter 特性是? Getter 可以对 state 进行计算操作,它就是 store 的计算属性 第 89 页
Getter 可以在多组件之间复用 如果一个状态只在一个组件内使用,可以不用 getters 51.vuex 的 Mutation 特性是? 更改 vuex store 中修改状态的唯一办法就是提交 mutation,可以在回 调函数中修改 store 中的状态 52.vuex 的 actions 特性是? Action 类似于 mutation,不同的是 action 提交的是 mutation,不是 直接变更状态,可以包含任意异步操作
20.vuex 的优势
优点:
- 能够在vuex中,集中管理共享的数据,易于开发和后期维护;
- Vuex 的状态存储是响应式的,当 Vue 组件从 store中读取状态的时候,若 store 中的状态发生变化,能够触发响应式的渲染页面更新(localStorage就不会),那么相应的组件也会相应地得到高效更新。
- js 原生的数据对象写法, 比起 localStorage不需要做转换, 使用方便
- 限定了一种可预测的方式改变数据, 避免大项目中, 数据不小心的污染
缺点:
- 刷新浏览器,vuex 中的 state 会重新变为初始状态,
- 解决办法是 vuex-along,得配合计算属性和 sessionstorage 来实现。
21.Vue3.0 是如何变得更快的?(底层,源码)
1、diff算法
vue2.x中的虚拟dom是全量对比的,而vue3.0增加了静态标记,再与上次虚拟节点对比的时候,只要对比有静态标记的,并且通过标记的信息得知当前节点要对比的具体内容。
2、静态提升
vue2.x 无论元素是否参与更新,每次都会重新创建
vue3.0 对不参与更新的元素,只会被创建一次,之后再每次渲染的时候被不停的复用。
3、事件监听器缓存
事件函数缓存起来复用
22.谈谈你对组件的看法
- 可组合(Composeable):一个组件易于和其它组件一起使用,或者嵌套在另一个组件内部。如果一个组件内部创建了另一个组件,那么说父组件拥有(own)它创建的子组件,通过这个特性,一个复杂的 UI 可以拆分成多个简单的 UI 组件;
- 可重用(Reusable):每个组件都是具有独立功能的,它可以被使用在多个 UI 场景;
- 可维护(Maintainable):每个小的组件仅仅包含自身的逻辑,更容易被理解和维护;
- 可测试(Testable):因为每个组件都是独立的,那么对于各个组件分别测试显然要比对于整个 UI 进行测试容易的多。
23.(组件的)状态(state)和属性(props)之间有何不同?
State 与 props 区别
Props 是一个从外部传进组件的参数,主要作用就是父组件向子组件传递数据,但是 props 对于使用它的组件来说是只读的,一旦赋值不能修改,只能通过外部组件主动传入新的 props 来重新渲染子组件。
State 一个组件的显示形态可以由数据状态和外部参数决定,外部参数是 props,数据状态就是 state,首先,在组件初始化的时候,用 this.state 给组件设定一个初始的 state,在第一次渲染的时候就会用这个数据来渲染组件,state 不同于 props 一点时,state 可以修改,通过 this.setState()
方法来修改 state
24.ref和$el的区别?
简述三者区别:
- ref :是 元素的属性,用于设置在元素上。
如果ref使用在组件上的,则拿到的是该组件的vue实例对象,那就可以直接使用child组件中定义的所有属性和方法。
ref 是访问 VUE 虚拟出来的DOM - $el :是用于获取组件内 DOM(包括子组件,当前.vue组件,以及父组件),就是组件中的根元素。
- $refs :是 ref 的集合,集合里面包含了当前.vue中的所有 ref,用于获取普通元素中的 DOM 以及子组件中方法/参数的。