* Vue2 和 Vue3的区别:
1)双向数据绑定原理的区别
2)根节点的不同
Vue2只能一个根节点
Vue3在组件中可以放置多个根节点
3)Vue3中采用composition API
vue2:采用的选项型API(opsition API)
vue3:采用的组合型API(composition API)
4)建立的数据方式不同
vue2:数据是放置在data属性中
vue3:需要使用setup 方法,该方法在初始化构造的时候触发
注:ref:需要value 访问,内部还是使用的defineProperty set get 方法进行监听(proxy 不支持基本类型的监听)
reactive: 使用的proxy对数据进行的一个代理
5)生命周期函数不同
6)diff算法不同
7)父子传参不同
vue2:父传子,用props,子传父用事件 Emitting Events。在vue2中,会调用this$emit然后传入事件名和对象。
vue3:父传子,用props,子传父用事件 Emitting Events。在vue3中的setup()中的第二个参数content对象中就有emit,那么我们只要在setup()接收第二个参数中使用分解对象法取出emit就可以在setup方法中随意使用了。
1. 什么是MVVM?
M - Model 数据:负责数据管理和业务逻辑。
V - View 视图:负责用户界面的展示和呈现。
VM - ViewModel 视图-数据:它是View和Model的粘合体,负责View和Model的交互和协作
vue 双向数据绑定是通过 数据劫持 结合 发布订阅模式的方式来实现的, 也就是说数据和视图同步,数据发生变化,视图跟着变化,视图变化,数据也随之发生改变;
核心:关于VUE双向数据绑定,其核心是 Object.defineProperty()方法,get set 方法。
在MVVM的框架下视图和模型是不能直接通信的。它们通过ViewModel来通信,ViewModel通常要实现一个observer观察者,当数据发生变化,ViewModel能够监听到数据的这种变化,然后通知到对应的视图做自动更新,而当用户操作视图,ViewModel也能监听到视图的变化,然后通知数据做改动,这实际上就实现了数据的双向绑定。并且MVVM中的View 和 ViewModel可以互相通信。
MVVM 是一种软件架构模式。它是基于 MVC 的一种演变,将视图和数据绑定的方式更加紧密地结合在一起。
2. 什么是MVC?
M - Model 数据:负责数据管理和业务逻辑。模型表示应用程序中的数据结构以及对数据的操作。
V - View 视图:负责用户界面的展示和呈现,通常是用户可以看到和与之交互的部分。
C - Controller 控制器: 负责接收用户的输入并作出响应,它处理用户与模型和视图之间的交互。控制器将用户的操作转发给模型进行处理,并将模型的结果传递给视图进行展示。
MVC 的优势:
能够将应用程序的各个功能模块分离开来,提高代码的可维护性和可扩展性。通过明确定义了各个组件的职责,开发人员可以更好地组织和管理代码,同时也使得代码更容易被复用。
3. MVVM 和 MVC的区别
1、mvvm各部分的通信是双向的,而mvc各部分通信是单向的;
2、mvvm是真正将页面与数据逻辑分离放到js里去实现,而mvc里面未分离。
MVC允许在不改变视图的情况下改变视图对用户输入的响应方式,用户对View的操作交给了Controller处理,在Controller中响应View的事件调用Model的接口对数据进行操作,一旦Model发生变化便通知相关视图进行更新。
4. Vue2响应式原理
对象类型:
使用 Object.defineProperty 遍历对象的每一个属性,把每一个属性变成一个 getter 和 setter 函数,读取属性的时候调用 getter,给属性赋值的时候就会调用 setter,这就是数据劫持。
数组类型:
通过重写更新数组的一系列方法,保留原功能的基础上增加一些数据劫持的代码(也就是将数据变为可监控的)来实现拦截。
7个方法:push、pop、shift、unshift、splice、sort、reverse。
存在问题:
1.新增属性、删除属性, 界面不会更新。
2.直接通过下标修改数组, 界面不会自动更新。
解决方法:
vue2中 $set 可以解决这些问题。
5. Vue3响应式原理
通过(Proxy)代理实现: 拦截对象中任意属性的变化, 包括属性值的读写, 属性的添加, 属性的删除等操作。
通过(Reflect)(反射); 被代理的对象, 属性进行操作。
vue3.0 中不存在vue2.0 中说的这些问题
在一个对象中新增, 删除, 修改属性, 界面不会自动更新。
直接通过下标修改数组, 界面不会自动更新。
6. Proxy 与 Object.defineProperty 优劣对比
1)Proxy的优势如下:
- Proxy可以直接监听对象⽽⾮属性 。
- Proxy可以直接监听数组的变化 。
- Proxy有多达13种拦截⽅法,不限于apply、ownKeys、deleteProperty、has等等是 Object.defineProperty 不具备的 。
- Proxy返回的是⼀个新对象,我们可以只操作新的对象达到⽬的,⽽ Object.defineProperty 只能遍历对象属性直接修改。
- Proxy作为新标准将受到浏览器⼚商重点持续的性能优化,也就是传说中的新标准的性能红利 。
2)Object.defineProperty的优势如下:
- 兼容性好,⽀持IE9。
7. Vue2和Vue3的diff的区别
Vue2:
diff算法就是进行虚拟节点对比,并返回一个patch对象,用来存储两个节点不同的地方,最后用patch记录的消息去局部更新Dom。
diff算法会比较每一个vnode,而对于一些不参与更新的元素,进行比较是有点消耗性能的。Vue3:
diff算法在初始化的时候会给每个虚拟节点添加一个patchFlags,patchFlags就是优化的标识。
只会比较patchFlags发生变化的vnode,进行更新视图,对于没有变化的元素做静态标记,在渲染的时候直接复用。详细内容比较多,但这个是重点部分。请跳转至:
Vue2 和 Vue3 的 Diff 算法的区别-CSDN博客
Vue diff算法_vue2 diff算法和vue3diff算法-CSDN博客
8. 生命周期的理解
Vue 实例有一个完整的生命周期,也就是从开始创建、初始化数据、编译模版、挂载 Dom -> 渲染、更新 -> 渲染、卸载等一系列过程,我们称这是 Vue 的生命周期。
9. Vue2的生命周期
创建阶段:
beforeCreate:在实例初始化之后,数据观测 (data observer) 和 event/watcher 事件配置之前被调用。
created:在实例创建完成后被调用,此阶段完成了数据观测 (data observer)、属性和方法的运算,以及 watch/event 事件的设置。但是此时还没有挂载到 DOM 上。挂载阶段:
beforeMount:在挂载开始之前被调用,相关的 render 函数首次被调用。
mounted:在实例被挂载到 DOM 后调用,此阶段完成了模板编译并且将实例挂载到 DOM 上。
更新阶段:
beforeUpdate:在数据更新之前被调用,发生在虚拟 DOM 重新渲染和打补丁之前。
updated:在数据更新完成后被调用,实例的 DOM 已经更新。
销毁阶段:
beforeDestroy:在实例销毁之前调用,此时实例仍然完全可用。
destroyed:在实例销毁后调用,此阶段完成了实例的事件监听器和子组件的销毁。
两个特殊的生命周期钩子函数:
activated:在使用 keep-alive 组件时,被激活的组件会调用该函数。
deactivated:在使用 keep-alive 组件时,被停用的组件会调用该函数。
10. Vue3的生命周期
1)普通写法: | 2)setup中写生命周期: |
beforeCreate | setup() |
created | setup() |
beforeMount | onBeforeMount |
mounted | onMounted |
beforeUpdate | onBeforeUpdate |
updated | onUpdated |
beforeUnmount | onBeforeUnmount |
unmounted | onUnmounted |
11. Vue2和Vue3生命周期区别
12. 在哪个生命周期内调用异步请求?
可以在钩子函数 created、beforeMount、mounted 中进行调用,因为在这三个钩子函数中,data 已经创建,可以将服务端端返回的数据进行赋值。
但是本人推荐在 created 钩子函数中调用异步请求,因为在 created 钩子函数中调用异步请求有以下优点:
- 能更快获取到服务端数据,减少页面 loading 时间;
- ssr 不支持 beforeMount 、mounted 钩子函数,所以放在 created 中有助于一致性;
13. 父组件可以监听到子组件的生命周期吗?
比如有父组件 Parent 和子组件 Child,如果父组件监听到子组件挂载 mounted 就做一些逻辑处理,可以通过以下写法实现:
// Parent.vue <Child @mounted="doSomething"/> // Child.vue mounted() { this.$emit("mounted"); }
以上需要手动通过 $emit 触发父组件的事件,更简单的方式可以在父组件引用子组件时通过 @hook 来监听即可,如下所示
// Parent.vue <Child @hook:mounted="doSomething" ></Child> doSomething() { console.log('父组件监听到 mounted 钩子函数 ...'); }, // Child.vue mounted(){ console.log('子组件触发 mounted 钩子函数 ...'); }, // 以上输出顺序为: // 子组件触发 mounted 钩子函数 ... // 父组件监听到 mounted 钩子函数 ...
当然 @hook 方法不仅仅是可以监听 mounted,其它的生命周期事件,例如:created,updated 等都可以监听。
14. 组件中 data 为什么是一个函数?
因为 Vue 在创建组件实例时,会为每个组件实例都创建一个独立的数据作用域。
如果将 data 直接定义为一个对象,那么所有组件实例都将共享同一个数据对象,这样就无法实现数据的隔离。
data 是函数的话那么每次创建组件实例时,都会调用这个函数并返回一个新的对象。