当前位置: 首页 > Web前端 > vue.js

今年秋招的前端体验(一)Vue部分

时间:2023-04-01 12:04:35 vue.js

VueVue虚拟DOM文档对象模型或DOM定义了一个接口,可以让JacasCript访问和操作HTML文档。元素用数字中的节点表示,界面允许我们操作它们,但是大量非常频繁的DOM操作会拖慢页面。每个元素都是一个节点,每段文字也是一个节点。节点是页面的一部分。每个节点也有相应的子节点。VirtualDOM就是为了解决操作真实DOM带来的性能问题。虚拟DOM就是用js对象模拟真实的DOM节点(虚拟节点VNode),即更新DOM的所有操作。先在JS对象上操作内存中的js对象显然要快很多。更新完成后,将最终的JS对象映射到真实的DOM中,让浏览器绘制页面。总结一下,就是获取监听变化,将生成的虚拟节点号与上次虚拟DOM节点号进行比较,找出差异,渲染到真实DOM节点,更新diff算法。由于在浏览器中操作DOM的成本非常“昂贵”,因此在Vue中只使用了引入VirtualDOM,VirtualDOM是对真实DOM的抽象描述,不了解的朋友可以自行查阅相关资料。即使使用VirtualDOM来渲染真实DOM,当页面更新时,也无法完整渲染整个VirtualDOM,而是渲染变化的部分。这时候就需要对VirtualDOM树变化的部分进行计算。算法,这个算法就是Diff算法。简单的说,就是新旧虚拟dom的对比。如有差异,以新的为准,再插入真实dom。重新渲染只会做同级比较,不会做跨级比较。比较后,如果(oldVnode===vnode),它们的引用是一致的,可以认为没有变化if(oldVnode.text!==null&&vnode.text!==null&&oldVnode.text!==vnode.text),比较文本节点,需要修改,会调用Node.textContent=vnode.text。if(oldCh&&ch&&oldCh!==ch),两个节点都有子节点,而且不相同,所以我们会调用updateChildren函数比较子节点,这就是diffelseif(ch)的核心,只有new节点有子节点,调用createEle(vnode),vnode.el已经引用了旧dom节点,createEle函数会在旧dom节点上添加子节点。elseif(oldCh),新节点没有子节点,老节点有子节点,直接删除老节点。key的作用不是设置key。newCh和oldCh只会比较头尾端。设置key后,除了比较头尾,还会从用key生成的对象oldKeyToIdx中找到匹配的节点,所以为节点设置key可以更高效的利用DOM,所以我们需要用key为每个节点做一个唯一的标识,Diff算法才能正确识别这个节点,找到正确的位置插入新的节点。key的作用主要是高效的更新虚拟DOM。另外,在vue中对同标签名的元素进行transition时,也会用到key属性。目的也是为了让vue区分他们。否则,vue只会替换其内部属性,而不会触发过渡效果。v-for中的key主函数的主要作用:key的主要作用是提高渲染性能!key属性可以避免数据混淆(如果元素中包含有临时数据的元素,不使用key会造成数据混淆)。Vue的一大特色是双向数据绑定。一旦数据发生变化,页面将呈现一个新的页面。数据呈现在页面上。为了减少添加数据时的渲染值,重复使用未改变的值,从而提高效率。v-for默认使用重用策略。当列表数据被修改时,会根据key值判断某个值是否被修改。如果修改了,会重现渲染图,否则会重复使用。最好用一个value不变的item作为key,对应item,即每条数据都有一个唯一的id,用来标识这条数据的唯一性。vue双向绑定原理MVVMM(MODEL,模型层),V(View,视图层)VM(ViewModel,连接V和M的桥梁,也可以看成是控制器)MVVM支持双向绑定,也就是说当M层数据进行修改时,VM层会监听到变化,并通知V层进行相应的修改。否则,修改V层会通知M层数据被修改,从而实现视图层和模型层的相互解耦。vue双向数据绑定是通过数据劫持结合发布订阅模式实现的,也就是说数据和视图是同步的,数据变了,视图变了,视图变了,数据变了也有变化。核心:关于Vue双向数据绑定,其核心是Object.defineProperty()方法。下面介绍Object.defineProperty()方法Object.defineProperty(obj,prop,descriptor)。这个语法中有三个参数,分别是obj(要定义的属性的对象)prop(要定义或修改的属性)descriptor(具体的改变方法)简单的说,这个方法就是用来定义一个价值。调用的时候,我们使用里面的get方法。当我们给this赋属性的时候,会用到它里面的set方法。具体例子可以参考:https://www.jianshu.com/p/e7e...响应式的原理是将一个普通的JavaScript对象作为dataoption传给Vue实例,Vue会遍历这个对象的所有属性对象,并使用Object.defineProperty将所有这些属性转换为getters/setters。Object.defineProperty是ES5特性,这也是Vue不支持IE8及更低版本浏览器的原因。  这些getters/setters对用户是不可见的,但在内部它们允许Vue跟踪依赖项并在访问和修改属性时通知更改。  每个组件实例对应一个watcher实例,watcher实例会在组件渲染过程中记录“touched”的数据属性作为依赖。然后,当依赖项的设置器触发时,观察者会收到通知,从而导致其关联的组件重新呈现。    简单理解就是通过数据劫持结合发布订阅者模型实现的。说白了,Object.defineProperty()就是用来劫持对象属性的setter和getter操作,通过发布订阅者模型来实现数据变化时的更新尝试。computedcomputed属性是vue实例中的一个配置选项:computed,比如将三门课程的成绩写在data中,我们需要计算平均值。我们可以在方法中写函数来计算。但是更好的解决方案是vue提供的计算属性通常是计算相关的函数。函数里面可以写很多逻辑,最后返回计算出来的值,也就是我们可以把计算过程写到每个计算属性里面。,让它动态计算。计算属性通常用于从其他数据中计算出一个新数据,一个优点是它可以缓存新数据。在其他依赖的数据没有变化的情况下,调用缓存的数据,极大地提高了程序的性能,并且写在了方法中。数据完全没有缓存的概念,所以每次都会重新选择。这就是不使用方法的原因。Vue生命周期Vue实例有一个完整的生命周期,也就是说,从创建、初始化数据、编译模板、挂入DOM、渲染-更新-渲染、卸载等一系列过程,我们称之为Vue的生命周期,hook是为了让你有机会在某个阶段做一些处理beforeCreate(创建前):实例初始化后,在数据观察和事件配置之前调用。此时option对象还没有创建,el和data还没有初始化,所以不能访问上面的methods、data、computed等方法和数据。created(aftercreation):实例创建后调用。这一步实例已经完成了如下配置:数据观察,属性和方法的操作,watch/event事件回调,data数据的初始化已经完成,但是el还没有。但是,挂载阶段还没有开始,$el属性目前是不可见的。这是一个常见的生命周期,因为可以在methods中调用方法,在data中更改数据,修改可以通过Vue的响应式绑定体现在页面上,在computed中获取计算的属性等。通常我们可以进行预处理实例在这里,有些喜欢在这里发送ajax请求。值得注意的是,在这个循环中没有生命方法实例化过程被拦截,所以如果必须获取一些数据才能允许访问页面,不适合在这个方法中发送请求。建议在组件路由钩子中完成beforeMountbeforeRouterEnter:挂载开始前调用,相关render函数第一次调用(虚拟DOM),实例已经完成如下配置和编译模板,从数据生成html和data中的templates,完成el和data的初始化。注意此时html还没有挂载到页面上。mounted:挂载完成,即模板中的HTML渲染到HTML页面。这时候一般可以做一些ajax操作。mounted只会执行一次beforeUpdata:它在数据更新之前被调用,它发生在虚拟DOM重新渲染和修补之前。钩子中状态的进一步变化不会触发额外的重新渲染过程更新(updated):虚拟DOM重新渲染和打补丁只会因数据变化而被调用。当被调用的时候,组件DOM已经更新了,所以依赖可以执行基于DOM的操作,那么在大多数情况下,你应该避免在这期间更新状态,因为这可能会导致更新的死循环。服务器渲染期间不会调用此挂钩。beforeDestory(销毁前):在实例销毁之前调用,实例这一步还是完全可用的。此步骤也可用于获取实例。一般在这一步会进行一些复位操作,比如清除组件中的定时器,监听的dom事件等。destroyed(afterdestruction):实例被销毁后调用,调用后,同期所有事件都会被移除,所有子实例也会被销毁。服务器端渲染期间不会调用此挂钩。Vue和React在监控数据变化方面有不同的实现原理。Vue使用getter/setter和一些函数。劫持,可以准确知道数据的变化。React默认比较引用(diff)。如果不优化,可能会导致大量不必要的VDOM重新渲染。为什么React不能准确监控数据变化?由于Vue和React在设计理念上的差异,Vue使用可变数据,而React强调数据的不可变性。两者没有区别。Vue更简单,而React更适合构建大型应用。Vue1.0中可以根据不同的数据流实现两种双向绑定:父子组件之间,props可以双向绑定;组件和DOM之间可以通过v-model进行双向绑定。Vue2.x去掉了父子组件的双向绑定(但提供了一个语法糖来帮助你通过事件自动修改),并且Vue2.x已经不鼓励组件对自己的props进行任何更改。React从来不支持双向绑定当然提倡单向数据流,这就是所谓的onChange/setState()模式。但是,由于我们一般使用Vuex、Redux等状态管理框架进行单向数据流,所以往往感觉不到HoC和mixinVue的区别。不同功能组合的方式就是通过mixin。Vue中的组件是一个封装好的函数。,不仅仅是我们在定义组件时传入的对象或函数。比如我们定义的模板是如何编译的?例如,声明的props是如何接收的?这些都是Vue在创建组件实例时隐式做的事情。因为Vue默默的为我们做了这么多事情,如果我们直接把下面组件的声明包装起来,返回一个HoC,那么包装好的组件是无法正常工作的。React结合不同功能的方式是通过HoC(高阶组件)。React一开始也是用mixins,但是后来觉得这种方式侵入性太强,会带来很多问题,所以放弃了mixinx,改用HoC。高阶组件的本质是高阶函数。React组件是纯函数,因此高阶函数对于React来说非常简单。组件通信的区别Vue中实现组件通信的方式有3种:父组件通过props向子组件传递数据或回调。虽然可以传递回调,但我们一般只传递数据。子组件通过事件向父组件发送消息。通过V2.2.0父组件中新增的provide/inject可以向子组件注入数据,可以跨越多个层级。React也有对应的三种方法:父组件可以通过props向子组件传递数据或者回调可以通过context跨级通信,其实类似于provide/inject的作用。React本身不支持自定义事件,在Vue中子组件向父组件传递消息有两种方式:事件和回调函数,但Vue更喜欢使用事件。在React中,我们都使用回调函数,这可能是它们之间最大的区别。表层的模板渲染方式不同,模板语法也不同。React通过JSX渲染模板。Vue通过扩展的HTML语法来渲染,但实际上这只是表面现象。与React相比,它不必深入依赖JSX,模板的原理也不同。这就是本质区别:React是在组件的JS代码中实现的,通过原生JS实现模板中的常用语法,比如插值、条件、循环等,都是通过JS语法实现的,更纯净而原生。Vue是通过与组件JS代码分离的单独模板中的指令来实现的。例如,条件语句需要V-IF才能实现。对于这一点,这种做法似乎有点独特,而且会把HTML搞乱。举例说明React的好处:React中的render函数支持闭包特性,所以我们导入的组件可以直接在render中调用。但是在Vue中,由于模板中使用的数据一定要挂载到这个上,所以我们导入一个组件后,需要在components中重新声明一次,这看起来很奇怪,但又不得不这样做,Vue可以计算出差异当渲染过程不同时,VDOM的速度更快。这是因为它会在渲染过程中跟踪每个组件的依赖关系,不需要重新渲染整个组件库。组件会被重新渲染,这可以通过shouldComponentUpdate生命周期方法来控制,但Vue将此视为默认优化。如果应用程序中的交互很复杂,需要处理大量的UI变化,那么使用VDOM是个不错的主意。如果更新元素不频繁,那么VDOM不一定适用,性能可能不如直接操作DOM框架。Vue的本质不同于MVVM框架。React是从MVC发展而来的前端组件框架,而Vuex和Redux的区别是从后端组件化发展而来。从表面上看,商店注入和应用程序之间存在一些差异。在Vue中,$store是直接注入到组件实例中的,因此可以更灵活的应用:使用dispatch,commit提交更新,通过mapState或者直接通过this.$store读取数据。在Redux中,我们的每个组件都需要实际使用connect来连接所需的props和dispatch。另外,Vuex更加灵活。组件可以派发动作或提交更新,而Redux只能派发,不能直接调用reducer进行修改。在实现原理上,最大的区别有两点:Redux使用的是不可变数据,而Vuex的数据是可变的。所以Redux每次都是用新状态替换旧状态,而Vuex在Redux检测到数据变化时直接修改差异,通过diff比较差异。Vuex和Vue的原理一样,这两点的区别是通过getter/setter来比较的,也是因为React和Vue的设计理念不同。React更倾向于构建稳定的大型应用程序。它非常坚硬。Vue更倾向于简单快速的解决问题。它比较灵活,不严格遵守规章制度。因此,也会给人一种大项目用React,小项目用Vue的感觉。vue-router中keep-alive的使用背景:在基于vue的单页富应用开发中,总会有这样的产品需求,即从列表页跳转到详情页,以及状态返回时需要保存列表页面在这种场景下,如果往全局状态写入数据,总是会面临复杂的页面路由判断来清除和保存页面状态。keep-alive介绍在2.x版本中,Vue将keep-alive的既定属性扩展为内置抽象组件本身不会渲染一个DOM元素,也不会出现在父组件链中.当组件在中切换时,其activated和deactivated的生命周期钩子函数会相应执行。保持被keep-alive组件包裹的组件的状态,避免组件的重复渲染。computed中的getsetget是根据其他数据获取computed中定义的数据。该集合基于计算中定义的数据。更改其他数据VuexVuex是专门为Vue.js应用开发的状态管理模式。它使用集中存储来管理应用程序所有组件的状态,并使用相应的规则来确保状态以可预测的方式变化。个人理解Vuex是一个管理组件间通信的插件。Vuex和简单的全局对象有以下两个区别之一:Vuex的状态存储是响应式的。当Vue组件从store中读取状态时,如果store中的状态发生变化,相应的组件将相应地高效更新,而不能直接更改store中的状态。更改存储中状态的唯一方法是显式提交更改。这使我们能够轻松地跟踪每个状态变化,使我们能够实现一些工具来帮助我们更好地了解我们的应用商店。每个Vuex应用程序的核心是商店(仓库)。“Store”基本上是一个容器,它包含了你应用程序中的大部分状态(state)。State-drivenapplication的数据源用于保存构建的所有公共数据。getter可以理解为store的计算属性,getters函数的返回值会根据其依赖关系缓存起来,只有当其依赖值发生变化时才会重新计算。Mutationmutations对象中保存变化数据的回调函数,函数名官方叫type,第一个参数为公式状态,第二个参数payload,为自定义参数。mutation必须是一个同步函数。mutation对象中的方法需要使用store.commit调用ActionAction来提交mutation,而不是直接改变状态。action可以包含任何异步操作。action对象中的方法需要store.dispatch调用Action函数接受一个和store实例属性相同的c??ontext对象,所以可以调用context.commit提交mutation,或者使用context.state和context.getters获取state和gettershash和history理解hash模式:即地址栏中URL中的#符号(这个hash不是密码学中的hash操作)。比如这个网址:http://www.abc.com/#/hello,哈希值为#/hello。它的特点是虽然hash出现在URL中,但不会包含在HTTP请求中,对后端完全没有影响,所以更改hash不会重新加载页面。历史模式:利用HTML5历史界面中新的pushState()和replaceState()方法。(需要特定浏览器支持)这两个方法应用于浏览器的历史栈。在已有的back、forward、go的基础上,提供了修改历史的功能。只是当他们进行修改的时候,虽然改变了当前的URL,但是浏览器并不会立即向后端发送请求。vue32020.9.19新特性,友达正式发布Vue3.0版本。这个代号为OnePiece的框架新大版本提供了更好的性能、更小的包大小、更好的TypeScript集成、用于处理大规模用例的新API,并为框架未来的长期迭代奠定了坚实的基础。Proxy是在Vue3.0的基础上引入的。Proxy是ES6中的一个新特性。它用于定义基本操作(如属性查找、赋值、枚举、函数调用等)的自定义行为。Proxy可以理解为,在目标对象中志强承担了一层拦截。外部访问这个对象首先要经过这一层拦截,所以提供了一种机制来过滤和重写外部访问,修改某些操作的默认行为,这样我们就不能直接操作对象本身了,但是本义Proxy这个词的意思是代理。这里用它来表示它的某些操作。当组件变得越来越大时,它可以被翻译为组合API(CompositionAPI),逻辑问题的列表也在增长。这会导致组件难以阅读和理解,碎片化使得理解和维护复杂组件变得困难。选项的分离掩盖了潜在的逻辑问题。另外,在处理单个逻辑关注点时,要不断“跳转”相关代码的选项块。如果同一个逻辑关注点相关的代码能配置在一起就更好了,于是就产生了compositionAPI,使用compositionapi的位置调用setup,引入createAPP从技术上讲,Vue2没有app的概念,我们的applicationdefine只是newVue()创建的根Vue实例。从同一个Vue构造函数创建的每个根实例共享相同的全局配置,因此全局配置很容易在测试过程中意外污染其他测试用例。用户需要小心保存原来的全局配置,并在每次测试后恢复。一些api没有restore方法,这使得设计插件的测试特别棘手v-modelusagehaschangedoncomponentswhencustomv-model,propandtimedefaultnamehaschangedprop:value->modelValueenent:input->更新:模型值。sync和components的model选项已经被移除,v-model可以作为替代现在你可以在同一个组件上使用多个v-model进行双向绑定现在你可以定义v-model修饰符比如自定义v-model.capiyalize,绑定到字符串首字母大写和non-v-for节点上的key用法有变化Vue2.x推荐在v-if/分支使用v-else/v-else-ifkey,Vue3.x仍然可以正常工作,但不再推荐,所以当条件分支没有提供key时,会自动生成一个唯一的key。Vue2.x中的