常考前端Vue篇

128 阅读14分钟

Vue

双向绑定原理

vue2.:vue.js 则是采用数据劫持结合发布者-订阅者模式的方式,通过Object.defineProperty()来劫持各个属性的setter,getter,

ue 3.0与Vue 2.0的区别仅是数据劫持的方式由Object.defineProperty更改为Proxy代理,其他代码不变。

资源请求一般在哪个生命周期

推荐在 created 钩子函数中调用异步请求,因为在 created 钩子函数中调用异步请求能更快获取到服务端数据,减少页面loading 时间;

还有哪些生命周期可以请求资源

可以在钩子函数 created、beforeMount、mounted 中进行调用,因为在这三个钩子函数中,data 已经创建,可以将服务端端返回的数据进行赋值。

Vuex中的几种状态

vuex的流程

页面通过mapAction异步提交事件到action。action通过commit把对应参数同步提交到mutation。mutation会修改state中对于的值。
最后通过getter把对应值跑出去,在页面的计算属性中,通过mapGetter来动态获取state中的值

vuex有哪几种状态和属性

有五种,分别是State , Getter , Mutation , Action , Module (就是mapAction)

vuex的State特性是?

stae就是存放数据的地方,类似一个仓库 , 特性就是当mutation修改了state的数据的时候,他会动态的去修改所有的调用这个变量的所有组件里面的值( 若是store中的数据发生改变,依赖这个数据的组件也会发生更新 )

vuex的Getter特性是?

getter用来获取数据,mapgetter经常在计算属性中被使用

vuex的Mutation特性是?

Action 类似于 mutation,不同在于:

  • Action 提交的是 mutation,而不是直接变更状态。

  • Action 可以包含任意异步操作

vuex的优势

1 状态管理工具 核心是响应式的做到数据管理, 一个页面发生数据变化。动态的改变对应的页面

MVVM 模式的优缺点,与 MVC 的区别

(1).什么是MVVM

MVVM最早由微软提出来,它借鉴了桌面应用程序的MVC思想,在前端页面中,把Model用纯JavaScript对象表示,View负责显示,两者做到了最大限度的分离,把Model和View关联起来的就是ViewModel。​ViewModel负责把Model的数据同步到View显示出来,还负责把View的修改同步回Model​View 和 Model 之间的同步工作完全是自动的,无需人为干涉(由viewModel完成)​因此开发者只需关注业务逻辑,不需要手动操作DOM, 不需要关注数据状态的同步问题,复杂的数据状态维护完全由 MVVM 来统一管理。

(2).MVVM模式的优点:

1、低耦合:MVVM模式中,数据是独立于UI的,ViewModel只负责处理和提供数据,UI想怎么处理数据都由UI自己决定,ViewModel不涉及任何和UI相关的事,即使控件改变(input换成p),ViewModel几乎不需要更改任何代码,专注自己的数据处理就可以了​2.自动同步数据:ViewModel通过双向数据绑定把View层和Model层连接了起来,View和Model这两者可以自动同步。程序员不需要手动操作DOM, 不需要关注数据状态的同步问题,MVVM 统一管理了复杂的数据状态维护​3、可重用性:你可以把一些视图逻辑放在一个ViewModel里面,让很多view重用这段视图逻辑。​4、独立开发:开发人员可以专注于业务逻辑和数据的开发(ViewModel),设计人员可以专注于页面设计。​5、可测试:ViewModel里面是数据和业务逻辑,View中关注的是UI,这样的做测试是很方便的,完全没有彼此的依赖,不管是UI的单元测试还是业务逻辑的单元测试,都是低耦合的

(3).MVVM 和 MVC 的区别:

mvc 和 mvvm 其实区别并不大。都是一种设计思想,主要区别如下:1.mvc 中 Controller演变成 mvvm 中的 viewModel2.mvvm 通过数据来驱动视图层的显示而不是节点操作。3.mvc中Model和View是可以直接打交道的,造成Model层和View层之间的耦合度高。而mvvm中Model和View不直接交互,而是通过中间桥梁ViewModel来同步4.mvvm主要解决了:mvc中大量的DOM 操作使页面渲染性能降低,加载速度变慢,影响用户体验。

一般在哪个生命周期里请求接口

接口请求一般放在mounted中,但需要注意的是服务端渲染时不支持mounted,需要放到created

Vue 的组件通信

参考我另一篇文章,所有组件之间的通信

juejin.cn/post/688403…

Vue 中是如何检测数组的变化

vue中我们对数组进行push,splice,shift的一些操作时候也会触发render-watcher。这是因为vue中对这些数组的方法进行了一些扩展,使其能够进行数据的响应式,

vue3:proxy可以自动做到

Vue 组件中的data为什么要写成函数形式

Vue 的组件都是可复用的,一个组件创建好后,可以在多个地方复用,而不管复用多少次,组件内的data都应该是相互隔离,互不影响的,所以组件每复用一次,data就应该复用一次,每一处复用组件的data改变应该对其他复用组件的数据不影响。

为了实现这样的效果,data就不能是单纯的对象,而是以一个函数返回值的形式,所以每个组件实例可以维护独立的数据拷贝,不会相互影响。

nextTick 是做什么用的,其原理是什么

Vue 实现响应式并不是数据发生变化之后 DOM 立即变化,而是按一定的策略进行 DOM 的更新。应用场景:需要在试图更新之后,基于新的视图进行操作

Vue 的模板编译原理

参考:www.jianshu.com/p/77717a3bf…

* 第一步将模版字符串转换成element ASTs(解析器)* 第二步是对AST进行静态节点标记,主要用来做虚拟DOM的渲染优化(优化器)* 第三步是使用element ASTs生成render函数代码字符串(代码生成器)

computed 与 watch 的差异

www.cnblogs.com/jiajialove/…

计算属性computed :

1\. 支持缓存,只有依赖数据发生改变,才会重新进行计算
2\. 不支持异步,当computed内有异步操作时无效,无法监听数据的变化
3.computed 属性值会默认走缓存,计算属性是基于它们的响应式依赖进行缓存的,也就是基于data中声明过或者父组件传递的props中的数据通过计算得到的值
4\. 如果一个属性是由其他属性计算而来的,这个属性依赖其他属性,是一个多对一或者一对一,一般用computed
5.如果computed属性属性值是函数,那么默认会走get方法;函数的返回值就是属性的属性值;在computed中的,属性都有一个get和一个set方法,当数据变化时,调用set方法。
![](https://img2018.cnblogs.com/blog/1402448/201908/1402448-20190809154932198-1444047098.png)

侦听属性watch:

1\. 不支持缓存,数据变,直接会触发相应的操作;
2.watch支持异步;
3.监听的函数接收两个参数,第一个参数是最新的值;第二个参数是输入之前的值;
4\. 当一个属性发生变化时,需要执行对应的操作;一对多;
5\. 监听数据必须是data中声明过或者父组件传递过来的props中的数据,当数据变化时,触发其他操作,函数有两个参数,
  immediate:组件加载立即触发回调函数执行,
  deep: 深度监听,为了发现**对象内部值**的变化,复杂类型的数据时使用,例如数组中的对象内容的改变,注意监听数组的变动不需要这么做。注意:deep无法监听到数组的变动和对象的新增,参考vue数组变异,只有以响应式的方式触发才会被监听到。
![](https://img2018.cnblogs.com/blog/1402448/201908/1402448-20190809160441362-1201017336.png)

监听的对象也可以写成字符串的形式

当需要在数据变化时执行异步或开销较大的操作时,这个方式是最有用的。这是和computed最大的区别,请勿滥用。嗯,就酱~

vue-router 中的导航钩子

vue-router 的导航钩子,主要用来作用是拦截导航,让他完成跳转或取消。

有三种方式可以植入路由导航过程中:

  1. 全局的

  2. 单个路由独享的

  3. 组件级的

1. 全局导航钩子:

全局导航钩子主要有两种钩子:前置守卫、后置钩子,

注册一个全局前置守卫:

const router = new VueRouter({ ... });
router.beforeEach((to, from, next) => {
    // do someting
});1234

这三个参数 to 、from 、next 分别的作用:

  1. to: Route,代表要进入的目标,它是一个路由对象

  2. from: Route,代表当前正要离开的路由,同样也是一个路由对象

  3. next: Function,这是一个必须需要调用的方法,而具体的执行效果则依赖 next 方法调用的参数

    • next():进入管道中的下一个钩子,如果全部的钩子执行完了,则导航的状态就是 confirmed(确认的)
    • next(false):这代表中断掉当前的导航,即 to 代表的路由对象不会进入,被中断,此时该表 URL 地址会被重置到 from 路由对应的地址
    • next(‘/’) 和 next({path: ‘/’}):在中断掉当前导航的同时,跳转到一个不同的地址
    • next(error):如果传入参数是一个 Error 实例,那么导航被终止的同时会将错误传递给 router.onError() 注册过的回调

注意:next 方法必须要调用,否则钩子函数无法 resolved

对于全局后置钩子:

router.afterEach((to, from) => {
    // do someting
});123

不同于前置守卫,后置钩子并没有 next 函数,也不会改变导航本身

2. 路由独享的钩子

顾名思义,即单个路由独享的导航钩子,它是在路由配置上直接进行定义的:

cont router = new VueRouter({
    routes: [
        {
            path: '/file',
            component: File,
            beforeEnter: (to, from ,next) => {
                // do someting
            }
        }
    ]
});1234567891011

至于他的参数的使用,和全局前置守卫是一样的

3. 组建内的导航钩子

组件内的导航钩子主要有这三种:beforeRouteEnter、beforeRouteUpdate、beforeRouteLeave。他们是直接在路由组件内部直接进行定义的

我们看一下他的具体用法:

const File = {
    template: `<div>This is file</div>`,
    beforeRouteEnter(to, from, next) {
        // do someting
        // 在渲染该组件的对应路由被 confirm 前调用
    },
    beforeRouteUpdate(to, from, next) {
        // do someting
        // 在当前路由改变,但是依然渲染该组件是调用
    },
    beforeRouteLeave(to, from ,next) {
        // do someting
        // 导航离开该组件的对应路由时被调用
    }
}123456789101112131415

需要注意是:

beforeRouteEnter 不能获取组件实例 this,因为当守卫执行前,组件实例被没有被创建出来,剩下两个钩子则可以正常获取组件实例 this

但是并不意味着在 beforeRouteEnter 中无法访问组件实例,我们可以通过给 next 传入一个回调来访问组件实例。在导航被确认是,会执行这个回调,这时就可以访问组件实例了,如:

beforeRouteEnter(to, from, next) {
    next (vm => {
        // 这里通过 vm 来访问组件实例解决了没有 this 的问题
    })
}12345

注意,仅仅是 beforRouteEnter 支持给 next 传递回调,其他两个并不支持。因为归根结底,支持回调是为了解决 this 问题,而其他两个钩子的 this 可以正确访问到组件实例,所有没有必要使用回调

最后是完整的导航解析流程:

  1. 导航被触发
  2. 在失活的组件里调用离开守卫
  3. 调用全局的 beforeEach 守卫
  4. 在重用的组件里调用 beforeRouteUpdate 守卫
  5. 在路由配置里调用 beforEnter
  6. 解析异步路由组件
  7. 在被激活的组件里调用 beforeRouteEnter
  8. 调用全局的 beforeResolve 守卫
  9. 导航被确认
  10. 调用全局的 afterEach 钩子
  11. 触发 DOM 更新
  12. 在创建好的实例调用 beforeRouteEnter 守卫中传给 next 的回调函数

vue-router的两种模式

众所周知,vue-router有两种模式,hash模式和history模式,这里来谈谈两者的区别。

hash模式

hash模式背后的原理是onhashchange事件,可以在window对象上监听这个事件:

上面的代码可以通过改变hash来改变页面字体颜色,虽然没什么用,但是一定程度上说明了原理。

更关键的一点是,因为hash发生变化的url都会被浏览器记录下来,从而你会发现浏览器的前进后退都可以用了,同时点击后退时,页面字体颜色也会发生变化。这样一来,尽管浏览器没有请求服务器,但是页面状态和url一一关联起来,后来人们给它起了一个霸气的名字叫前端路由,成为了单页应用标配。

history路由

随着history api的到来,前端路由开始进化了,前面的hashchange,你只能改变#后面的url片段,而history api则给了前端完全的自由

Vue中 key 值的作用

key 的作用是给予一个节点唯一的身份识别,有相同父元素的子元素必须有独特的 key 。这样它可以前后对比,算出哪些节点是要重复使用或者调整顺序。比如原先的 key 的顺序是 i1,i2,i3 ,之后变成了 i2,i1,i3 这个时候只要i3保持不变,把i2 insertBefore 到i1节点前就行了(以上是举例,vue具体怎么操作的需要去研究源码)。如果是利用数组的 index 来作为 key 则两次对比没有区别,就会出现上面动图里出现的子组件没有更新的情况。

  • v-for遍历时,用id,uuid之类作为key,唯一标识节点加速虚拟DOM渲染
  • 响应式系统没有监听到的数据,用+new Date()生成的时间戳作为key,手动强制触发重新渲染

详解:www.jb51.net/article/173…

Vue中常见的修饰符

.lazy .number .trim

详细:www.cnblogs.com/gitByLegend…

Vue中常用的指令

v-text v-html v-bind v-model v-for和key v-ifv-show

v-show 与 v-if 的区别

  • vue-show本质就是标签display设置为none,控制隐藏
  • vue-if是动态的向DOM树内添加或者删除DOM元素

keep-alive 组件的作用

1.keep-alive的作用以及好处

在做电商有关的项目中,当我们第一次进入列表页需要请求一下数据,当我从列表页进入详情页,详情页不缓存也需要请求下数据,然后返回列表页,这时候我们使用keep-alive来缓存组件,防止二次渲染,这样会大大的节省性能。

2.keep-alive的基本用法

![](https://upload-images.jianshu.io/upload_images/19330661-5096303c5403084e.png?imageMogr2/auto-orient/strip|imageView2/2/w/850/format/webp)

需要缓存的组件内容直接在router中添加:

![](https://upload-images.jianshu.io/upload_images/19330661-adb1951e31ed4ff0.png?imageMogr2/auto-orient/strip|imageView2/2/w/812/format/webp)

3.keep-alive的生命周期

当引入keep-alive的时候,页面第一次进入,钩子的触发顺序created-> mounted-> activated,退出时触发deactivated。当再次进入(前进或者后退)时,只触发activated。

Vue的虚拟dom

模板转换成视图得过程;

详解:www.cnblogs.com/fundebug/p/…

Virtual DOM 是什么?

Virtual DOM 其实就是一棵以 JavaScript 对象( VNode 节点)作为基础的树,用对象属性来描述节点,实际上它只是一层对真实 DOM 的抽象。最终可以通过一系列操作使这棵树映射到真实环境上。

简单来说,可以把Virtual DOM 理解为一个简单的JS对象,并且最少包含标签名( tag)、属性(attrs)和子元素对象( children)三个属性。不同的框架对这三个属性的命名会有点差别。

对于虚拟DOM,咱们来看一个简单的实例,就是下图所示的这个,详细的阐述了模板 → 渲染函数 → 虚拟DOM树 → 真实DOM的一个过程

跨域的几种实现方式

jsonp ,

nginx代理,

CORS

Websocket,

HTML5 推出了一个新的函数 postMessage()

网站的本地缓存

Cookie(或者Cookies

localStorage

是html5的一种新的本地缓存方案,目前用的比较多,一般用来存储ajax返回的数据,加快下次页面打开时的渲染速度。

localStorage核心API:

localStorage.setItem(key, value) 设置记录

localStorage.getItem(key) 获取记录

localStorage.removeItem(key) 删除该域名下单条记录

localStorage.clear() 删除该域名下所有记录

sessionStorage

IndexedDB