Vue.js面试题

目录

1. ★★★ 如何再Vue的单文件组件里的样式定义全局CSS?

在style标签上不加上scoped的属性,默认为全局css样式

2. ★★ vue-router 3.1.0 新增的v-slot属性怎么用?

router-link 通过一个作用域插槽暴露底层的定制能力。
这是一个更高阶的 API,主要面向库作者,但也可以为开发者提供便利,
多数情况用在一个类似 NavLink 这样的自定义组件里。
在使用 v-slot API 时,需要向 router-link 传入一个单独的子元素。
否则 router-link 将会把子元素包裹在一个 span 元素内。

3. ★★★ 如何实现一个路径渲染多个组件?

可以通过命名视图(router-view),它容许同一界面中拥有多个单独命名的视图,
而不是只有一个单独的出口。如果 router-view 没有设置名字,那么默认为 default。
通过设置components即可同时渲染多个组件。

4. ★★★ 如何实现多个路径共享一个组件?

只需将多个路径的component字段的值设置为同一个组件即可。

5. ★★★ 如何监测动态路由的变化

可以通过watch方法来对$route进行监听,
或者通过导航守卫的钩子函数beforeRouteUpdate来监听它的变化。

6. ★★★ 对MVC,MVP,MVVM的理解

mvc 和 mvvm 其实区别并不大。都是一种设计思想。
主要就是 mvc 中 Controller 演变成 mvvm 中的 viewModel。
mvvm 主要解决了 mvc 中大量的 DOM 操作使页面渲染性能降低,加载速度变慢,影响用户体验。
当 Model 频繁发生变化,开发者需要主动更新到 View 。

MVVM 是 Model-View-ViewModel 的缩写。mvvm 是一种设计思想。
1、Model 层代表数据模型,也可以在 Model 中定义数据修改和操作的业务逻辑;
View 代表 UI 组件,它负责将数据模型转化成 UI 展现出来,
ViewModel 是一个同步 View 和 Model 的对象。
2、在 MVVM 架构下,View 和 Model 之间并没有直接的联系,
而是通过 ViewModel 进行交互,Model 和 ViewModel 之间的交互是双向的,
因此 View 数据的变化会同步到 Model 中,而 Model 数据的变化也会立即反应到 View 上。
3、ViewModel 通过双向数据绑定把 View 层和 Model 层连接了起来,
而 View 和 Model 之间的同步工作完全是自动的,无需人为干涉,
因此开发者只需关注业务逻辑,不需要手动操作 DOM, 不需要关注数据状态的同步问题,
复杂的数据状态维护完全由 MVVM 来统一管理。

7. ★★ 说一下 r o o t , root, rootparent,$refs

$ r o o t ,和 root,和 root,和parent都能访问父组件的属性和方法,
区别在于如果存在多级子组件,通过parent 访问得到的是它最近一级的父组件,
通过root 访问得到的是根父组件。
通过在子组件标签定义 ref 属性,在父组件中可以使用$refs 访问子组件实例。

8. ★★★★★ 你知道Vue响应式数据原理吗?Proxy 与 Object.defineProperty 优劣对比?

响应式原理
vue的响应式实现主要是利用了Object.defineProperty的方法里面的setter 与getter方法的观察者模式来实现。在组件初始化时会给每一个data属性注册getter和setter,然后再new 一个自己的Watcher对象,此时watcher会立即调用组件的render函数去生成虚拟DOM。在调用render的时候,就会需要用到data的属性值,此时会触发getter函数,将当前的Watcher函数注册进sub里。当data属性发生改变之后,就会遍历sub里所有的watcher对象,通知它们去重新渲染组件。

proxy的优势
Proxy 可以直接监听对象而非属性,可以直接监听数组的变化;
Proxy 有多达 13 种拦截方法,不限于 apply、ownKeys、deleteProperty、has 等等是 Object.defineProperty 不具备的;
Proxy 返回的是一个新对象,我们可以只操作新的对象达到目的,而 Object.defineProperty 只能遍历对象属性直接修改;

Object.defineProperty 的优势:
兼容性好,支持 IE9,而 Proxy 的存在浏览器兼容性问题,而且无法用 polyfill(垫片)来弥补

9. ★★★★ Composition API 的出现带来哪些新的开发体验,为啥需要这个?

  • 在Compostion API 中时根据逻辑相关组织代码的,提高可读性和可维护性,类似于react的hook写法。
  • 更好的重用逻辑代码,在Options API中通过MIxins重用逻辑代码,容易发生命名冲突且关系不清。
  • 解决在生命周期函数经常包含不相关的逻辑,但又不得不把相关逻辑分离到了几个不同方法中的问题,如在mounted中设置定时器,但需要在destroyed中来清除定时器,将同一功能的代码拆分到不同的位置,造成后期代码维护的困难。

10. ★★★ 什么情况下使用 Vuex

如果应用够简单,最好不要使用 Vuex,一个简单的 store 模式即可,
需要构建一个中大型单页应用时,使用Vuex能更好地在组件外部管理状态

11. ★★★ Vuex可以直接修改state的值吗?

可以直接修改,但是极其不推荐,
state的修改必须在mutation来修改,
否则无法被devtool所监测,无法监测数据的来源,无法保存状态快照,
也就无法实现时间漫游/回滚之类的操作。

12. ★★★★ 为什么Vuex的mutation不能做异步操作

Vuex中所有的状态更新的唯一途径都是mutation,
异步操作通过 Action 来提交 mutation实现,这样使得我们可以方便地跟踪每一个状态的变化,
从而让我们能够实现一些工具帮助我们更好地了解我们的应用。
每个mutation执行完成后都会对应到一个新的状态变更,这样devtools就可以打个快照存下来,
否则无法被devtools所监测。
如果mutation支持异步操作,就没有办法知道状态是何时更新的,
无法很好的进行状态的追踪,给调试带来困难。

13. ★★★ v-model和vuex有冲突吗?

用法上不冲突,但是设计理念不一致。

双向绑定的理念是,双向数据流,数据和视图可以互相改变,用法简单但可维护性差。

vuex 的理念是,单向数据流,用法复杂但是可维护性强。

14. ★★★ 解释单向数据流和双向数据绑定

对于 Vue 来说,组件之间的数据传递具有单向数据流这样的特性称为单向数据流,
单向数据流(Unidirectional data flow)方式使用一个上传数据流和一个下传数据流进行双向数据通信,
两个数据流之间相互独立,单向数据流指只能从一个方向来修改状态。

双向数据绑定即为当数据发生变化的时候,视图也就发生变化,当视图发生变化的时候,数据也会跟着同步变化,两个数据流之间互为影响。

15. ★★ Vue 如何去除url中的#

将路由模式改为history

16. ★★★ $route 和 $router 的区别

$route用来获取路由的信息的,它是路由信息的一个对象,里面包含路由的一些基本信息,
包括name、meta、path、hash、query、params、fullPath、matched、redirectedFrom等。

$router主要是用来操作路由的,它是VueRouter的实例,包含了一些路由的跳转方法,钩子函数等

17. ★★ 对比 jQuery,Vue 有什么不同

jQuery 专注视图层,通过直接操作 DOM 去实现页面的一些逻辑渲染;
Vue 专注于数据层,通过数据的双向绑定,最终表现在 DOM 层面,减少了 DOM 操作。
Vue 使用了组件化思想,使得项目子集职责清晰,提高了开发效率,方便重复利用,便于协同开发

18. ★★★ Vue 中怎么自定义指令

通过directive来自定义指令,自定义指令分为全局指令和局部指令,
自定义指令也有几个的钩子函数,常用的有bind和update,当 bind 和 update 时触发相同行为,
而不关心其它的钩子时可以简写。
一个表达式可以使用多个过滤器。过滤器之间需要用管道符“|”隔开。其执行顺序从左往右。

19. ★★★ Vue 中怎么自定义过滤器

通过filter来定义过滤器,过滤器分为全局和局部过滤器,
过滤器的主体为一个普通的函数,来对数据进行处理,可以传递参数。
当有局部和全局两个名称相同的过滤器时候,会以就近原则进行调用,
局部过滤器优先于全局过滤器被调用。

20. ★★★ Vue 等单页面应用的优缺点

优点
1单页应用的内容的改变不需要重新加载整个页面,web应用更具响应性和更令人着迷。
2、单页应用没有页面之间的切换,就不会出现“白屏现象”,也不会出现假死并有“闪烁”现象
3、单页应用相对服务器压力小,服务器只用出数据就可以,不用管展示逻辑和页面合成,吞吐能力会提高几倍。
4、良好的前后端分离。后端不再负责模板渲染、输出页面工作,后端API通用化,即同一套后端程序代码,不用修改就可以用于Web界面、手机、平板等多种客户端。

缺点
1、首次加载耗时比较多。
2、SEO问题,不利于百度,360等搜索引擎收录。
3、容易造成Css命名冲突。
4、前进、后退、地址栏、书签等,都需要程序进行管理,页面的复杂度很高,需要一定的技能水平和开发成本高。

21. ★★★ Vue-router 使用params与query传参有什么区别

用法上
1:query要用path来引入,params要用name来引入,接收参数都是类似的,分别是this.$ r o u t e . q u e r y . n a m e 和 t h i s . route.query.name和this. route.query.namethis.'$'route.params.name。
展示上
2:query更加类似于我们ajax中get传参,params则类似于post,说的再简单一点,前者在浏览器地址栏中显示参数,后者则不显示
3:params是路由的一部分,必须要有。query是拼接在url后面的参数,没有也没关系。
4:params、query不设置也可以传参,params不设置的时候,刷新页面或者返回参数会丢失

22. ★★★ Vue中 keep-alive 的作用

keep-alive 是 Vue 内置的一个组件,可以使被包含的组件保留状态,或避免重新渲染。
一旦使用keepalive包裹组件,此时mouted,created等钩子函数只会在第一次进入组件时调用,
当再次切换回来时将不会调用。
此时如果我们还想在每次切换时做一些事情,就需要用到另外的周期函数,
actived和deactived,这两个钩子函数只有被keepalive包裹后才会调用。

23. ★★★ Vue如何实现单页面应用

通常的url 地址由以下内容构成:协议名 域名 端口号 路径 参数 哈希值,
当哈希值改变,页面不会发生跳转,单页面应用就是利用了这一点,
给window注册onhashchange事件,当哈希值改变时通过location.hash就能获得相应的哈希值,
然后就能跳到相应的页面。

24. ★★★ 说出至少4种Vue当中的指令和它的用法?

v-if(判断是否隐藏,用来判断元素是否创建)
v-show(元素的显示隐藏,类似css中的display的block和hidden)
v-for(把数据遍历出来)
v-bind(绑定属性)
v-model(实现双向绑定)

25.★★★ Vue-loader解释一下

解析和转换 .vue 文件,提取出其中的逻辑代码 script、样式代码 style、以及 HTML 模版 template,
再分别把它们交给对应的 Loader 去处理。

26.★★★ 用过插槽吗?用的是具名插槽还是匿名插槽

用过,都使用过。
插槽相当于预留了一个位置,可以将我们书写在组件内的内容放入,
写一个插槽就会将组件内的内容替换一次,两次则替换两次。
为了自定义插槽的位置我们可以给插槽取名,它会根据插槽名来插入内容,一一对应。

27.★★★ Vue 路由守卫

vue-router 提供的导航守卫主要用来对路由的跳转进行监控,
控制它的跳转或取消,路由守卫有全局的, 单个路由独享的, 或者组件级的。

导航钩子有3个参数:
1、to:即将要进入的目标路由对象;
2、from:当前导航即将要离开的路由对象;
3、next :调用该方法后,才能进入下一个钩子函数(afterEach)。

28.★★ Vue中如何实现子组件内的css样式名在项目中绝对唯一性

在style标签上加上scoped属性

29.★★★★★ Vue3中的双向数据绑定proxy

Proxy相当于在目标对象之前架设一层“拦截”,外界对该对象的访问,
都必须先通过这层拦截,因此提供了一种机制,
可以对外界的访问进行过滤和改写,
可以这样认为,Proxy是Object.defineProperty的全方位加强版,
它解决了之前defineProperty无法监听到数组变化等缺点。

30.★★★★★ Vue和React中diff算法区别

vue和react的diff算法,都是忽略跨级比较,只做同级比较。
vue diff时调动patch函数,参数是vnode和oldVnode,分别代表新旧节点。

1.vue对比节点。当节点元素相同,但是classname不同,认为是不同类型的元素,删除重建,而react认为是同类型节点,只是修改节点属性。

2.vue的列表对比,采用的是两端到中间比对的方式,而react采用的是从左到右依次对比的方式。当一个集合只是把最后一个节点移到了第一个,react会把前面的节点依次移动,而vue只会把最后一个节点移到第一个。总体上,vue的方式比较高效。

31.★★★ 请你说一下 Vue 中 create 和 mount 的区别

create为组件初始化阶段,在此阶段主要完成数据观测(data observer),属性和方法的运算, watch/event 事件回调。
然而,挂载阶段还没开始,此时还未生成真实的DOM,也就无法获取和操作DOM元素。
而mount主要完成从虚拟DOM到真实DOM的转换挂载,此时html已经渲染出来了,
所以可以直接操作dom节点。

32.★★★★ Object.defineProperty有什么缺点

  • 无法监控到数组下标的变化,导致通过数组下标添加元素,不能实时响应;
  • 只能劫持对象的属性,从而需要对每个对象,每个属性进行遍历,如果,属性值是对象,还需要深度遍历。

33.★★★★ axios是什么?怎么使用?描述使用它实现登录功能的流程?

axios 是请求后台资源的模块。
通过npm install axios -S来安装,在大多数情况下我们需要封装拦截器,
在实现登录的过程中我们一般在请求拦截器中来加入token,
在响应请求器中通过判断后端返回的状态码来对返回的数据进行不同的处理。
如果发送的是跨域请求,需在配置文件中 config/index.js 进行代理配置。

34.★★ v-model是什么?Vue中标签怎么绑定事件?

v-model是一个语法糖,这一个指令可以分为几个指令,
它内部已经帮我们处理整合了。对于普通的文本框来说,
v-model = v-bind:value + @input。
对单选框和复选框来说,v-model = v-bind:checked + @change,
并且它还有一个非常重要的功能,就是解决父子组件之间的通讯问题,
可以提升我们的开发效率。
在vue中通过使用<v-on:事件名 = 函数名>的方式来绑定事件。

35.★★★ 路由懒加载

把不同路由对应的组件分割成不同的代码块,
然后当路由被访问时才加载对应的组件即为路由的懒加载,
可以加快项目的加载速度,提高效率。
通过这种格式来导入组件const foo = () => import(‘./foo.vue’);

36.★★★★ computed和watcher的区别?watch实现原理?watch有几种写法?

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

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

watch工作原理:
watch在一开始初始化的时候,会读取一遍监听的数据的值,此时那个数据就收集到watch的watcher了然后你给watch设置的handler,watch 会放入watcher的更新函数中,当数据改变时,通知watch的watcher进行更新,于是你设置的handler就被调用了。

37. ★★★★ 如果你是leader,做管理系统项目 Vue和React 怎么选择?

评估项目成员的水平,如果成员js基础较好、编码能力较强则选择React,否则Vue。
评估系统的大小,如果想构建生态系统,则选择React,如果要求而快,简单和“能用就行",则选择Vue。
评估系统运行环境,如果你想要一个同时适用于Web端和原生APP的框架,请选择React(RN)。

38.★★★ Vuex的缺点

如果不打算开发大型单页应用,使用 Vuex 可能是繁琐冗余的,
并且state中的值会伴随着浏览器的刷新而初始化,无缓存。

39.★★★★ Vue和React区别

1、Vue 使用的是 web 开发者更熟悉的模板与特性,Vue的API跟传统web开发者熟悉的模板契合度更高,比如Vue的单文件组件是以模板+JavaScript+CSS的组合模式呈现,它跟web现有的HTML、JavaScript、CSS能够更好地配合。React 的特色在于函数式编程的理念和丰富的技术选型,Vue更加注重web开发者的习惯。

2、Vue跟React的最大区别在于数据的reactivity,就是反应式系统上。Vue提供反应式的数据,当数据改动时,界面就会自动更新,而React里面需要调用方法SetState。我把两者分别称为Push-based和Pull-based

40.★★★ Vue路由传参,刷新后还有吗

通过params传参会出现参数丢失的情况,
可以通过query的传参方式或者在路由匹配规则加入占位符即可以解决参数丢失的情况。

41.★★★ Vue深层次嵌套传值方法

利用$attrs 和 $listeners

42.★★★ Vue组件如何引入使用

  1. 定义组件并抛出
  2. import引入,并在component里面定义
  3. 使用组件(注意首字母大写)

43.★★★★ Vue路由实现的底层原理

在Vue中利用数据劫持defineProperty在原型prototype上初始化了一些getter,
分别是router代表当前Router的实例 、 router代表当前Router的实例、router代表当前Router的实例、route 代表当前Router的信息。在install中也全局注册了router-view,router-link,其中的Vue.util.defineReactive, 这是Vue里面观察者劫持数据的方法,
劫持_route,当_route触发setter方法的时候,则会通知到依赖的组件。
接下来在init中,会挂载判断是路由的模式,是history或者是hash,点击行为按钮,
调用hashchange或者popstate的同时更_route,_route的更新会触发route-view的重新渲染。

44.★★★★ 如何封装一个通用组件

通用组件的封装就是对可复用组件的解耦和样式复用,为了解耦一般数据都是通过父组件传递过来,
在子组件中进行数据处理,对于一些较为复杂的数据可能还需要做数据验证,
为了避免高耦合,逻辑最好放在父组件中,通过自定义事件将数据回传,子组件只是一个承载体,
这样既降低耦合,保证子组件中数据和逻辑不会混乱。
如果同一组件需要适应不同需求时,我们需要配合slot来使用,
可以通过具名插槽灵活地解决了不同场景同一组件不同配置的问题。

45.★★ Vue 生命周期通常使用哪些

常用的生命周期有,beforeCreate,created,beforeMount,mounted,beforeUpdate,updated,beforeDestroy,destroyed

46.★★ Vue 深层次的组件怎么和父组件通讯

//使用$attrs和$listeners
Vue.component('C', {
  template: `
    <div>
      <p>我是C组件</p>
      <input 
        type='text' 
        v-model='$attrs.msgc' 
        @input='$emit("getC", $attrs.msgc)' 
      />
    </div>
    `
})

Vue.component('B', {
  /**
    给C组件绑定$attrs属性和$listeners事件,C组件可以直接获取到A组件中传递下来的props(除了B组件中props声明的)
  */
  template: `
    <div>
      <p>我是B组件</p>
      <input 
        type='text' 
        v-model='mymsg1' 
        @input="$emit('getChild', mymsg1)"
      />
      <C v-bind='$attrs' v-on='$listeners'/>
    </div>
  `,
  props: ['msg1'],
  data () {
    return {
      mymsg1: this.msg1
    }
  }
})

Vue.component('A', {
  template: `
    <div id='app'>
      <p>我是A组件</p>
      <B 
        :msg1='msg1' 
        :msgc='msgc' 
        @getChild='getChild'
        @getC='getC'
      />
    </div>
  `,
  data () {
    return {
      msg1: 'A',
      msgc: 'hello c!'
    }
  },
  methods: {
    getChild (val) {
      console.log( val )
    },
    getC (val) {
      console.log( val )
    }
  }
})

const app = new Vue({
  el: '#app',
  template: `
      <A />  
  `
})

47.★★★★★ Vue 响应式原理

1.观察者observer:首先通过观察者对data中的属性使用object.defineproperty劫持数据的getter和setter,通知订阅者,触发他的update方法,对视图进行更新

2.Compile:用来解析模板指令,并替换模板数据,初始化视图,初始化相应的订阅器

3.订阅者Watcher:订阅者接到通知后,调用update方法更新对应的视图

4.订阅器Dep:订阅者可能有多个,因此需要订阅器Dep来专门接收这些订阅者,并统一管理

但在vue3中抛弃了object.defineproperty方法,因为

  • Object.defineproperty无法监测对象属性的添加和删除、数组索引和长度的变更,因此vue重写了数组的push/pop/shift/unshift/splice/sort/reverse方法
  • Object.defineProperty只能劫持对象的属性,因此我们需要对每个对象的每个属性进行遍历,这样很消耗性能

vue3中实现数据双向绑定的原理是数据代理,使用proxy实现。Proxy 可以理解成,在目标对象之前架设一层“拦截”,外界对该对象的访问,都必须先通过这层拦截,因此提供了一种机制,可以对外界的访问进行过滤和改写。

48.★★★★ Vue proxy的原理

主要通过Proxy对对象进行绑定监听处理,通过new Map对对象的属性操作进行处理,将要执行的函数匹配到存到对应的prop上面,通过每次的访问触发get方法,进行存方法的操作,通过修改触发set的方法,此时执行回调监听的函数,这样达到修改数据和视图的

49. ★★★ Vue $forceUpdate的原理

作用
迫使 Vue 实例重新渲染。注意它仅仅影响实例本身和插入插槽内容的子组件,而不是所有子组件。

内部原理

Vue.prototype.$forceUpdate = function () {
    const vm: Component = this
    if (vm._watcher) {
        vm._watcher.update()
    }
}

50.★★★ v-for key

  • key是为Vue中的vnode标记的唯一id,通过这个key,我们的diff操作可以更准确、更快速
  • diff算法的过程中,先会进行新旧节点的首尾交叉对比,当无法匹配的时候会用新节点的key与旧节点进行比对,然后超出差异.

diff程可以概括为:oldCh和newCh各有两个头尾的变量StartIdx和EndIdx,它们的2个变量相互比较,一共有4种比较方式。如果4种比较都没匹配,如果设置了key,就会用key进行比较,在比较的过程中,变量会往中间靠,一旦StartIdx>EndIdx表明oldCh和newCh至少有一个已经遍历完了,就会结束比较,这四种比较方式就是首、尾、旧尾新头、旧头新尾.
准确: 如果不加key,那么vue会选择复用节点(Vue的就地更新策略),导致之前节点的状态被保留下来,会产生一系列的bug. 快速: key的唯一性可以被Map数据结构充分利用,相比于遍历查找的时间复杂度O(n),Map的时间复杂度仅仅为O(1)

51.★★★★ defineProperty在数据劫持后是如何通知数据的更新和视图的更新的

vue的双向绑定是由数据劫持结合发布者-订阅者模式实现的,那么什么是数据劫持?vue是如何进行数据劫持的?说白了就是通过Object.defineProperty()来劫持对象属性的setter和getter操作,在数据变动时做你想要做的事情

我们已经知道实现数据的双向绑定,首先要对数据进行劫持监听,所以我们需要设置一个监听器Observer,用来监听所有属性。如果属性发生变化了,就需要告诉订阅者Watcher看是否需要更新。因为订阅者是有很多个,所以我们需要有一个消息订阅器Dep来专门收集这些订阅者,然后在监听器Observer和订阅者Watcher之间进行统一管理的。接着,我们还需要有一个指令解析器Compile,对每个节点元素进行扫描和解析,将相关指令(如v-model,v-on)对应初始化成一个订阅者Watcher,并替换模板数据或者绑定相应的函数,此时当订阅者Watcher接收到相应属性的变化,就会执行对应的更新函数,从而更新视图

因此接下去我们执行以下3个步骤,实现数据的双向绑定:
1.实现一个监听器Observer,用来劫持并监听所有属性,如果有变动的,就通知订阅者。
2.实现一个订阅者Watcher,每一个Watcher都绑定一个更新函数,watcher可以收到属性的变化通知并执行相应的函数,从而更新视图。
3.实现一个解析器Compile,可以扫描和解析每个节点的相关指令(v-model,v-on等指令),如果节点存在v-model,v-on等指令,则解析器Compile初始化这类节点的模板数据,使之可以显示在视图上,然后初始化相应的订阅者(Watcher)。

52.★★★★ axios谁封装的,怎么封装的

// 使用axios用于对数据的请求
import axios from 'axios'
// 创建axios实例
const instance = axios.create({
  baseURL: baseURL + version,
  timeout: 5000
})

// 创建请求的拦截器
instance.interceptors.request.use(config => {
  config.headers['Authorization'] = localStorage.getItem('token')
  return config
}, error => {
  return Promise.reject(error)
})

// 创建响应的拦截器
instance.interceptors.response.use(response => {
  let res = null

  // 对相应的数据进行过滤
  if (response.status === 200) {
    if (response.data && response.data.err === 0) {
      res = response.data.data
    } else if (response.data.err === -1) {
      return alert('token无效')
    }
  } else {
    return alert('请求失败')
  }

  return res
}, error => {
  return Promise.reject(error)
})

export default instance

53.★★★ 为什么要设置key值,可以用index吗?为什么不能?

vue中列表循环需加:key=“唯一标识” 唯一标识可以是item里面id index等,因为vue组件高度复用增加Key可以标识组件的唯一性,为了更好地区别各个组件 key的作用主要是为了高效的更新虚拟DOM

54.★★★ 怎么修改Vuex中的状态?Vuex中有哪些方法?

  • 通过this.$store.state.属性 的方法来访问状态
  • 通过this.$store.commit(‘mutation中的方法’) 来修改状态

55.★★★ vue-router路由传参的方式

query
// 方法一
<template>
    <router-link
          :to="{
                  path: 'blogDetail',
                  query: { id: item.id, views: item.views }
                }"
          tag="h2"
        >
    </router-link>
</template>

// 方法二
this.$router.push({  
  path: 'blogDetail', 
  query: { 
    id: item.id,
    views: item.views
  }
})

params
<template>
    <router-link
          :to="{
                  name: 'blogDetail',
                  params: { id: item.id, views: item.views }
                }"
          tag="h2"
        >
    </router-link>
</template>

this.$router.push({  
  name: 'blogDetail', 
  params: { 
    id: item.id,
    views: item.views
  }
})

56.★★★ hash history区别

hashhistory
url显示有#,很Low无#,好看
回车刷新可以加载到hash值对应页面一般就是404掉了
url显示支持低版本浏览器和IE浏览器HTML5新推出的API

57.★★★ 用过beforeEach吗?

每次通过vue-router进行页面跳转,都会触发beforeEach这个钩子函数,这个回调函数共有三个参数,to,from,next这三个参数,to表示我要跳转的目标路由对应的参数,from表示来自那个路由,就是操作路由跳转之前的,即将离开的路由对应的参数,next是一个回调函数,一定要调用next方法来resolve这个钩子函数;

58.★★★ Vue中的单项数据流

  • 单向数据流指只能从一个方向来修改状态。
  • 数据从父级组件传递给子组件,只能单向绑定。
  • 子组件内部不能直接修改从父级传递过来的数据。

59.★★★ Vue组件中的Data为什么是函数,根组件却是对象呢?

如果data是一个函数的话,这样每复用一次组件,就会返回一份新的data,类似于给每个组件实例创建一个私有的数据空间,让各个组件实例维护各自的数据。而单纯的写成对象形式,就使得所有组件实例共用了一份data,就会造成一个变了全都会变的结果。
所以说vue组件的data必须是函数。这都是因为js的特性带来的,跟vue本身设计无关。

60.★★★ 你做过哪些Vue的性能优化?

1、首屏加载优化

2、路由懒加载

{      
  path: '/',      
  name: 'home',      
  component: () => import('./views/home/index.vue'),      
  meta: { isShowHead: true }
}

3、开启服务器 Gzip
开启 Gzip 就是一种压缩技术,需要前端提供压缩包,然后在服务器开启压缩,文件在服务器压缩后传给浏览器,浏览器解压后进行再进行解析。首先安装 webpack 提供的compression-webpack-plugin进行压缩,然后在 vue.config.js:

const CompressionWebpackPlugin = require('compression-webpack-plugin')
const productionGzipExtensions = ['js', 'css']......plugins: [      
  new CompressionWebpackPlugin(
    {        
      algorithm: 'gzip',        
      test:     new RegExp('\\.(' + productionGzipExtensions.join('|') +                 ')$'),            
      threshold: 10240,        
      minRatio: 0.8      
       }
)]....

4、启动 CDN 加速
我们继续采用 cdn 的方式来引入一些第三方资源,就可以缓解我们服务器的压力,原理是将我们的压力分给其他服务器点。

5、代码层面优化

  • computed 和 watch 区分使用场景

computed: 是计算属性,依赖其它属性值,并且 computed 的值有缓存,只有它依赖的属性值发生改变,下一次获取 computed 的值时才会重新计算 computed 的值。当我们需要进行数值计算,并且依赖于其它数据时,应该使用 computed,因为可以利用 computed 的缓存特性,避免每次获取值时,都要重新计算;
watch:类似于某些数据的监听回调 ,每当监听的数据变化时都会执行回调进行后续操作;当我们需要在数据变化时执行异步或开销较大的操作时,应该使用 watch,使用 watch 选项允许我们执行异步操作 ( 访问一个 API ),限制我们执行该操作的频率,并在我们得到最终结果前,设置中间状态。这些都是计算属性无法做到的。

  • v-if 和 v-show 区分使用场景 v-if 适用于在运行时很少改变条件,不需要频繁切换条件的场景;v-show 则适用于需要非常频繁切换条件的场景。这里要说的优化点在于减少页面中 dom 总数,我比较倾向于使用 v-if,因为减少了 dom 数量。
  • v-for 遍历必须为 item 添加 key,且避免同时使用 v-if v-for 遍历必须为 item 添加 key,循环调用子组件时添加 key,key 可以唯一标识一个循环个体,可以使用例如 item.id 作为 key 避免同时使用 v-if,v-for 比 v-if 优先级高,如果每一次都需要遍历整个数组,将会影响速度。

6、Webpack 对图片进行压缩

7、避免内存泄漏

8、减少 ES6 转为 ES5 的冗余代码

61.★★★★★ nextTick知道吗、实现的原理是什么?是宏任务还是微任务?

微任务

原理:

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

作用: nextTick用于下次Dom更新循环结束之后执行延迟回调,在修改数据之后使用nextTick用于下次Dom更新循环结束之后执行延迟回调,在修改数据之后使用nextTick用于下次Dom更新循环结束之后执行延迟回调,在修改数据之后使用nextTick,则可以在回调中获取更新后的DOM。

62.★★★ 介绍下vue单页面和多页面区别

单页应用 页面跳转---->js渲染 优点:页面切换快 缺点:首屏加载稍慢,seo差

多页应用 页面跳转---->返回html 优点:首屏时间快,seo效果好 缺点:页面切换慢

63.★★★★ 虚拟 dom 为什么会提高性能?

虚拟DOM其实就是一个JavaScript对象。通过这个JavaScript对象来描述真实DOM,真实DOM的操作,一般都会对某块元素的整体重新渲染,采用虚拟DOM的话,当数据变化的时候,只需要局部刷新变化的位置就好了 ,
虚拟dom相当于在js和真实dom中间加了一个缓存,利用dom diff算法避免了没有必要的dom操作,从而提高性能

具体实现步骤如下:

  • 用 JavaScript 对象结构表示 DOM 树的结构;然后用这个树构建一个真正的 DOM 树,插到文档当中
  • 当状态变更的时候,重新构造一棵新的对象树。然后用新的树和旧的树进行比较,记录两棵树差异
  • 把所记录的差异应用到步骤1所构建的真正的DOM树上,视图就更新

64.★★★ Vue中key的作用?不加会怎么样?

vue中列表循环需加:key=“唯一标识” 唯一标识可以是item里面id index等,因为vue组件高度复用增加Key可以标识组件的唯一性,为了更好地区别各个组件 key的作用主要是为了高效的更新虚拟DOM

65.★★★ Vue的常用修饰符

v-model修饰符

1、.lazy:输入框改变,这个数据就会改变,lazy这个修饰符会在光标离开input框才会更新数据

2、.trim:输入框过滤首尾的空格

3、.number:先输入数字就会限制输入只能是数字,先字符串就相当于没有加number,注意,不是输入框不能输入字符串,是这个数据是数字

事件修饰符

4、.stop:阻止事件冒泡,相当于调用了event.stopPropagation()方法

5、.prevent:阻止默认行为,相当于调用了event.preventDefault()方法,比如表单的提交、a标签的跳转就是默认事件

6、.self:只有元素本身触发时才触发方法,就是只有点击元素本身才会触发。比如一个div里面有个按钮,div和按钮都有事件,我们点击按钮,div绑定的方法也会触发,如果div的click加上self,只有点击到div的时候才会触发,变相的算是阻止冒泡

7、.once:事件只能用一次,无论点击几次,执行一次之后都不会再执行

8、.capture:事件的完整机制是捕获-目标-冒泡,事件触发是目标往外冒泡

9、.async对prop进行双向绑定

10、.keyCode:监听按键的指令,具体可以查看vue的键码对应表

66.★★★ Vue计算属性和 Watch 的区别

methods(方法):只要进行调用就会执行,不管依赖的值有没有改变。无缓存。

computed(计算属性):监听其所有依赖的变化,如果有变化会执行,没有变化不执行。有缓存,不用每次重新算。不支持异步。

详解:在vue的 模板内({{}})是可以写一些简单的js表达式的 ,很便利。但是如果在页面中使用大量或是复杂的表达式去处理数据,对页面的维护会有很大的影响。这个时候就需要用到computed 计算属性来处理复杂的逻辑运算。

优点:在数据未发生变化时,优先读取缓存。computed 计算属性只有在相关的数据发生变化时才会改变要计算的属性,当相关数据没有变化是,它会读取缓存。而不必想 motheds方法 和 watch 方法是否每次都去执行函数。

setter 和 getter方法:(注意在vue中书写时用set 和 get)setter 方法在设置值是触发。getter 方法在获取值时触发。

watch(侦听属性):观察某一个变量,发生变化会执行。支持异步。Vue 实例将会在实例化时调用 $watch(),遍历 watch 对象的每一个属性。一个对象,键是需要观察的表达式,值是对应回调函数。值也可以是方法名,或者包含选项的对象。

小结
1.主动调用的方法写在methods里,依据某些变量的更新进行某种操作用computed或者watch。
2.computed和watch:如果要异步,只能用watch。如果是计算某个值推荐用computed,比如购物车全选单选功能,购物车计算总价小计功能。

67.★★★ Vue 中 v-on 可以绑定多个方法吗?

<p v-on="{click:dbClick,mousemove:MouseClick}"></p>

68.★★★ Vue 中 template 的编译过程

vue template模板编译的过程经过parse()生成ast(抽象语法树),optimize对静态节点优化,generate()生成render字符串 之后调用new Watcher()函数,用来监听数据的变化,render 函数就是数据监听的回调所调用的,其结果便是重新生成 vnode。 当这个 render 函数字符串在第一次 mount、或者绑定的数据更新的时候,都会被调用,生成 Vnode。 如果是数据的更新,那么 Vnode 会与数据改变之前的 Vnode 做 diff,对内容做改动之后,就会更新到 我们真正的 DOM

69.★★★ 说一下Vue-router守卫有哪些。如何实现路由懒加载?

router.beforeEach 全局前置守卫 进入路由之前

router.beforeResolve 全局解析守卫(2.5.0+) 在beforeRouteEnter调用之后调用

router.afterEach 全局后置钩子 进入路由之后

70.★★★ 简述Vue每个生命周期具体适合哪些场景

生命周期发生了什么
beforeCreate初始化界面前 : 在当前阶段data、methods、computed以及watch上的数据和方法都不能被访问,都还没有完成初始化。
created初始化界面后 : 在实例创建完成后发生,当前阶段已经完成了数据观测,也就是可以使用数据,更改数据,在这里更改数据不会触发updated函数,也就是不会更新视图。实例的data数据和methods方法都已经被初始化完毕了,可以正常访问
beforeMount挂载前 :完成模板编译,虚拟Dom已经创建完成,即将开始渲染。在此时也可以对数据进行更改,不会触发updated。数据还没有更新到页面上去。当编译完成之后,只是在内存中已经有了编译好的页面,但并未渲染。
mounted挂载完成 : 将编译好的模板挂载到页面 (虚拟DOM挂载) ,可以在这进行异步请求以及DOM节点的访问,在vue用$ref操作
beforeUpdate更新数据前 : 组件数据更新之前调用,数据都是新的,页面上数据都是旧的。将要根据最新的data数据,重新解析所有指令,从而重新渲染浏览器页面。
updated组件更新后 : render重新渲染 , 此时数据和界面都是新的 ,要注意的是避免在此期间更改数据,因为这可能会导致无限循环的更新
beforeDestroy组件卸载前 : 实例销毁之前,在当前阶段实例完全可以被使用,我们可以在这时进行善后收尾工作,比如清除计时器
destroyed组件卸载后 : 组件已被拆解,数据绑定被卸除,监听被移出,子实例也统统被销毁。
activitedkeep-alive 专属 , 组件被激活时调用
deactivatedkeep-alive 专属 , 组件被销毁时调用

71.★★★ 什么是v-model?它的原理是什么?

  • v-model本质上是一个语法糖,可以看成是value + input 方法的语法糖。可以通过model的prop属性和event事件来进行自定义。
  • v-model是vue的双向绑定的指令,能将页面上控件输入的值同步更新到相关绑定的data属性, 也会在更新data绑定属性时候,更新页面上输入控件的值。

72.★★★ 简单说一下 微信小程序 与 Vue 的区别

1、生命周期
小程序的钩子函数要简单得多 。 vue的钩子函数在跳转新页面时,钩子函数都会触发,但是小程序的钩子函数,页面不同的跳转方式,触发的钩子并不一样。
在页面加载请求数据时,两者钩子的使用有些类似,vue一般会在created或者mounted中请求数据,而在小程序,会在onLoad或者onShow中请求数据。

2、数据绑定
vue动态绑定一个变量的值为元素的某个属性的时候,会在变量前面加上冒号:

小程序 绑定某个变量的值为元素属性时,会用两个大括号括起来,如果不加括号,为被认为是字符串

3、列表循环

4、显示与隐藏元素
vue中,使用v-if 和v-show控制元素的显示和隐藏
小程序中,使用wx-if和hidden控制元素的显示和隐藏

5、事件处理
vue:使用v-on:event绑定事件,或者使用@event绑定事件,小程序中,全用bindtap(bind+event),或者catchtap(catch+event)绑定事件

6、数据的双向绑定
在vue中,只需要再表单元素上加上v-model,然后再绑定data中对应的一个值,当表单元素内容发生变化时,data中对应的值也会相应改变 。
当表单内容发生变化时,会触发表单元素上绑定的方法,然后在该方法中,通过this.setData({key:value})来将表单上的值赋值给data中的对应值 。

7、绑定事件传参
在vue中,绑定事件传参挺简单,只需要在触发事件的方法中,把需要传递的数据作为形参传入就可以了
在小程序中,不能直接在绑定事件的方法中传入参数,需要将参数作为属性值,绑定到元素上的data-属性上,然后在方法中,通过e.currentTarget.dataset.*的方式获取

8、父子组件通信
父组件向子组件传递数据,只需要在子组件通过v-bind传入一个值,在子组件中,通过props接收,即可完成数据的传递
父组件向子组件通信和vue类似,但是小程序没有通过v-bind,而是直接将值赋值给一个变量 在子组件properties中,接收传递的值

73.★★★ Vue的组件通信

1、props和$emit

父组件向子组件传递数据是通过prop传递的,子组件传递数据给父组件是通过$emit触发事件

2、 a t t r s 和 attrs和 attrslisteners

3、中央事件总线 bus

上面两种方式处理的都是父子组件之间的数据传递,而如果两个组件不是父子关系呢?这种情况下可以使用中央事件总线的方式。新建一个Vue事件bus对象,然后通过bus. e m i t 触发事件, b u s . emit触发事件,bus. emit触发事件,bus.on监听触发的事件。

4、provide和inject

父组件中通过provider来提供变量,然后在子组件中通过inject来注入变量。不论子组件有多深,只要调用了inject那么就可以注入provider中的数据。而不是局限于只能从当前父组件的prop属性来获取数据,只要在父组件的生命周期内,子组件都可以调用。

5、v-model

父组件通过v-model传递值给子组件时,会自动传递一个value的prop属性,在子组件中通过this.$emit(‘input’,val)自动修改v-model绑定的值

6、 p a r e n t 和 parent和 parentchildren

7、boradcast和dispatch

8、vuex处理组件之间的数据交互 如果业务逻辑复杂,很多组件之间需要同时处理一些公共的数据,这个时候才有上面这一些方法可能不利于项目的维护,vuex的做法就是将这一些公共的数据抽离出来,然后其他组件就可以对这个公共数据进行读写操作,这样达到了解耦的目的。

74.★★★ 谈谈你对Vue3.0有什么了解?

一、六大亮点

性能比vue2.x快1.2~2倍
支持tree-shaking,按需编译,体积比vue2.x更小
支持组合API
更好的支持TS
更先进的组件

二、性能比vue2.x快1.2~2倍如何实现的呢
1.diff算法更快
vue2.0是需要全局去比较每个节点的,若发现有节点发生变化后,就去更新该节点
vue3.0是在创建虚拟dom中,会根据DOM的的内容会不会发生内容变化,添加静态标记, 谁有flag!比较谁。

2、静态提升
vue2中无论元素是否参与更新,每次都会重新创建,然后再渲染 vue3中对于不参与更新的元素,会做静态提升,只被创建一次,在渲染时直接复用即可

3、事件侦听缓存
默认情况下,onclick为动态绑定,所以每次都会追踪它的变化,但是因为是同一函数,没有必要追踪变化,直接缓存复用即可
在之前会添加静态标记8 会把点击事件当做动态属性 会进行diff算法比较, 但是在事件监听缓存之后就没有静态标记了,就会进行缓存复用

三、为什么vue3.0体积比vue2.x小

在vue3.0中创建vue项目 除了vue-cli,webpack外还有 一种创建方法是Vite Vite是作者开发的一款有意取代webpack的工具,其实现原理是利用ES6的import会发送请求去加载文件的特性,拦截这些请求,做一些预编译,省去webpack冗长的打包时间

四、vue3.0组合API

说一说vue3.0的组合API跟之前vue2.0在完成业务逻辑上的区别:
在vue2.0中: 主要是往data 和method里面添加内容,一个业务逻辑需要什么data和method就往里面添加,而组合API就是 有一个自己的方法,里面有自己专注的data 和method。

再说一下组合API的本质是什么: 首先composition API(组合API) 和 Option API(vue2.0中的data和method)可以共用 composition API(组合API)本质就是把内容添加到Option API中进行使用

五、ref和reactive的简单理解

1.ref和reactive都是vue3的监听数据的方法,本质是proxy
2.ref 基本类型复杂类型都可以监听(我们一般用ref监听基本类型),reactive只能监听对象(arr,json)
3.ref底层还是reactive

六、对生命周期的监听(ref获取属性)
七、proxy响应式本质

75.★★★ Vue如何在用户没登陆的时候重定向登录界面?


现在 我们需要实现这样 一个功能,登录拦截,其实就是 路由拦截,首先在定义路由的时候就需要多添加一个自定义字段requireAuth,用于判断该路由的访问是否需要登录。如果用户已经登录,则顺利进入路由, 否则就进入登录页面。在路由管理页面添加meta字段

{
  path:'/manage',
  name:'manage',
  component:manage,
  meta:{requireAuth:true}
}

在入口文件中,添加路由守卫
1、先判断该路由是否需要登录权限
2、判断本地是否存在token,如果存在token就next(),不存在token重定向到登录页

76.★★★★★ Vue项目常见优化点​

1、首屏加载优化

2、路由懒加载

{      
  path: '/',      
  name: 'home',      
  component: () => import('./views/home/index.vue'),      
  meta: { isShowHead: true }
}

3、开启服务器 Gzip

开启 Gzip 就是一种压缩技术,需要前端提供压缩包,然后在服务器开启压缩,文件在服务器压缩后传给浏览器,浏览器解压后进行再进行解析。首先安装 webpack 提供的compression-webpack-plugin进行压缩,然后在 vue.config.js:

const CompressionWebpackPlugin = require('compression-webpack-plugin')
const productionGzipExtensions = ['js', 'css']......plugins: [      
  new CompressionWebpackPlugin(
    {        
      algorithm: 'gzip',        
      test:     new RegExp('\\.(' + productionGzipExtensions.join('|') +                 ')$'),            
      threshold: 10240,        
      minRatio: 0.8      
       }
)]....

4、启动 CDN 加速

我们继续采用 cdn 的方式来引入一些第三方资源,就可以缓解我们服务器的压力,原理是将我们的压力分给其他服务器点。

5、代码层面优化

  • computed 和 watch 区分使用场景
    computed: 是计算属性,依赖其它属性值,并且 computed 的值有缓存,只有它依赖的属性值发生改变,下一次获取 computed 的值时才会重新计算 computed 的值。当我们需要进行数值计算,并且依赖于其它数据时,应该使用 computed,因为可以利用 computed 的缓存特性,避免每次获取值时,都要重新计算;
    watch:类似于某些数据的监听回调 ,每当监听的数据变化时都会执行回调进行后续操作;当我们需要在数据变化时执行异步或开销较大的操作时,应该使用 watch,使用 watch 选项允许我们执行异步操作 ( 访问一个 API ),限制我们执行该操作的频率,并在我们得到最终结果前,设置中间状态。这些都是计算属性无法做到的。

  • v-if 和 v-show 区分使用场景 v-if 适用于在运行时很少改变条件,不需要频繁切换条件的场景;v-show 则适用于需要非常频繁切换条件的场景。这里要说的优化点在于减少页面中 dom 总数,我比较倾向于使用 v-if,因为减少了 dom 数量。

  • v-for 遍历必须为 item 添加 key,且避免同时使用 v-if v-for 遍历必须为 item 添加 key,循环调用子组件时添加 key,key 可以唯一标识一个循环个体,可以使用例如 item.id 作为 key 避免同时使用 v-if,v-for 比 v-if 优先级高,如果每一次都需要遍历整个数组,将会影响速度。

6、Webpack 对图片进行压缩

7、避免内存泄漏

8、减少 ES6 转为 ES5 的冗余代码

77.★★★ Vuex和redux有什么区别?他们的共同思想。

Redux和Vuex区别

  • Vuex改进了Redux中的Action和Reducer函数,以mutations变化函数取代Reducer,无需switch,只需在对应的mutation函数里改变state值就可以
  • Vuex由于Vue自动重新渲染的特性,无需订阅重新渲染函数,只要生成新的state就可以
  • Vuex数据流的顺序是:View调用store.commit提交对应的请求到Store中对应的mutation函数 – store改变(vue检测到数据变化自动渲染)

共同思想

  • 单一的数据源
  • 变化可以预测
  • 本质上:Redux和Vuex都是对MVVM思想的服务,将数据从视图中抽离的一种方案
  • 形式上:Vuex借鉴了Redux,将store作为全局的数据中心,进行数据管理
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

北海屿鹿

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值