当前位置: 首页 > Web前端 > HTML

Vue3.0面试题

时间:2023-04-02 12:46:27 HTML

,先介绍一下Vue的响应式系统。Vue是一个MVVM框架。当数据模型数据发生变化时,页面视图将相应更新。原理是拦截数据(Object.definePropertyorProxy)的getter/setter方法,使用发布-订阅设计模式,在getter方法中订阅,在setter方法中发出通知,让所有订阅者完成响应.在响应式系统中,Vue会为数据模型data的每个属性创建一个新的订阅中心作为发布者,而listenerwatch、computed属性computed、viewrenderingtemplate/render这三个角色同时作为订阅者.对于listenerwatch,会直接订阅被观察和被监控的属性。对于计算属性和视图渲染模板/render,如果内部执行获取到数据的某个属性,就会执行该属性的getter方法,然后自动完成对该属性的订阅。当属性被修改时,会执行属性的setter方法,从而完成属性的发布通知,通知所有订阅者进行更新。computed和watch的区别computedattribute和listenerwatch都可以观察到属性的变化并做出响应。不同的是:计算属性更多的是缓存函数的观察者,它可以对一个或多个数据属性进行复杂的计算,生成一个新的值提供给渲染函数。当依赖属性发生变化时,computed不会立即重新计算生成新值,而是先标记为脏数据,下次获取computed时再使用。将重新计算并返回。侦听器手表没有缓存能力。listenerwatch提供监听功能。当被监控的属性发生变化时,该函数将立即执行。引入Vue的生命周期beforeCreate:它是newVue()之后触发的第一个钩子。目前阶段,data、methods、computed、watch上的数据和方法是无法访问的。created:实例创建后发生。当前阶段已经完成了数据观察,即可以使用和更改数据。更改此处的数据不会触发更新功能。可以做一些初步的数据获取,现阶段还不能和Dom交互。如果你愿意,你可以通过vm.$nextTick访问Dom。beforeMount:发生在挂载之前,在模板模板导入并编译渲染函数之前。目前阶段,虚拟Dom已经创建完成,即将开始渲染。此时也可以更改数据而不触发更新。mounted:挂载完成后发生。现阶段挂载真正的Dom,双向绑定数据,可以访问Dom节点,通过$refs属性来操作Dom。beforeUpdate:发生在更新之前,即响应式数据更新时,在虚拟dom重新渲染之前触发。您可以在当前阶段更改数据而不会导致重新渲染。updated:更新完成后发生,当前阶段的组件Dom已经更新。小心避免在这段时间内更改数据,因为这可能会导致更新无限循环。beforeDestroy:在实例销毁之前发生,当前阶段实例可以完全使用。这个时候我们可以进行收尾工作,比如清空定时器。destroyed:实例销毁后发生,此时只剩下dom壳。组件拆了,数据绑定拆了,监听器拆了,子实例全部销毁了。为什么组件的数据必须是一个函数?一个组件可能会被用在很多地方,也就是会创建很多实例。如果数据是对象,则该对象是引用类型。一个实例修改数据会影响其他实例,所以数据必须使用函数为每个实例创建自己的数据,这样同一个组件的不同实例不会相互影响。组件如何通信?父子组件通信父组件->子组件:prop子组件->父组件:$on/$emit获取组件实例:使用$parent/$children、$refs.xxx,获取实例后直接获取属性数据或调用组件方法与兄弟组件通信。EventBus:每个Vue实例都是一个EventBus,支持$on/$emit。您可以在同级组件的实例之间创建一个新的Vue实例,以作为事件总线进行通信。.Vuex:提取状态和方法到Vuex,完成共享的跨层组件通信使用provide/injectEventBus:与兄弟组件通信EventBusVuex:提取状态和方法到Vuex,完成共享的Vue事件绑定原理说说各个Vue实例是事件总线。当子组件被创建时,父组件将事件传递给子组件。在子组件初始化的时候,有一个$on方法在里面注册事件,需要的时候用$emit来触发函数。对于原生原生事件,使用addEventListener绑定到真实的DOM元素。什么是插槽?效果如何?原理是什么?Slot,又称槽,是Vue的内容分发机制。组件内部的模板引擎使用slot元素作为承载和分发内容的出口。Slot槽是子组件的一个模板标签元素,是否显示以及如何显示这个标签元素由父组件决定。插槽分为三种类型:默认插槽、命名插槽和作用域插槽。Defaultslot:又称匿名检查,当slot没有指定name属性值时,默认显示一个slot,一个组件中只有一个anonymousslot。命名插槽:具有特定名称的插槽,即具有名称属性的插槽。一个组件中可以出现多个命名槽。scopeslot:defaultslot,namedslot的变种,可以是匿名slot也可以是namedslot,这个slot的区别在于子组件渲染scopeslot时,子组件内部的数据传递给父组件,父组件组件根据从子组件传递的数据决定如何渲染插槽。实现原理:子组件vm实例化时,获取父组件传入的slot标签内容,存放在vm.$slot中。默认插槽为vm.$slot.default,命名插槽为vm.$slot.xxx,xxx为插槽名称。组件在执行渲染函数时,遇到一个slot标签,将其替换为$slot中的内容。这时候,数据就可以传到槽中了。如果有数据,则该槽可以称为Scoped槽。Vue模板渲染的原理是什么?vue中的template模板无法被浏览器解析渲染,因为这不是浏览器标准,不是正确的HTML语法,所以需要将模板转换成JavaScript函数,这样浏览器才能执行这个函数并渲染它对应的HTML元素可以使视图运行起来,这个转换过程称为模板编译。模板编译分为三个阶段,解析parse,优化optimize,生成generate,最后生成可执行函数render。解析阶段:使用大量正则表达式解析模板字符串,将标签、指令、属性等转化为抽象语法树AST。优化阶段:遍历AST,找到一些静态节点并标记出来,这样当页面重新渲染时,可以直接跳过这些静态节点,从而优化运行时的性能。生成阶段:将最终的AST转换为渲染函数字符串。什么是模板预编译?对于Vue组件,模板编译只会在组件实例化时编译一次,生成渲染函数后不会再编译。因此,编译是组件运行时的性能损失。模板编译的目的只是将模板转换为渲染函数。这个过程可以在项目构建过程中完成,使得实际组件在运行时可以直接跳过模板渲染,从而提高性能。这是在项目建设过程中完成的。编译模板的过程就是预编译。模板和jsx有什么区别?对于运行时,我们只需要保证组件有render函数即可,而在我们预编译之后,只需要保证在构建过程中生成render函数即可。在webpack中,我们使用vue-loader编译.vue文件,在webpack构建过程中,内部依赖vue-template-compiler模块将模板预编译成render函数。和react类似,加入jsx语法糖解析器babel-plugin-transform-vue-jsx后,可以直接手写render函数。所以template和jsx都是渲染的一种形式。不同的是,JSX比template有更高的灵活性,在复杂的组件上更有优势,而template就显得有点迟钝了。但是template在代码结构上更符合视图和逻辑分离的习惯,更简单,更直观,也更好维护。先说说什么是VirtualDOMVirtualDOM是JavaScript中DOM节点的一种抽象数据结构。之所以需要虚拟DOM,是因为在浏览器中对DOM的操作是昂贵的,频繁操作DOM会带来性能问题。虚拟DOM的作用是每次响应式数据发生变化,重新渲染页面时,Vue都会比较更新前后的虚拟DOM,匹配找到尽可能少的需要更新的真实DOM,所以从而达到提高性能的目的。介绍Vue中的Diff算法。比较新旧虚拟DOM时,首先比较节点本身,判断是否是同一个节点。如果不是,则删除节点并重新创建节点以进行替换。如果是同一个节点,执行patchVnode,判断如何处理这个节点的子节点,先判断一方有子节点,另一方没有子节点的情况(如果新的孩子没有子节点,去掉旧子节点),比较是否有所有子节点,然后updateChildren,判断如何对这些新旧节点的子节点进行操作(diff核心)。匹配时,找到相同的子节点,递归比较diff中的子节点,只比较同一层的子节点,放弃跨层节点比较,这样时间复杂度从O(n^3)降低到O(n),也就是说,只有当新旧子节点为多个子节点时,才需要使用核心Diff算法进行同级比较。key属性的作用是什么?在diff节点的过程中,判断是否为同一节点的一个重要条件是key是否相等。如果是同一个节点,会尽可能重用原来的DOM节点。所以key属性是提供给框架在比较时使用的,而不是开发人员。说说Vue2.0和Vue3.0的区别重构响应式系统,用Proxy代替Object.defineProperty,使用Proxy的好处:可以直接监听数组类型的数据变化,监听的对象是对象本身,没有需要像Object.defineProperty一样遍历每个属性,有一定的性能提升,可以拦截apply、ownKeys、has等13个方法,但Object.defineProperty不能直接实现对象属性的增删改查。新的CompositionAPI,更好的逻辑重用和代码编译VirtualDOM模板时组织重建优化,将一些静态节点编译成常量slot进行优化,将slot编译成惰性函数,将slot渲染的决定权交给抽取和子组件模板中内联事件的复用(原来每次渲染都会重新生成Inline函数)代码结构调整更方便Treeshaking,体积更小使用Typescript代替Flow为什么要加CompositionAPI,能解决什么问题在Vue2.0中,随着功能的增多,Components越来越复杂,维护难度越来越大。困难的根本原因是Vue的API设计迫使开发人员使用watch、computed和methods选项来组织代码,而不是实际的业务逻辑。另外,Vue2.0缺乏一个相对简单和低成本的机制来完成逻辑复用。minxis虽然可以完成逻辑复用,但是当mixin比较多的时候,会导致很难找到对应的data、computed或者method的来源。mixins,使类型推断变得困难。因此,CompositionAPI的出现主要是为了解决OptionAPI带来的问题。首先是代码组织的问题。CompostionAPI允许开发者按照业务逻辑组织自己的代码,让代码有更好的可读性和可扩展性,也就是说,当下一个开发者接触到一段不是自己写的代码时,他可以更好的利用代码的组织方式推导出实际的业务逻辑,或者说根据业务逻辑更好的理解代码。二是实现代码的逻辑抽取和复用。当然,mixin也可以实现逻辑抽取和复用,但是如前所述,当多个mixin作用于同一个组件时,很难看出属性来自于哪个mixin,来源不明。此外,多个mixin的属性存在变量命名冲突的风险。CompositionAPI正好解决了这两个问题。据说CompositionAPI与ReactHook非常相似。让我们谈谈区别。从ReactHook的实现来看,ReactHook是根据useState的调用顺序来判断下一次重新渲染的state来自哪个useState,所以出现如下限制。在循环、条件和嵌套函数中调用Hook时,必须始终在React函数的顶部调用Hook。UseEffect、useMemo和其他函数必须手动确定依赖关系。CompositionAPI是基于Vue的响应式系统实现的,而ReactHook的与setup函数中的声明相比,一个组件实例化只调用一次setup,ReactHook每次重新渲染都需要调用Hook,这使得React的GC更加比Vue压力大,性能也比Vue慢。CompositonAPI的调用不需要担心调用顺序。它还可以使用响应式系统自动实现循环、条件和嵌套函数中的依赖收集。然后,一些组件的性能优化是Vue自己做的,而ReactHook需要手动传入依赖,并且必须保证依赖的顺序,这样useEffect和useMemo等函数才能正确捕获依赖变量,否则组件性能会因不正确的依赖关系而降低。CompositonAPI虽然看起来比ReactHook好用,但其设计思想也是基于ReactHook。SSR懂吗?原理是什么?当客户端请求服务器时,服务器从数据库中获取相关数据,并在服务器内部将Vue组件渲染成HTML,并将数据和HTML一起返回给客户端。服务端将数据和组件转换成HTML的过程称为服务端渲染SSR。而当客户端拿到服务端渲染的HTML和数据时,由于数据已经存在,客户端不需要再次请求数据,只需要将数据同步到组件或者Vuex内部即可。除了数据意外之外,HTML结构已经存在。客户端在渲染组件时,只需要将HTMLDOM节点映射到VirtualDOM即可。无需重新创建DOM节点。这个同步数据和HTML的过程,也称为客户端激活。使用SSR的好处:对SEO有好处:其实爬虫爬你的页面是有好处的,因为有些页面爬虫不支持JavaScript执行,不支持JavaScript执行的爬虫抓到的非SSR页面会是一个EmptyHTML页面,加上SSR,这些爬虫就可以获得完整的HTML结构的数据,然后收录到搜索引擎中。白屏时间更短:与客户端渲染相比,服务端渲染在浏览器请求URL后,已经得到了一个带有数据的HTML文本。浏览器只需要解析HTML,直接构建DOM树。对于客户端渲染,你需要先得到一个空的HTML页面。此时页面已经进入白屏,接下来需要加载并执行JavaScript,请求后端服务器获取数据,JavaScript渲染页面,查看最终结果。页。尤其是在复杂的应用中,由于需要加载JavaScript脚本,应用越复杂,需要加载的JavaScript脚本越多越大,会导致应用首屏加载时间非常长,从而降低体验感。更详细的内容请看吃透服务端渲染原理-SSRhttps://github.com/yacan8/blo...