Vue 面试经

181 阅读7分钟

Vue

一个渐进式框架,主张最少、轻量级。具有angular双向绑定、react组件化等特点。国人开发,容易上手。

<keep-alive>组件

vue内置的一个组件,保留了组件化状态。避免重新渲染,即实现组件缓存。
    a、一般结合路由和动态组件一起使用。
    b、提供include和exclude属性,前者优先级低于后者。
    c、提供activated(keep-alive缓存的组件激活)  deactivated(keep-alive缓存的组件停用时调用)钩子函数

生命周期

简述:开始创建vue实例->初始化数据->编译模板->挂载DOM->渲染更新->渲染卸载

钩子函数

a、beforeCreate(创建前) 实例初始化之后,数据观测和初始化事件之前调用。此时data、watcher、methods都没有
b、created(创建后) 实例创建完之后调用。此时data、watcher、events、methods出现了。可以调用后台接口获取数据,初始化data值。
c、beforeMount(载入前)在挂载之前被调用,相关的render函数首次被调用。此时实例已经完成:编译模板,将data里面的数据和模板生成html。注意html并没有挂载到页面上
d、mounted(载入后)el被vm.$el替换,并挂载到实例之后调用。具体过程:用载入前编译好的dom替换el属性指定的dom对象。完成模板中dom渲染到真实页面。此钩子函数可进行ajax交互
e、beforeUpdate(更新前)在数据更新之前调用,发生在虚拟dom和打补丁之前。可以在该钩子函数中进一步地更改状态
f、updated(更新后)由于数据更改导致的虚拟 DOM 重新渲染和打补丁,在这之后会调用该钩子。此时可以执行依赖于dom的操作,然而应该避免更改状态,因为可能会导致更新无限循环。
g、beforeDestroy(销毁前),在实例销毁之前调用。实例仍然完全可用。
h、destroyed(销毁后),在实例销毁之后调用。调用后,所有的事件监听器会被移除,所有的子实例也会被销毁。该钩子在服务器端渲染期间不被调用。

computed

计算属性,依赖于其他属性。eg:购物车、商品结算

watch

更多是观察,类似于数据的监听回调。eg:执行异步,开销较大时

v-model

表单双向绑定,本质是一个语法糖,背后做了v-bind与v-on

class、style

都可以通过对象或者数组语法绑定:v-bind:class={‘active: isActive ...

组件通信

1、父子组件通信 props/$emit
2、访问父子实例 $parent/$children
3、父子、隔代、兄弟 EventBus($emit/$on)通过一个空的vue实例做为中央事件总线,来触发和监听事件从而实现 父子、隔代、兄弟通信
4、vuex状态管理实现通信

vuex状态管理模式

核心是store仓库,基本上就是容器,包含应用中状态state,是响应式状态存储。改变store中的state,需要显示提交mutation。
1、state基本数据存放
2、getters读取基本数据
3、mutations同步更改数据方法
4、actions像一个装饰器包裹nutations可异步
5、modules模块化vuex

MVVM(model->veivew->viewModel)

促进前后端分离,核心就viewModel就像一个中转站,负责转换model中的数据,变的方便管理和运用。向上与view层进行双向绑定,向下与model层通过接口请求数据交互,起呈上启下作用

双向绑定原理 主要采用订阅发布者模式实现

1、监听器obsever,利用object.defineProperty()
2、解析器complie
3、订阅者watcher
4、订阅器dep

vue-Router

主要是通过跳转和取消的方式实现导航守卫,以下三种方式可以植入路由导航
1、全局,前置守卫router.beforeEach, 后置守卫afterEach
2、单个路由独享beforeEnter
3、组件级的
    a、beforeRouterEnter
    b、beforeRouterupdate
    c、beforeRouterLeave
守卫方法接受三个参数(to,from,next)进入、离开、下一个
模式包括hash(#)、history历史记录模式,支持HTML5 historyAPI,包括history.pushState()、history.replaceState()

虚拟DOM

优点:保证性能、跨平台、无需手动操作dom
缺点:无法进行极致优化
原理:a、用js模拟真实dom,对真实dom进行抽象
      b、diff算法比较两颗虚拟dom的差异
      c、patch算法将两颗虚拟dom的差异应用到真正DOM树上

Vue中key的作用

是Vnode的唯一标识,通过key、diff操作计算更准确更快捷

数组赋值bug

直接给数组赋值不能检测到变化,利用vue.set/vue.$set/vue.items.splice()

为何vue采用异步更新

为了性能考虑,vue是组件级别的,每次数据更新都会对当前组件进行重新渲染,所以vue采用数据更新后,再异步更新试图

nextTick原理

nextTick主要使用了宏任务和微任务,定义了一个异步方法,多次调用nextTick会将方法存入队列中,通过异步方法清空当前队列

compute特点

method方法如果用到模板上每一次变化,就会重新渲染。所以method方法开销比较大。但computed是一个watcher具备缓存的,只有当依赖属性发生变化的时,才会更新视图。而watch属性是不具备缓存的,类似于数据监听回调,执行异步很耗性能

wacth中的deep是如何实现的?

如果当前监控的是数组类型,会对对象中的每一项进行求值,此时会将当前watch存入到对应属性的依赖中,这样数组中对象发生变化时也会通知数据更新

ajax放在哪个生命周期?

1、created时,视图中的真实DOM还没有渲染出来,无法操作相关元素
2、mounted中,此时DOM已经渲染出来了,可以操作元素
一般情况下放到mounted中,保证逻辑的统一性,因为生命周期时同步执行的,而ajax是异步执行的。
服务端不支持mounted方法(ssr),如果服务端渲染放到created中

v-for v-if不能连用

v-for比v-if优先级高一些,如果连用的话,会把v-if每一个元素都添加一下,会造成性能影响

Vnode

Vnode来描述一个DOM结构,即虚拟节点就是用一个对象(Vnode)来描述真实dom元素

data为什么是一个函数

同一组件被多次复用,就会创建多个实例,而这些实例用的是同一构造函数。如果data是一个对象的话,那么组件共享了同一对象。为了保证组件数据独立性,要求每个组件必须通过data函数返回一个对象作为组件状态

vue事件绑定原理

1、分为原生事件绑定.native eg:@click.native
2、组件事件绑定采用@on方法

vue相同逻辑抽离?

vue.mixin用法给组件每个生命周期函数都混入一些公共逻辑

为什么要使用异步组件?

如果组件功能多,打包出结果会变大,可以采用异步方式加载组件,依赖inport语法实现文件分割加载

Vue模板编译原理

代码层面-> 通过with语法,再包装成一个new Function
大概是将template转化成render函数,首先是变成ast抽象语法树,再经过正则匹配变成一个虚拟dom,再通过diff算法,将虚拟dom挂载到真实dom上

Vue 编码优化

1、不要将所有的数据都放在data中,data中的数据都会增加getter和setter,会收集对应的watcher,增加性能。eg:比如静态数据可以放到computed中
2、v-for时给每项元素添加事件时需要事件代理
3、spa需要采用keep-alive缓存组件
4、拆分组件,提高复用性,增加代码的可维护性,减少不必要的渲染
5、key保证唯一性(默认vue采用就地复用策略)
6、v-if值为false时,内部指令不会执行,具有阻断功能。多数情况下可以使用v-if替代v-show
7、当数据较大了时,在data中赋值时,会增加getter、setter等,可以使用ES5中冻结数据object.freeze
8、合理使用路由,懒加载、异步组件

Vue加载优化

1、第三方模块按需导入(babel-plugin-component)
2、滚动到可视区域动态加载(用vue-virtual-scroll-list)默认只渲染三屏,上中下,其他的用空div撑起来
3、图片懒加载

Vue加载优化

1、seo优化--> 服务端渲染ssr

vue3.0改进哪些

1、vue3.0采用ts编写
2、响应式原理由defineProperty为proxy
3、vDom对比算法更新,只更新了Vdom绑定动态数据的部分

SPA

优点:体验好、避免了不必要的跳转和渲染、服务器压力小、前后职责分离,架构清晰
缺点:初次加载耗时多,前后退路由管理,seo难度大

webpack

一个前端模块化方案,更侧重模块打包,可以把开发中所有的资源看成模块,通过loader(加载器)和插件(plugins)对资源进行处理,打包成符合生产环境部署的前端资。而gulp强调的是前端开发的工作流程,定义执行顺序构建项目的整个前端开发流程