面试集合

178 阅读23分钟

juejin.cn/post/684490…

  1. Vue2的响应式原理? 答:主要是由Observer,Dep(依赖管理器),Watcher(监听器)实现的,在Vue初始化数据的时候,会将每个data属性进行响应式绑定,通过Object.defineProperty方法进行重新定义,当页面使用对应的属性时,会触发getter方法去收集对应的依赖watcher到各自属性依赖管理器上,当属性发生了变化,会触发setter方法,通过依赖管理器找到属性的所有watcher方法,执行对应的更新方法。

  2. Vue3的响应式原理? 答:用proxy替代Object.defineProperty,因为proxy也可以做到监听对象的变化;

  3. Vue2的如何监听对象和数组变化? 答: juejin.cn/post/684490… juejin.cn/post/684490… 拦截数组对象的原型 重新定义一个新的拦截器,重新给push,pop,shift,unshift,sort,reverse,splice七种方法做监听 Vue将data中的数组进行了原型链重写,指向自己定义的数组原型方法,这样在调用数据api时,可以通知依赖更新,实现监测数组的变化(如果数组中包含有引用类型,则会对数组+中的引用类型再次递归遍历进行监测) const arrayMethods = Object.create(Array.prototype); // 重新定义一个新的拦截器,避免污染Array.prototype Object.defineProperty(arrayMethods, 'push' / 'pop' .... 七种方法;, { value (...args) { // 监听操作 ......

     Array.prototype.push.apply(this, args);
    

    }, enumerable: true, writable: true, configurable: true })

let list = [1];

list.proto === arrayMethods; list.push(2, 3); // 此时就能监听这个数组的变化

  1. 什么是MVVM? juejin.cn/post/684490… 答:model(数据模型)-view(UI视图层)-viewModel(); Model层:通过Ajax/Fetch等API完成客户端和服务端数据的同步; View层:作为视图模板存在,作为一个动态模板,除了定义页面结构之外,还做了数据绑定的声明,指令声明,事件绑定声明 ViewModel层:将View层的数据绑定声明,指令声明,事件绑定声明等做对应的处理,当数据变化,view层会得到更新 MVVM最标志性的特性就是数据绑定,核心理念是通过声明式的数据绑定来实现View层个其他层的分离; MVVM实现了双向绑定(数据变化更新视图,视图变化更新数据),ViewModel的内容会实时展现在View层,不必去操作DOM,因为框架的底层已经做好了; view展示ViewModel的数据,ViewModel跟Model层交互获取最新数据,就像作为两者之间的桥梁 MVVM的设计思想:关注Model的变化,让MVVM框架去自动更新DOM的状态,从而把开发者从操作DOM的繁琐步骤中解脱出来

与mvc的最大区别: 1.mvc是由view层发起交互事件给controller的事件控制器做处理,然后传递给model层,model层再跟view层做交互;而在mvvm中,view和model是没有直接的关联的,都是通过vm层实现两者的联系,做到数据更新视图,视图变化更新数据层 2.在mvc中,当用户触发交互事件,传到控制器事件处理器进行处理,需要操作大量的dom数据,这个过程会导致浏览器频繁的回流和重绘,导致页面渲染性能下降,加载速度变慢,用户体验不好 3.在mvvm中,view层与model层两者互不干扰,view层通过模板,指令绑定,事件绑定与viewmodel产生关联,当model的数据发生变化告知viewmodel,viewmodel作出对应的响应式更新视图

mvc: model:模型层,处理数据逻辑相关 view:视图层,展示视图内容,与用户做交互 controler:控制层,事件处理器 当用户与view层做交互触发相关事件交互,controller控制器将作出对应的回调函数,操作dom,与model层做数据对接,当model层数据发生变化,会触发对应的更新函数,从而更新视图

5.nextTick实现原理? 答:在下次Dom更新循环结束之后执行的延迟回调函数,当页面数据发生变化,会触发对应的watcher的回调函数被push到vue中自定义的一个任务队列数组,当前主线程执行栈为空时就会去清空对应任务队列中的回调函数,当调用nexttick的话对应的回调函数也就在任务队列当中了。 pending标志符决定只能加入一次nextTick。

6.Vue的生命周期? 答:beforeCreate->created->beforeMount->mounted->beforeUpdate->updated->beforeDestroy->destoryed beforeCreate:new Vue()之后触发的第一个钩子,在调()之后触发的第一个钩子,在调用initState(初始化props,data,methods,computed,watch)之前,所以这个阶段不可访问所有数据和方法 created:在实例创建之后发生,initState之后调用,可以使用数据,更改数据,但是不会触发updated函数,这个时候还不能与Dom进行交互,可以通过vm.nextTick来访问DombeforeMount:发生在挂载之前,template模板已经导入渲染函数编译,而当前阶段的VNODE已经创建完成,即将开始渲染,可以对数据进行更改不会触发updatedmounted:发生在挂载之后,真实的Dom挂载完成,数据完成双向绑定,可以访问到Dom节点,使用nextTick来访问Dom beforeMount:发生在挂载之前,template模板已经导入渲染函数编译,而当前阶段的VNODE已经创建完成,即将开始渲染,可以对数据进行更改不会触发updated mounted:发生在挂载之后,真实的Dom挂载完成,数据完成双向绑定,可以访问到Dom节点,使用refs属性对Dom进行操作,可以向后台发送请求,拿到数据 beforeUpdate:在响应式数据发生更新,虚拟Dom重新渲染之前被触发,在这个阶段更改数据,不会造成重新渲染 updated:数据更新之后,当前阶段的Dom已完成更新,避免在这个阶段更新数据,会造成无限循环更新 beforeDestroy:在发生实例销毁之前,当前阶段的该实例还可以被使用,这个阶段可以清除定时器 destroyed:发生在实例销毁之后,只剩下dom空壳,组件被拆散,数据绑定被拆除,监听被移除,子实例也统统销毁 activated:keep-alive组件激活时被调用,===============该钩子在服务端渲染期间不被调用 deactivated:keep-alive组件停用时调用,同上 errorCaptured:捕获子孙组件的错误时被调用,可以防止当一个错误被捕获时该组件进入一个无限的渲染循环中

父 beforeCreate->父 created->父 beforeMount->子 beforeCreate->子 created->子 beforeMount->子 mounted->父 mounted 父 beforeUpdate->子 beforeUpdate->子 updated->父 updated 父 beforeUpdate->父 updated 父 beforeDestroy->子 beforeDestroy->子 destroyed->父 destroyed

new Vue() -> 调用Vue.prototype._init(),执行initLifecycle(确认组件的父子关系,挂载parent,parent,children),执行initEvents(处理自定义事件传递给子组件,处理on,on,emit),执行initRender(将render函数转换成Vnode)-> beforeCreate钩子函数 -> initInjection -> initState(初始化data,props,methods,computed,watch) -> initProvide(初始化父组件提供的provide依赖) -> created -> 执行mountComponent对element进行挂载 -> beforeMounte钩子函数 -> 执行updateComponent(执行vm._update(vm._render()))生成VNODE并传给update调用patch生成真实的dom -> 执行mounted钩子函数

7.Vue2跟Vue3的差异? 答: 1.响应式监听方式不同:Vue2基于Object.defineProperty,不具备监听数组的能力,需要重新定义数组的原型来达到响应式目的,而Vue3基于proxy可以监听原生数组,并且实现对对象属性的添加和删除 2.对初始化data的要求较高,vue2需要将所有属性放在data对象vue才能转换为响应式,而vue3不需要,可以动态监听对象属性的添加和删除 3.proxy只能兼容到IE11 4. 全面支持TypeScript 5. watch,mixin写法改进 Vue2的数据劫持方法的缺点: 有时候数据更新了,但是页面没有更新; 原因分析:直接修改数组下标值或者是对data的对象新增了属性,这些都不会被vue检测到,需要用this.set方法在vue2中,直接修改数组的下标值不会触发视图更新,vue2是通过对数组的七大方法进行原型链的拦截,重新写了一个原型对象,让数组的方法指向我们自己写的原型对象,从而实现对数组的数据监听对data的对象新增的属性也不会触发视图更新,需要用this.set方法 在vue2中,直接修改数组的下标值不会触发视图更新,vue2是通过对数组的七大方法进行原型链的拦截,重新写了一个原型对象,让数组的方法指向我们自己写的原型对象,从而实现对数组的数据监听 对data的对象新增的属性也不会触发视图更新,需要用this.set方法对后期新增的属性手动的进行数据劫持

8.computed和watch什么区别? 答: computed是计算属性,带有缓存功能(标志位判断当前的数据是否已经计算过),当依赖的数据发生变化时会重新计算,派发通知compoted-watcher重新计算,渲染页面 watch为需要观察的数据创建并收集user-watcher,当数据改变时通知到user-watcher将新值和旧值传递给用户自定义的回调函数 当模板中的某个值需要一个或多个数据计算得到,就可以使用计算属性,还有计算属性的函数不接受参数;监听属性主要是监听某个值发生以后,对新值去做的逻辑处理

  • 计算属性如何与属性(另一个计算属性)建立依赖关系?属性发生变化又是怎么通知计算属性重新计算?(computed) 建立依赖:在initComputed的时候会将为每个计算属性生成对应的观察者computed-watcher,当页面读取计算属性时,会触发getter函数,getter函数会读取它所依赖的数据,读取这些响应式数据又会触发它们的getter方法,那么就会将这个computed-watcher以及页面更新的render-watcher都添加到data的依赖收集器中; 派发通知:当依赖的数据发生改变时,会触发数据对应的依赖管理器中的观察者,从而会对计算属性进行重新计算

  • watch:在initdata之后执行initwatch,将watch里监听的数据创建一个watcher实例,立马执行get方法获取value,这个时候就能执行getter收集data属性中对watch的依赖,如果此时有immediate属性会立马执行watch中的回调函数,当监听的数据发生变化时,会触发这个user-watcher实现watch回调函数的执行

  1. React与Vue之间的区别相同点? 答: 相同点:

  2. 都用了虚拟dom

  3. 都是响应式数据和组件化的思想

  4. 有各自的全家桶,路由和状态管理库 区别:

  5. vue实现了数据的双向绑定,而React是单向绑定,数据的变化只能由通过setState对页面内做更改,vue可以通过v-model实现view和model之间的双向绑定 (数据流指的是组件之间的数据流动,绑定指的是view层跟model层之间的数据映射关系)

  6. react是基于jsx,vue基于template模板

  7. vue是单向数据流但是也能双向绑定,view的变化能实时让model也发生变化,而model的变化也能实时更新到view。 vue采用数据劫持 + 发布-订阅模式,vue在创建实例时,会将数据配置在实例当中,通过Object.definedProperty对数据进行挟持,添加getter与setter方法,当获取数据的时候会触发getter方法,并且将对应的watcher监听器添加到dep收集依赖管理器中,当设置数据会触发setter方法,从而进一步触发该数据的依赖管理器中所有的watcher监听器的回调函数,从而实现更新视图;

  • react和vue的相同点: ①都是异步更新数据:react与vue都是异步更新数据,当调用setState更新state或者vue中修改data,都不是立刻生效,这两个框架都是会加入到一个异步的任务队列,等到nextTick,可能是本次事件循环的结尾或者是下一个事件循环更新。react中的话用的是setState的第二个回调函数,vue中用的是nextTick ②都有diff算法:

  • react和vue区别: ①vue template加上指令式命令,通过预编译生成一颗ast树;react用jsx一种函数式编程,通过React.createElement进行编译 ②vue能实现双向绑定,这个是基于表单元素来说的,只是一种props中的value单向绑定+监听onchange或oninput事件的语法糖,但是其数据的流向本质跟react一样都是单向数据流,这里的单向数据流是针对父组件向子组件传递值,其数据流动核心是很透明清晰的。 ③更新视图策略不一样,vue是对数据进行拦截代理,对于数据的变动采用依赖追踪,敏感准确,diff找出对应的差异部分进行patch更新;对于react来说,采取的是一种粗暴手段,开发者需要手动调用setState触发局部的重新变化,这样会导致很多组件无用的diff,为了性能优化,提供了shouldComponentUpdate生命周期来避免不必要的渲染。 ④预编译阶段,vue在整个parse的过程中利用正则表达式顺序编译模板,当解析到开始标签,闭合标签,文本的时候都会分别执行对应的回调函数,来达到构造AST树的目的,在vue中,对某些静态的节点会被打上static标识,表明是一个不需要重新渲染更新的节点,实现了预编译的优化;但是对于react来说,调用React.createElement来实现局部的重新渲染,所以没办法实现像vue这样的动静分析。

  1. 对于虚拟dom的理解? 答:虚拟dom是一个描述真实dom的js对象,包含tag,children,text等属性。引入虚拟dom是为了能尽可能少去操作dom,频繁更新dom会造成浏览器的重绘和回流,因此在数据发生变更时能一次性将差异更新到dom上,提高性能。 element.js -> 生成js对象表示真实dom节点 diff.js -> 对新旧两颗虚拟dom树做比较,将差异push到patches对象上 patch.js ->对所有差异反映到真实的dom树上

  2. Vue的初始化过程? 答:调用new Vue()创建一个vue实例化对象 -> 执行init方法,初始化事件中心,初始化渲染,初始化生命周期 -> beforeCreate周期函数 -> 执行initState方法,初始化data,props,computed,watch -> create周期函数 -> 调用mount方法对Vue实例进行挂载(挂载的核心:模板编译,渲染,收集更新)>执行compiletemplate模板编译成renderfunction>调用mount方法对Vue实例进行挂载(挂载的核心:模板编译,渲染,收集更新) -> 执行compile对template模板编译成render function -> 调用mount的mountComponent方法 -> beforeMount周期函数 -> 实例化一个render-watcher监听器,在回调函数中执行updateComponent(调用render方法将render function渲染生成虚拟dom,将他作为参数传给vm.update对两颗虚拟dom树做diff算法找出差异,调用patch将差异部分去更新对应dom) -> mounted周期函数

new Vue() -> 调用Vue.prototype._init(),执行initLifecycle(确认组件的父子关系,挂载parent,parent,children),执行initEvents(处理自定义事件传递给子组件,处理on,on,emit),执行initRender(将render函数转换成Vnode)-> beforeCreated钩子函数 -> initInjection -> initState(初始化data,props,methods,computed,watch) -> initProvide(初始化父组件提供的provide依赖) -> created -> 执行mountComponent对element进行挂载 -> beforeMounte钩子函数 -> 执行updateComponent(执行vm._update(vm._render()))生成VNODE并传给update调用patch生成真实的dom -> 执行mounted钩子函数

  1. Vue的响应式过程? 答:在init的时候对Vue中的data数据实现数据劫持能力,用Object.defineProperty的方法重新改写data数据,添加访问器属性get和set方法,这是在vue2的处理,vue3中使用proxy来优化这种响应式的原理。在初始化过程中,当render function被渲染的时候就会读取Vue中的data,此时会触发getter函数进行依赖收集,也就是将对应的观察者render-watcher或者是其他类的user-watcher等加入到当前数据自身的一个dep收集器上,这样就达到了依赖收集的目的;当数据发生变化或者视图导致的数据发生变化,会触发数据的set方法,在set方法中会去调用初始化时所依赖收集的dep中所有watcher的update方法,通知需要重新渲染视图。

  2. v-model双向绑定原理? 答:v-model机制:v-model会把它所关联的响应式数据动态的绑定到表单元素的value属性上,然后监听表单元素的input事件/change事件,当v-model绑定的响应数据发生变化时,表单元素的value值也会同步变化,当表单元素接受用户的输入,触发input事件,从而将input的回调逻辑会把表单的value值同步赋值给v-model绑定的响应式数据。 在父子组件中,利用props的value属性和input事件,可以实现这种双向绑定机制

  3. Vue的数据为什么频繁变化但只更新一次? 答:Vue是异步执行Dom更新,只要观察到数据变化,会触发set方法然后依赖管理器通知watcher,将回调函数push到vue自定义的一个任务队列当中,对于同一个id的watcher,vue不会重复push,在下一次的事件循环或者是当前事件的尾部执行微任务阶段去执行这些回调函数,所以只有当所有数据变化完成之后,才会去统一进行视图更新。

  4. template渲染原理? 答:过程:

  5. 模板解析成AST树 var ast = parse(template.trim(), options),用parse函数生成ast树;processAttrs函数处理指令和html标签属性 解析器(parser):通过正则匹配模板,遇到开始标签,闭合标签,文本的时候都会执行对应的回调函数,将模板字符串转换成AST树,通过截取字符串和截取之后对字符串做解析 原理:一小段一小段的取截取字符串,然后维护一个stack用来保存dom,每截取到一段标签的开始就push到stack中,当截取到尾标签再一个个pop出来,最后解析出了一个完成的AST树(带有tag,children,text等属性)

  6. 优化AST树 优化器(optimizer):找出静态节点并打上标记,静态节点指的是不需要发生变化的dom节点(静态节点的好处:每次重新渲染的时候不需要为静态节点创建新节点;在diff算法中可以被直接跳过不用做对比)。递归AST树,然后将静态节点和静态根节点打上标记。 原理:用递归的方式将所有节点打上标记,表明是否是一个静态节点,然后再次递归遍历标记出静态根节点

如何判断静态节点: 不能使带变量的动态文本节点;不能带有if,for属性;不能是组件;如果子节点都是静态节点的

  1. 将AST树生成render函数代码字符串 代码生成器generate(code generator) 原理:通过递归拼一个函数执行代码的字符串,递归过程根据不同的节点类型调用不同的生成方法,如果是元素节点,会调用createElement方法,如果有children再递归children,最后拼出一个完整的render function代码

  2. diff算法? 答:先对新旧节点判断是不是相同节点,如果不是的话就直接销毁旧节点,渲染新节点,说明diff算法是在同级做比较的;如果是同个节点就去判断两者的子节点是否一致,这里会有多种情况,

  3. 旧节点没有子节点,新节点有子节点 -> 直接addVnodes添加新子节点

  4. 旧节点有子节点,新节点没有子节点 -> 直接removeVnodes移除子节点

  5. 新节点是文本节点 -> 直接替换掉旧节点

  6. (重要的一种)两者都存在子节点 -> 执行updateChildren,先定义四个变量,分别指向新旧节点的首尾处,对这四个指针进行两两配对比较是不是同一个节点,如果有匹配到的就直接复用,如果没有就查找所有旧节点的key,看有没有可以复用的节点,最后当新旧指针有其中两端相遇了,则停止比较,然后根据情况删除和添加节点 juejin.cn/post/684490…

  7. keep-alive? keep-alive是一个抽象组件,自身不会渲染一个dom元素,也不会出现在附件链中,使用keep-alive包裹的组件,会缓存不活动的组件实例,而不是销毁它们。

为什么keep-alive不会渲染成一个真正的DOM节点? 因为vue在初始化生命周期的时候,为组件实例建立父子关系会根据abstract属性决定是否忽略某个组件,在keep-alive中,设置了abstract: true,那vue就会跳过该组件的实例。

  1. Vue能做什么性能优化? ①key保证唯一性,因为key是可以用来判断该节点是不是可以被复用的唯一标识; ②组件懒加载 ③合理使用v-if/v-show:v-if只有当条件成立时才会去渲染组件,v-show无论条件是否成立都会渲染,只是做简单的css的display属性切换;所以对于频繁切换条件的可以用v-show,不需要频繁切换条件的用v-if; ④合理使用computed/watch:computed是计算属性,值有缓存作用,只有当它所依赖的数据发生变化才会去重新计算computed值,watch是观察作用,当观察的数据发生变化会执行异步回调函数;所以当我们需要进行数值计算依赖其他数据时,应该使用computed,可以利用缓存作用,避免每次获取值重新计算,当数据变化需要发生复杂的操作时,使用watch ⑤避免在v-for中使用v-if:v-for比v-if的渲染级别高,如果只需要渲染一小部分的内容,但是每一次都需要去遍历整个数组去判断是否满足条件,这样会影响速度,所以可以先把数组通过computed计算出来再去做v-for渲染 ⑥数据不会更新的组件用Object.freeze方法冻结起来:对于纯粹数据展示的组件,数据不会有任何变化,可以通过Object.freeze方法冻结对象,减少vue内部Object.defineProperty的数据劫持时间 ⑦事件的销毁:vue组件销毁时,会自动清理它与其他实例的链接,解绑它的全部指令及事件监听器,但是仅限于组件本身的事件,如果js内使用addEventListener等方式是不会自动销毁的,需要在组件销毁时beforeDestroy移除事件的监听,避免内存泄漏 ⑧图片资源懒加载,用vue-lazyload:给父元素(overflow:scroll/auto)绑定监听事件,用intersectionObserver判断图片的可见性 ⑨路由懒加载:vue是单页面应用,会有很多的路由引入,所以当进入首页时,加载的资源过多会出现白屏情况,不利于用户体验,所以当路由被访问的时间才加载对应的组件,这样就会大大提高首屏显示速度,但是其他页面的速度就会降下来 juejin.cn/post/684490…

  2. Vue的单向数据流? vue是单向数据流,但是却可以实现双向绑定,v-model只是一个语法糖,是基于value和input/change事件来实现的,对于input元素上的v-model,input元素上本身自带有onchange和oninput事件,将value默认作为元素的属性,然后把input事件作为传递value的触发事件; 而在父子组件之间也可以用v-model来实现双向绑定,其本质也是通过子组件中props的value属性和input方法作为组件的绑定事件名 => <input :value="price" @input="price = $event.target.value" /> 对于checkbox,radio类型的input,只会触发onChange事件。 vue是单向数据流,只能由父组件的数据传递到子组件,子组件无权修改传递给它的数据,这样做是为了组件的更好解耦,因为会有多个子组件依赖父组件的某个数据,假如子组件可以修改父组件数据,那一个子组件变化会引发所有依赖这个数据的子组件内容,所以vue不推荐子组件修改父组件的数据,单向数据流能让整个数据流动变得更加的透明化,数据从哪来就在哪里改,直接修改props会抛出错误

  3. vue的通信方式? ①props + emitEventBusvuexemit ②EventBus ③vuex ④parent + $children

  4. vue-loader的原理? webpack中的一个loader,解析和转换.vue文件,提取其中的逻辑代码script,样式代码style,以及template模板,将vue文件变异成浏览器能识别的loader

  5. vue-router的原理? 将组件components映射到路由routes上,然后告诉vue-router在哪里渲染他们。 ①router-link组件来做导航,通过传入to属性指定链接(组件),router-link会被渲染成一个a标签 ②router-view路由匹配到的组件将渲染在这里 ③vue.use(route)

  6. key的作用? vue和react都是通过diff算法来对比新旧虚拟节点,从而更新节点,在vue的diff算法中,是通过交叉对比的方式,新头新尾旧头旧尾两两对比,没有找到相同节点就会去根据key值生成一个map映射表,从而找到可以复用的旧子节点,如果没有key,那么就会采用遍历查找的方式去找旧节点,map映射比遍历查找并且还要去对比两个节点是否相同,要快得多

  7. vuex的设计思想? 设计思想:把组件之间需要共享的状态抽取出来,遵循特定的约定,统一来管理,让状态的变化变得可预测 store:每一个vuex里面有一个全局的store,包含着应用中的状态state; 同步变更:view -》 commmit mutation -》 state变化 -》 view变化 异步变更:view -》 dispatch action -》 commit mutation -》 state变化 -》 view变化 异步变更:view去dispatch某个事件来触发某个Action,Action里面不管执行多少异步操作,之后都通过store.commit来触发mutation,从而mutation改变state,state发生改变根据vue的响应式机制,从而改变了视图

State:定义了应用状态的数据结构,可以在这里设置默认的初始状态。 Getter:允许组件从 Store 中获取数据,mapGetters 辅助函数仅仅是将 store 中的 getter 映射到局部计算属性。 Mutation:是唯一更改 store 中状态的方法,且必须是同步函数。 Action:用于提交 mutation,而不是直接变更状态,可以包含任意异步操作。 Module:允许将单一的 Store 拆分为多个 store 且同时保存在单一的状态树中。

总的思想:让view通过某种方式触发Store的事件或方法,Store的事件或方法对state进行修改或返回一个新的state,state改变之后,根据vue的响应式机制,view也会跟着发生变化 store:存放state数据,store中有一堆action,action用来改变state数据,不对state直接修改,而是通过action来改变,这样数据改变就可追踪了。

  1. 对比一下react和vue? ①template与jsx:react中的html是写在js中的,而vue是保留template,style,script三者分离的形式。 ②组件传值:react中通过this.props的方法 ③单向数据流:react是单向数据流,数据从哪里来就要从哪里改,当然也可以通过onchange+setState的方法实现双向数据流,而vue中有v-model这样的语法糖帮我们实现了双向的数据流,但是其实它的核心思想也是单向数据流 ④

  2. 性能优化: ①路由懒加载:由于vue是单页面应用,所以在首屏加载的时候会将所有的路由资源都一次性加载,这样就会导致首屏时间过长导致用户体验不好,可以通过路由懒加载的方式,当访问某个路由就加载当前路由的组件,这样就能大大减少资源浪费。 ②第三方库组件的按需加载:对于element-ui,moments,echarts这些第三方库,真正用到的只有一小部分的组件,如果全部引入就会导致打包后的文件体积过大,加载时间也会增加,所以可以通过按需加载组件的方式,用babel-plugin-equire,babel-plugin-component插件实现,moments库可以通过配置plugins的相关插件tree-shaking掉不需要的内容 ③用splitchunk提取公共代码

  3. vue组件通讯 ①props和emitemit ②refs ③eventBus ④vuex

juejin.cn/post/696122…