Vue面试题集锦

VUE的双向绑定原理

image.png

原理:在创建Vue实例时,Vue会遍历data选项的属性,利用Object.defineProperty()为属性添加getter和setter对数据的读取进行劫持(getter用来依赖手机,setter用来派发更新),并且在内部追踪依赖,在属性被访问和修改时通知变化。每个组件实例会有相应的watcher实例,会在组件渲染过程中记录依赖的所有数据属性,之后依赖项被改动时,setter方法会通知依赖与此data的watcher实例重新计算(派发更新),从而使它关联的组件重新渲染。

一句话总结:vue.js采用数据劫持结合发布-订阅模式,通过Object.defineProperty()来劫持各个属性的setter、getter,在数据变动时发布消息给订阅者,触发响应的监听回调。

我的理解:在new Vue的时候,在Observer中通过Object.defineProperty()达到数据劫持,代理所有数据的getter和setter属性,在每次触发setter的时候,都会通过Dep来通知Watcher,Watcher作为Observer数据监听器与Compile模板解析器之间的桥梁,当Observer监听到数据发生改变的时候,通过Updater来通知Compile更新视图。而Compile通过Watcher订阅对应数据,绑定更新函数,通过Dep来添加订阅者,达到双向绑定。

什么是Vue的生命周期?

Vue实例从创建到销毁的全过程,就是生命周期。也就是从开始创建、初始化数据、编译模板、挂载DOM->渲染、更新->渲染、卸载等一系列过程。

Vue生命周期的作用是什么?

它的生命周期中有多个事件钩子,让我们在控制整个Vue实例的过程时更容易形成好的逻辑。

Vue生命周期共有几个阶段?

它可以分为8个阶段:创建前/后、载入前/后、更新前/后、销毁前/后。

  • beforeCreate:在实例初始化之后,el和data并未初始化(这个时候,this变量还不能使用,在data下的数据,和methods下的方法,watcher中的事件都不能获取到)。
  • created:完成了data数据的初始化,el没有(这个时候,可以操作Vue实例中的数据和各种方法了,但是还不能对dom节点进行操作)。
  • beforeMount:完成了el和data初始化(这里的el是虚拟的dom)。
  • mounted:完成挂载,在这发起后端请求,拿回数据,配合理由钩子做一些事情(挂载完毕,这时dom节点被渲染到文档中,一些需要dom的操作在此时才能正常进行)。
  • beforeUpdate:是指view层数据变化前,不是data中的数据改变前触发。
  • update:是指view层数据变化之后。
  • beforeDestroy:你确认删除XX吗?
  • destroyed:当前组件已被删除,清空相关内容。

第一次页面加载会触发哪几个钩子?

第一次页面加载时会触发beforeCreate、created、beforeMounted、mounted

DOM渲染在哪个周期中就已经完成?

DOM渲染在mounted中就已经完成。

简单描述每个周期具体适合哪些场景?

1、beforeCreate:可以在这加个loading事件,在加载实例时触发;
2、created:初始化完成时的事件写在这里,如在这结束loading事件,异步请求也适宜在这里调用;
3、mounted:挂载元素,获取DOM节点;
4、updated:如果对数据统一处理,在这里写上相应函数;
5、beforeDestroy:可以放一个确认停止事件的确认框;
6、nextTick:更新数据后立即操作DOM。

v-show和v-if的区别

  • v-show是CSS切换,v-if是完整的销毁和重新创建(使用频繁切换时使用v-show,运行时较少改变使用v-if)
  • v-if 是条件渲染,当v-if=false时不会渲染,也就是页面不会有这个HTML标签生成
  • v-show则是不管是true还是false,HTML元素都会存在,只是css中的display显示或隐藏
  • v-show仅仅控制元素的显示方式,将display属性在block和none中来回切换;而v-if会控制这个DOM节点的存在与否。当我们需要经常切换某个元素的显示/隐藏时,使用v-show更能节省性能上的开销;当只需要一次显示/隐藏时,使用v-if更合理。

开发中常用的指令有哪些?

  • v-model:一般用于表达输入(输入框),很轻松的实现表单控件和数据的双向绑定
  • v-html:更新元素的innerHTML
  • v-show和v-if:条件渲染
  • v-on:click:可以简写为@click,@绑定一个事件,如果事件触发了,就可以指定事件的处理函数
  • v-bind:当表达式的值改变时,将其产生的连带影响,响应式地作用于DOM语法
  • v-bind:title='msg'简写:title='msg'

绑定class的数组用法

1、对象方法v-bind:class="{'orange': isRipe, 'green': isNotRipe}"
2、数组方法v-bind:class="[class1, class2]"
3、行内v-bind:style="{color: color, fontSize: fontSize+'px'}"

路由跳转方式

1、router-link标签会渲染为标签,咋填template中的跳转都是这种;
2、另一种是编辑式导航,也就是通过js跳转比如router.push('/home')

MVVM

M- model ,model 表示数据模型,也可以在model中定义数据修改和操作的业务逻辑
V- view,view表示视图,它负责将数据模型转换为视图展示出来
VM- viewmodel,viewmodel是一个同步view和model的对象,连接view和model,用于监听数据模型的改变和控制视图行为

computed和watch的区别?

computed:computed是计算属性,也就是计算值,更多用于计算值的场景。它具有缓存性,computed的值在getter执行后是会缓存的,只有在它依赖的属性值改变之后,下一次获取computed的值时重新调用对应的getter来计算。

watch:watch更多的是观察作用,类似于某些数据的监听回调,用于观察props、$emit或者本组件的值,当数据变化时用来执行回调进行后续操作。它不具有缓存性,页面重新渲染时值不会变化也不会执行。

Vue组件的scoped属性的作用

在style标签上添加scoped属性,以表示它的样式作用于当下的模块,很好的实现了样式私有化的目的,但是也得慎用,样式不易改变。
解决方法:
① 使用混合型的css样式,混合使用全局样式和私有样式。
② 深度作用选择器:如果你希望scoped样式中的一个选择器能够作用的更深,可以使用>>>操作符。如:

vue.js的两个核心是什么?

  • 数据驱动:Object.defineProperty和存储器属性:getter和setter(只兼容IE9及以上版本)。可称为基于依赖收集的观测机制,核心是VM,即viewmodel,保证数据和视图的一致性。
  • 组件系统:能够把页面抽象成多个相对独立的模块,实现代码重用,提高开发效率和代码质量,使代码易于维护。

v-on可以监听多个方法吗?(可以的)

一个元素绑定多个事件的写法有两种:
1、修饰符的使用

doSomething

2、在method方法里分别写两个事件

vue事件中如何使用event对象


vue中data为什么必须是函数?

data () {
  return {}
}

Vue组件中的data值不能为对象,因为对象是引用类型,组件可能会被多个实例同时引用,如果data值为对象,将导致多个实例共享一个对象,其中一个组件改变data属性值,其它实例也会受到影响。

Vue中的nextTick是什么作用?

原理:JS执行是单线程的,它是基于事件循环的。所有同步任务都在主线程上执行,形成一个执行栈。主线程之外,还存在一个任务队列,只要异步任务有了运行结果,就在任务队列中放置一个事件。一旦执行栈中的所有同步任务执行完毕,系统就会读取任务队列,看看那些对应的异步任务,等结束等待状态,进入执行栈,开始执行。主线程不断重复上面的步骤。主执行的执行过程就是tick,所有的异步结果都是通过任务队列来调度的。任务分为两大类:宏任务和微任务,宏任务包括:setTimeOut等,微任务包括promise.then。

Vue用异步队列的方式来控制DOM更新和nextTick回调先后执行。在下次DOM更新循环结束之后执行延迟回调,nextTick主要使用了宏任务和微任务,nextTick把要执行的任务推入一个队列中,在下一个tick同步执行队列的所有任务,它是异步任务中的微任务。如果我们在更新了一个响应式数据后,需要同步拿到这个渲染后的DOM结果,就使用nextTick方法,异步拿这个结果。
使用方式:
① this.nextTick.then(cb); 异步

组件中如何传递数据?

props: {
  message: String // 定义传值的类型
}

父组件调用子组件的方法
父组件:this.$refs.yeluosen.childMethod()
子组件向父组件传值并调用方法:$emit
组件之间:bus==$emit+$on

Vue中子组件调用父组件的方法

1、第一种方法是直接在子组件中通过this.emit向父组件触发一个事件,父组件监听这个事件就行了。
3、第三种都可以实现子组件调用父组件的方法。



vue中keep-alive组件的作用

keep-alive是Vue内置的一个组件,可以使被包含的组件保留状态,或避免重新渲染。


  
    
  


如果只想 router-view 里面某个组件被缓存
export default [{
  {
    path: '/',
    name: 'home',
    component: Home,
    meat: {
      keepAlive: true // 需要被缓存
    }
  }, {
    path: '/:id',
    name: 'edit',
    component: Edit,
    meta: {
      keepAlive: false, // 不需要被缓存
    }
  }
}]

  
    
  



  

vue-router实现路由懒加载(动态加载路由)

import Vue from 'vue'
import Router from 'vue-router'
Vue.use(router)

export default new Router ({
  routes: [
    {
      path: '/Login',
      name: 'Login',
      component: resolve => require(['@/components/Login'], resolve)
    },
    {
      path: '/',
      name: 'Home',
      component: resolve => require(['@/components/Home'], resolve),
      children: [{
        path: '/',
        name: 'Skill',
        component: resolve => require(['@/components/Skill'], resolve)
      }, {
        path: '/Skill',
        name: 'Skill',
        component: resolve => require(['@/components/Skill'], resolve)
      }]
    }
  ]
})

完整的vue-router导航解析流程

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

vue-router如何响应路由参数的变化?

原来的组件实例会被复用。这也意味着组件的生命周期钩子不会再被调用,你可以简单的监控watch $route对象:

const User = {
  template: '...',
  watch: {
    '$route' (to, from) {
      // 对路由变化作出响应
    }
  }
}

vue-route的几种实例方法以及参数传递

  • name传递
  • to来传递
  • 采用URL传递

is的用法(用于动态组件且基于DOM内模板的限制来工作)

is用来动态切换组件,DOM模板解析

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

全局的:前置守卫、后置钩子(beforeEach、afterEach)beforeResolve
单个路由独享的:beforeEnter
组件级的:beforeRouteEnter(不能获取组件实例this)、beforeRouteUpdate、beforeRouteLeave
这是因为在执行路有钩子函数beforeRouteEnter的时候,组件还没有被创建出来,先执行beforeRouteEnter,再执行周期钩子函数beforeCreate,可以通过next获取组件的实例对象,如:next((vm) => {}),参数vm就是组件的实例化对象。

Vue单页面应用及其优缺点

缺点:

  • 不支持低版本的浏览器,最低支持到IE9。
  • 不利于SEO的优化(如果要支持SEO,建议通过服务端来进行渲染组件)。
  • 第一次加载首页耗时相对长一些。
  • 不可以使用浏览器的导航按钮需要自行实现前进、后退。

优点:

  • 无刷新体验,提升了用户体验。
  • 前端开发不再以页面为单位,更多地采用组件化的思想,代码结构和组织方法更加规范化,便于修改和调整。
  • API共享,同一套后端程序代码不用修改就可以用于Web页面、手机、平板等多种客户端。
  • 用户体验好、快,内容的改变不需要重新加载整个页面。

什么是Vue的计算属性computed?

计算属性是需要复杂的逻辑,可以用方法method代替。

computed: {
  totalPrice () {
    return (this.good.price * this.good.count)*this.discount+this.deliver;
  }
}

vue-cli提供的几种脚手架模板

vue-cli提供的脚手架模板有browserify和webpack。

vuex是什么?怎么使用?那种功能场景使用它?

① 是什么?
Vue框架中的状态管理,分别是State、Getter、Mutation、Action、Module。
② 怎么使用?
新建一个目录store。
③ 功能场景?
单页应用中,组件之间的状态。音乐播放、登录状态、加入购物车等。
④ vuex的状态:
a. State特性:vuex就是一个仓库,仓库里面放了很多对象,其中state就是数据源存放地,对应于一般Vue对象里面的data。state里面存放的数据是响应式的,Vue组件从store中读取数据,若是store中的数据发生改变,依赖这个数据的组件也会发生更新。它通过mapState把全局的state和getters映射到当前组件的computed计算属性中。
b. Getter特性:getters可以对State进行计算操作,它就是store的计算属性。虽然在组件内可以做计算属性,但是getters可以在多组件之间复用。如果一个状态只在一个组件内使用,可以不用getters。
c. Mutation特性:改变store中state状态的唯一方法就是提交mutation,每个mutation都有一个字符串类型的事件类型和一个回调函数,我们需要改变state的值就要在回调函数中改变。我们要执行这个回调函数,那我们需要执行一个相应的调用方法:store.commit。
d. Action特性:类似于mutation,不同点在于:Action提交的是mutation,而不是直接变更状态。Action可以包含任意异步操作,Action函数接受一个与store实例具有相同方法和属性的context对象,因此你可以调用context.commit提交一个mutation。或者通过context.state和context.getters来获取state和getters。Action通过store.dispatch方法触发:store.dispatch('increment')。
e. Module特性:Module其实只是解决了当state中很复杂臃肿的时候,module可以将store分解为模块,每个模块中拥有自己的state、mutation、action和getter。

vue中如何编写可复用的组件?

① 创建组件页面eg Toast.vue
② 用Vue.extend() 扩展一个组件构造器,再通过实例化组件构造器,就可以创造出可复用的组件。
③ 将toast组件挂载到新创建的div上;
④ 将toast组件的dom添加到body里;
⑤ 修改优化达到动态控制页面显示文字跟显示时间;

import Vue from 'vue'; 
import Toast from '@/components/Toast';     //引入组件
let ToastConstructor  = Vue.extend(Toast) // 返回一个“扩展实例构造器”
 
let myToast = (text,duration)=>{
    let toastDom = new ToastConstructor({
        el:document.createElement('div')    //将toast组件挂载到新创建的div上
    })
    document.body.appendChild( toastDom.$el )   //把toast组件的dom添加到body里
    
    toastDom.text = text;
    toastDom.duration = duration;
 
    // 在指定 duration 之后让 toast消失
    setTimeout(()=>{
        toastDom.isShow = false;  
    }, toastDom.duration);
}
export default myToast;

Vue常用修饰符

修饰符分为:一般修饰符、事件修饰符、按键、系统
① 一般修饰符:

  • .lazy:v-model在每次input事件触发后将输入框的值与数据进行同步,你可以添加lazy修饰符,从而转变为使用change事件进行同步。
  • .number
  • .trim:如果要自动过滤用户输入的首尾空白字符


② 事件修饰符



...
...

③ 按键修饰符

.enter
.tab
.delete (捕获“删除”和“退格”键)
.esc
.space
.up
.down
.left
.right
.ctrl
.alt
.shift
.meta

 或者 

④ 系统修饰符(可以用如下修饰符来实现仅在按下相应按键时才触发鼠标或键盘事件的监听器。)

.ctrl
.alt
.shift
.meta

 或者 
Do something

对VUE是渐进式框架的理解

Vue的核心的功能,是一个视图模板引擎,但这不是说Vue就不能成为一个框架。在声明式渲染(视图模板引擎)的基础上,我们可以通过添加组件系统、客户端路由、大规模状态管理来构建一个完整的框架。更重要的是,这些功能相互独立,你可以在核心功能的基础上任意选用其他的部件,不一定要全部整合在一起。可以看到,所说的“渐进式”,其实就是Vue的使用方式,同时也体现了Vue的设计的理念
在我看来,渐进式代表的含义是:主张最少。视图模板引擎每个框架都不可避免会有自己的一些特点,从而会对使用者有一定的要求,这些要求就是主张,主张有强有弱,它的强势程度会影响在业务开发中的使用方式。
比如说,Angular,它两个版本都是强主张的,如果你用它,必须接受以下东西:
必须使用它的模块机制- 必须使用它的依赖注入- 必须使用它的特殊形式定义组件(这一点每个视图框架都有,难以避免)所以Angular是带有比较强的排它性的,如果你的应用不是从头开始,而是要不断考虑是否跟其他东西集成,这些主张会带来一些困扰。
Vue可能有些方面是不如React,不如Angular,但它是渐进的,没有强主张,你可以在原有大系统的上面,把一两个组件改用它实现,当jQuery用;也可以整个用它全家桶开发,当Angular用;还可以用它的视图,搭配你自己设计的整个下层用。也可以函数式,都可以,它只是个轻量视图而已,只做了自己该做的事,没有做不该做的事,仅此而已。
渐进式的含义,我的理解是:主张最少,没有多做职责之外的事。

你可能感兴趣的:(Vue面试题集锦)