Vue面试总结

Vue优点

数据驱动和组件化

  • 数据驱动:自动计算属性和追踪依赖的模板表达
  • 组件化:可复用,解耦的组件来构造页面

Vue生命周期

  • beforeCreated:创建前。数据观测和初始化事件未开始。
  • created:创建后。完成数据观测、属性和方法的处理。以及初始化事件。
  • beforeMounted:挂载前。挂载开始前被调用,render函数被首次调用。完成编译模板,data里的数据和模板生成HTML
  • mounted:挂在后。el属性被新创建出来的vm.$el代替,并挂载到实例上之后被调用。
  • beforeUpdate:虚拟DOM重新渲染之前
  • update:虚拟DOM重新渲染之后
  • beforeDestory:实例被摧毁之前调用,实例仍然可用。
  • destoryed:实例被摧毁之后调用;调用时,所有的监听器都会被移除。

Vue的指令有哪些

v-if/v-else/v-else-if/v-bind(:)/v-on(@)/v-show/v-html/v-text/v-model/v-for/v-once;

Vue常用修饰符

.prevent: 提交事件不再重载页面
.stop: 阻止单击事件冒泡
.self: 当事件发生在该元素本身而不是子元素的时候会触发
.capture: 事件侦听,事件发生的时候会调用
.once: 跟v-once作用类似,只渲染一次,第二次不会执行

watch和computed的区别

  • computed:计算属性。通过其他变量来获取另一个属性,具有缓存。计算属性只有在他们依赖的属性改变的时候才会重新计算求值
  • watch:监听某一属性。回调里面可以传入新旧值。

watch详解

watch:可以用来监测VUE实例上数据的变动;

  1. 简单运用:
    watch: function(newVal,OldVal) {};
  2. 复杂运用:
    1.immediate: 由于watch有一个特点,就是最初绑定的时候 不会去执行,只有当值发生改变的时候 才会去执行监听计算。如果我们想要在最初绑定的时候就去执行监听计算的话,就需要在watch中设置immediate属性值为true;
    2.deep: 比如说我们data里面监听的是一个对象,但是我们想要监听的是object.a的值的变化,就监听不到的。由于handler只监听data里的obj的变化。这时候我们就需要这是deep属性为true。deep就是指深度观察,监听器会逐一的遍历下去,给obj的每一属性都加上监听器,但是这样是非常耗性能的。
watch: {
   handler:functio(newVal,OldVal) {},
   immediate:true,
}

Vue中如何获取DOM

只有在mounted阶段之后才能获取dom

  1. ref:ref被用来给元素或者是子组件注册引用信息,引用信息将会注册在父组件的$refs对象上。如果是在普通的DOM上用,那么指向的就是普通的元素,如果是在子组件上使用,指向的就是子组件实例;
  2. 选择器获取:比如docment.querySelector("#id");

组件之间的传值

  1. 父组件传给子组件:子组件通过props接收传递的数据
  2. 子组件传递给父组件:通过$emit传递参数
  3. 同级之间传递:eventBus,创建一个事件中心,相当于一个中转站,可以用它来传递数据和接收数据;
  4. vuex
  5. 祖传孙:通过provide
//祖
provide: {
    foo: {
      a: 1,
      b: 2,
      c: 3
    }
  }
 
//在孙组件中
inject: ["foo"],
  data() {
    return {
      bar: this.foo.a
    };
  },
  created() {
    console.log(1);
    console.log(this.bar); // => "bar"
  }

Vue-router的钩子函数

  1. 全局导航钩子函数
    1. router.beforeEach(to, from, next),
    2. router.beforeResolve(to, from, next),
    3. router.afterEach(to, from ,next)
  2. 组件内钩子:
    1. beforeRouterEnter
    2. beforeRouterUpdate
    3. beforeRouterLeave
  3. 单独路由独享组件:
    beforeEnter

完整的导航解析流程

  • 导航被触发
  • 在失活的组件里调用离开守卫
  • 调用全局的 beforeEach 守卫
  • 在重用的组件里调用 beforeRouteUpdate 守卫
  • 在路由配置里调用 beforEnter
  • 解析异步路由组件
  • 在被激活的组件里调用 beforeRouteEnter
  • 调用全局的 beforeResolve 守卫
  • 导航被确认
  • 调用全局的 afterEach 钩子
  • 触发 DOM 更新
  • 在创建好的实例调用 beforeRouteEnter 守卫中传给 next 的回调函数

vue组件中data为什么必须是函数

因为一个组件是可以共享的,但他们的data是私有的,所以每个组件都要return一个新的data对象,返回一个唯一的对象,不要和其他组件共用一个对象

从源码看Vue中数组的问题

由于JavaScript的限制,Vue不能做以下操作

  1. 利用索引直接设置一个数组项。vm.items[indexofitem] = newValue
  2. 修改数组的长度,vm.items.length = newLength

解决方法

在源代码中,采用数组变异思路,首先对功能进行扩展,之后进行数组劫持。

功能扩展思路:

  1. 创建一个继承原Array的新函数对象。
  2. 重新定义函数对象
  3. 在新定义的函数中调用原函数
// 变异方法名称
const methodsToPatch = [
  'push',
  'pop',
  'shift',
  'unshift',
  'splice',
  'sort',
  'reverse'
]

const arrayProto = Array.prototype
// 继承原有数组的方法
const arrayMethods = Object.create(arrayProto)

mutationMethods.forEach(method => {
    // 缓存原生数组方法
    const original = arrayProto[method]
    arrayMethods[method] = function (...args) {
        const result = original.apply(this, args)
        
        console.log('执行响应式功能')
        
        return result
    }

共有7种变异函数。

数据劫持思路
使用原型链,将普通函数指向我们所扩展的新组对象

let arr = []
// 通过隐式原型继承arrayMethods
arr.__proto__ = arrayMethods

// 执行变异后方法
arr.push(1)

Vue 的变异数组从本质上是来说是一种装饰器模式,通过学习它的原理,我们在实际工作中可以轻松处理这类保持原有功能不变的前提下对其进行功能拓展的需求。


// Vue.set
Vue.set(vm.items, indexOfItem, newValue)
// vm.$set,Vue.set的一个别名
vm.$set(vm.items, indexOfItem, newValue)
// Array.prototype.splice
vm.items.splice(indexOfItem, 1, newValue)

vm.items.splice(newLength)

在vue中有的时候是不能获取到数组的,那么vue源码是怎样去处理这些数组,并获取到的呢?

答:组件处理 vue做了拦截,重写了数组的方法,最终还是通过数据劫持获取到的。

Vue 怎么用 vm.$set() 解决对象新增属性不能响应的问题 ?

vue 无法检测到对象属性的添加或者删除。所以Vue提供了Vue.set (object, propertyName, value) / vm.$set (object, propertyName, value) 来实现为对象添加响应式属性。

源码实现思想

  1. 如果目标是数组,直接使用扩展数组的splice方法触发响应式。

  2. 如果目标是对象,会先判读属性是否存在、对象是否是响应式,最终如果要对属性进行响应式处理,则是通过调用 defineReactive 方法进行响应式处理( defineReactive 方法就是 Vue 在初始化对象时,给对象属性采用 Object.defineProperty 动态添加 getter 和 setter 的功能所调用的方法)

父子组件生命周期调用顺序

父组件beforeMounted阶段之后进入子组件,子组件完成mounted之后继续父组件的周期。当子组件触发数据更新,先触发父组件beforeUpdate,之后触发子组件beforeUpdate,然后触发子组件updated,最后触发父组件updated。

Vuex

  • state: vuex store实例的根状态对象,用于定位共享的状态
  • action: 动作,执行本地操作或者异步操作(相当于state的methods)。action可以进行异步操作。store.dispatch()来执行action
  • Mutations: 修改器。唯一只用于修改state。store.commit()来执行。
  • getter:读取器,外部程序通过他获取变量的具体值,或者是在取值前做一些计算,可以认为是store的计算属性。

vuex提供了三种辅助函数用于获取、修改vuex:
mapState、mapGetters、mapActions
即将vuex的变量或者方法映射到vue组件this指针上。

methods: {
       //下述中的 ... 是拓展运算符
       // 使用 [] 是解构赋值
    ...mapActions([
      'increment', // 将 `this.increment()` 映射为 `this.$store.dispatch('increment')`
 
      // `mapActions` 也支持载荷:
      'incrementBy' // 将 `this.incrementBy(amount)` 映射为 `this.$store.dispatch('incrementBy', amount)`
    ]),
    ...mapActions({
      add: 'increment' // 将 `this.add()` 映射为 `this.$store.dispatch('increment')`
    })
  }

Vue-router原理

spa实现方式分为三种

hash模式

地址栏中#符号。特点是hash虽然出现在浏览器url中,但是不会包含在HTTP请求中,对后端没有影响,不会重新加载页面

history模式

利用HTML5新增的pushState()和replaceState()实现。这两个方法应用于浏览器的历史记录栈。但是需要后端对路由进行配置,重定向到Vue打包生成的index.html的页面上寻找相应的代码,否则会报错。

 window.history.pushState(state, title, url)
 - state: 一个与指定网址相关的状态对象,popstate事件触发时,该对象会传入回调函数
 - title:新页面的标题,大部分浏览器不支持这个
 - url: 新的网址,必须是与当前页面同一个域名。浏览器显示的地址
 
 重点是 pushstate方法不会触发页面刷新,只是会导致history对象发生变化,地址栏会有反应
 
 window.onpopstate = function (event) {}
 
 popstate事件会在点击后退、前进按钮(或调用history.back()、history.forward()、history.go()方法)时触发。前提是不能真的发生了页面跳转,而是在由history.pushState()或者history.replaceState()形成的历史节点中前进后退

注意:用history.pushState()或者history.replaceState()不会触发popstate事件。

在Vue中需要这样配置node:'history'

abstract模式

abstract模式是使用一个不依赖于浏览器的浏览历史虚拟管理后端。

根据平台差异可以看出,在 Weex 环境中只支持使用 abstract 模式。 不过,vue-router 自身会对环境做校验,如果发现没有浏览器的 API,vue-router 会自动强制进入 abstract 模式,所以 在使用 vue-router 时只要不写 mode 配置即可,默认会在浏览器环境中使用 hash 模式,在移动端原生环境中使用 abstract 模式。 (当然,你也可以明确指定在所有情况下都使用 abstract 模式)

注意

  1. hash模式不会生成404的错误
  2. history模式需要后端支持。指定的路径需要返回对应的HTML页面。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,718评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,683评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,207评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,755评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,862评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,050评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,136评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,882评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,330评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,651评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,789评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,477评论 4 333
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,135评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,864评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,099评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,598评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,697评论 2 351

推荐阅读更多精彩内容