Vue 面试题

什么是 MVVM ?

 MVVM 由 Model、View、ViewModel 三部分构成, 
 Model-View-ViewModel 的缩写, Model 代表数据模型,View 代表 UI 组件, 
 ViewModel 将 Model 和 View 关联起来,数据会绑定到 ViewModel 层,并自动将数据渲染到页面中,
 视图变化的时候会通知 ViewModel 层更新数据。

MVVM 和 MVC 的区别?

MVC 和 MVVM 其实区别并不大,都是一种设计思想。主要就是 MVC 中 Controller 演变成 MVVM 中 viewModel 
MVVM 主要解决了 MVC 中大量的 DOM 操作使页面渲染性能降低,加载速度变慢,影响用户体验。

单页面应用的优缺点

优点:
    1. 用户体验好,快,内容的改变不需要重新加载整个页面,基于这一点spa对服务器压力较小
    2. 前后端分离
    3. 页面效果会比较炫酷(比如切换页面内容时的专场动画)
缺点:
    1. 不利于seo
    2. 导航不可用,如果一定要导航需要自行实现前进、后退由于是单页面不能用浏览器的前进后退功能,所以需要自己建立堆栈管理.
    3. 初次加载时耗时多
    4. 页面复杂度提高很多

VNode 是什么?虚拟 DOM 是什么?

Vue 在页面上渲染的节点,及其子节点称为**“虚拟节点 (Virtual Node)”**,简写为VNode,虚拟 DOM 是由 
Vue 组件树建立起来的整个 VNode 树的称呼。

双向数据绑定原理

双向数据绑定是通过数据劫持和订阅者发布模式的方式,通过 object.defineProperty() 给各个属性添加 setter,
getter 并进行劫持监听,在数据变动时发布消息给订阅者,触发相应的监听回调。

vue 响应式原理

响应式原理就是当数据发生改变的时候,视图会重新渲染,匹配更新为最新的值,
Object.defineProperty 为对象中的每一个属性,设置 get 和 set 方法,每个声明的属性,都会有一个专属的依赖。
收集器 subs,当页面使用到某个属性时,触发 ObjectdefineProperty - get 函数,页面的 watcher 就会被放到
属性的依赖收集器 subs 中,在数据变化时,通知更新;当数据改变的时候,会触发 Object.defineProperty - set 函数,
数据会遍历自己的 依赖收集器 subs,逐个通知 watcher,视图开始更新。

vue 中使用的设计模式

1.工厂模式 - 传入参数即可创建实例虚拟 DOM 根据参数的不同返回基础标签的 Vnode 和组件 Vnode
2.单例模式 - 整个程序有且仅有一个实例vuex 和 vue-router 的插件注册方法 install 判断如果系统存在实例就直接返回掉
3.发布-订阅模式 (vue 事件机制)
4.观察者模式 (响应式数据原理)
5.装饰模式: (@装饰器的用法)
6.策略模式 策略模式指对象有某个行为,但是在不同的场景中,该行为有不同的实现方案-比如选项的合并策略

vue 中 created 与 mounted 的区别

   在 created 阶段,实例已经被初始化,但是还没有挂载至 el 上,所以我们无法获取到对应的节点,但是此时
我们是可以获取到vue中data与methods中的数据的。
   在 mounted 阶段,vue 的 template 成功挂载在 $el 中,此时一个完整的页面已经能够显示在浏览器中,
所以在这个阶段,可以调用节点了。

vue 中 computed 与 methods 的区别

computed 会基于响应数据缓存,methods 不会缓存;
diff 之前先看 data 里的数据是否发生变化,如果没有变化 computed 的方法不会执行,但 methods 里的方法会执行
computed 是属性调用,而 methods 是函数调用。

computed 和 watch 的区别

computed 是计算属性,依赖其它属性值,并且 computed 的值有缓存,只有它依赖的属性值发生改变,下一次获取 
computed 的值时才会重新计算 computed 的值。
watch 没有缓存性,更多的是「观察」的作用,类似于某些数据的监听回调 ,每当监听的数据变化时都会执行回调进行
后续操作;当我们需要深度监听对象中的属性时,可以打开 deep:true 选项,这样便会对对象中的每一项进行监听。

vue 中 watch 用法

监听的数据后面可以写成对象形式,包含 handler 方法,immediate 和 deep,
immediate 表示在 watch 中首次绑定的时候,是否执行 handler,值为 true 则表示在 watch 中声明的时候,
就立即执行 handler 方法,值为 false,则和一般使用 watch 一样,在数据发生变化的时候才执行 handler,
当需要监听一个对象的改变时,普通的 watch 方法无法监听到对象内部属性的改变,只有 data 中的数据才能够监听到变化,
此时就需要 deep 属性对对象进行深度监听。

代码示例:
                watch: {
                    name: {
                      handler(newName, oldName) {
                      
                      },
                      deep: true,
                      immediate: true
                    }
                } 

vue 中常用的指令

1.v-model 指令 : 用于表单输入,实现表单控件和数据的双向绑定。
2.v-on: 简写为 @,基础事件绑定
3.v-bind: 简写为 : ,动态绑定一些元素的属性,类型可以是:字符串、对象或数组。
4.v-if 指令:取值为 true/false,控制元素是否需要被渲染
5.v-else 指令:和 v-if 指令搭配使用,没有对应的值。当 v-if 的值 false,v-else 才会被渲染出来。
6.v-show 指令:指令的取值为 true/false,分别对应着显示/隐藏。
7.v-for 指令:遍历data中存放的数组数据,实现列表的渲染。
8.v-once: 通过使用 v-once 指令,你也能执行一次性地插值,当数据改变时,插值处的内容不会更新

vue 常用的修饰符

.stop - 调用 event.stopPropagation(),禁止事件冒泡。
.prevent - 调用 event.preventDefault(),阻止事件默认行为。
.capture - 添加事件侦听器时使用 capture 模式
.self - 只当事件是从侦听器绑定的元素本身触发时才触发回调
.native - 监听组件根元素的原生事件
.once - 只触发一次回调
v-model 指令常用修饰符:
.number - 输入字符串转为数字
.trim - 输入首尾空格过滤
.lazy - 使双向数据绑定不起作用,且失去焦点时,触发 @change方法。

vue 自定义指令

全局指令: 通过 Vue.directive() 函数注册一个全局的指令。
局部指令:通过组件的 directives 属性,对该组件添加一个局部的指令,钩子函数: bind(绑定事件出发)、
inserted(节点插入时候触发)、update(组件内相关更新)、钩子函数参数: el、binding.
自定义指令5个生命周期(也叫钩子函数):
    1.bind:只调用一次,指令第一次绑定到元素时调用。在这里可以进行一次性的初始化设置。
    2.inserted:被绑定元素插入父节点时调用 (仅保证父节点存在,但不一定已被插入文档中)。
    3.update:被绑定于元素所在的模板更新时调用,而无论绑定值是否变化,通过比较更新前后的绑定值,可以忽略不必要的模板更新。
    4.componentUpdated:被绑定元素所在模板完成一次更新周期时调用。
    5.unbind:只调用一次,指令与元素解绑时调用。
自定义指令原理:
    1.在生成 ast 语法树时,遇到指令会给当前元素添加 directives 属性
    2.通过 genDirectives 生成指令代码
    3.在 patch 前将指令的钩子提取到 cbs 中,在 patch 过程中调用对应的钩子
    4.当执行指令对应钩子函数时,调用对应指令定义的方法

nextTick 原理和使用场景

$nextTick 是在下次 DOM 更新循环结束之后执行延迟回调,在修改数据之后使用 $nextTick,则可以在回调中
获取更新后的 DOM,使用场景:需要在视图更新之后,基于新的视图进行操作。

vue v-for 和v-if 同时使用的解决办法

1.将 v-for 放在外层嵌套 template,然后在内部进行 v-if 判断           
2.使用 compted 通过计算属性过滤掉列表中不需要显示的数据

Vue.set 改变数组和对象中的属性

在一个组件实例中,只有在 data 里初始化的数据才是响应的,Vue 不能检测到对象属性的添加或删除,没有在
data 里声明的属性不是响应的,所以数据改变了但是不会在页面渲染。
解决办法:使用 Vue.set(object, key, value) 方法将响应属性添加到嵌套的对象上

vue 生命周期

beforecreate (初始化界面前)
created      (初始化界面后)
beforemount  (渲染界面前)
mounted      (渲染界面后)
beforeUpdate (更新数据前)
updated      (更新数据后)
beforedestory(卸载组件前)
destroyed    (卸载组件后)

vuex

state       用来存储数据状态,不可以直接修里面的数据
mutaions    动态修改 store 中的状态或数据
action      改变 state 的值,可以进行异步操作
getter      过滤数据,计算属性
modules     项目模块过多,可以划分成多个模块

vuex 页面刷新数据丢失怎么解决

需要做 vuex 数据持久化一般使用本地存储的方案来保存数据可以自己设计存储方案也可以使用第三方插件
推荐使用 vuex-persist 插件,它就是为 Vuex 持久化存储而生的一个插件,不需要你手动存取 storage,
而是直接将状态保存至 cookie 或者 localStorage 中.

hash 和history 的区别

hash 模式有'#',history 模式没有刷新页面时,hash 模式可以正常加载到 hash 值对应的页面,
而 history 没有处理的话,会返回 404,一般需要后端将所有页面都配置重定向到首页路由兼容性,
hash 可以支持低版本浏览器。

vue 路由懒加载

路由懒加载的含义:把不同路由对应的组件分割成不同的代码块,然后当路由被访问的时候才加载对应组件;
实现:结合 Vue 的异步组件和 Webpack 的代码分割功能
   1.可以将异步组件定义为返回一个 Promise 的工厂函数 (该函数返回的 Promise 应该 resolve 组件本身)
     const Foo = () => Promise.resolve({ /* 组件定义对象 */ })
   2.在 Webpack 中,我们可以使用动态 import 语法来定义代码分块点 import('./Foo.vue') // 返回 Promise
   3.使用命名 chunk,和webpack中的魔法注释就可以把某个路由下的所有组件都打包在同个异步块 (chunk) 中
     chunkconst Foo = () => import(/* webpackChunkName: "group-foo" */ './Foo.vue')

router 和 route 的区别

router 为 VueRouter 的实例,相当于一个全局的路由器对象,里面含有很多属性和子对象。
route 相当于当前正在跳转的路由对象,可以从里面获取 name, params, path, query 等。

vue-router 有几种钩子函数?

全局钩子: beforeEach, afterEach 
组件钩子: beforeRouteEnter, beforeRouteUpdate, beforeRouteLeave
路由钩子: beforeEnter(to,from,next)=>{}

vue-router路由跳转方式

标签跳转: <router-link :to="{name:'home'}"></router-link>
JS跳转:  this.$router.push({path:'/home'})

vue 组件通信方式

1.父传子:父组件通过 props 传递数据给子组件,注:组件中的数据共有三种形式:data、props、computed
2.子传父:子组件通过 $emit() 给父组件传递事件,父组件通过v-on绑定事件,接收子组件传来的数据。
3.父传子孙:provide 和 inject 父组件定义 provide 方法 return 需要分享给子孙组件的属性,子孙组件使用 inject 选项来接收指定的我们想要添加在这个实例上的属性。
4.父子、兄弟、跨级:eventBus.js 这种方法通过一个空的 Vue 实例作为中央事件总线(事件中心), 用(emit)触发事件和(on)监听事件,巧妙而轻量地实现了任何组件间的通信。
5.通信插件:PubSub.js
6.vuex: vuex 是 vue 的状态管理器,存储的数据是响应式的。只需要把共享的值放到 vuex 中,其他需要的组件直接获取使用即可;

vue中父组件调用子组件的方法?

父组件利用 ref 属性操作子组件方法。
父:
    <child ref="childMethod"></child>
子:
    method: {
        test() {
            alert(1)
        }
    }
在父组件里调用 test,即 this.$refs.childMethod.test()

父组件给子组件 props 传参,子组件接收的6种方法

1. data 中变量  = this.props 里面的数据
2. watch 监听赋值
3. mounted 渲染完成后调用一个函数进行赋值
4. vuex
5. computed 计算属性,用法和 watch 类似,computed 是同步,watch 可以异步。
6. 父组件 v-if 触发渲染和销毁,子组件触发传参

vue 子组件调用父组件的方法

1.在子组件中通过 this.$parent.event 来调用父组件的方法
2.子组件用 $emit 向父组件触发一个事件,父组件监听这个事件。
3.父组件把方法传入子组件中,在子组件里直接调用这个方法。

vue 组件缓存 keep-alive

keep-alive 介绍:在组件切换过程中将状态保留在内存中,防止重复渲染 dom。
keep-alive 组件提供了 include 与 exclude 两个属性来允许组件有条件地进行缓存,二者都可以用逗号分隔字符串、
正则表达式或一个数组来表示。
keep-alive 提供了两个生命钩子,分别是 activated (组件被激活时调用)与deactivated (组件被移除时使用),
因为 keep-alive 会将组件保存在内存中,并不会销毁以及重新创建,所以不会重新调用组件的 created 等方法,
需要用 activated 与 deactivated 这两个生命钩子来得知当前组件是否处于活动状态。
keep-alive 是 Vue 内置的一个组件,可以使被包含的组件保留状态,避免重新渲染 ,其有以下特性:
一般结合路由和动态组件一起使用,用于缓存组件;提供 include 和 exclude 属性,两者都支持字符串或正则表达式,
include 表示只有名称匹配的组件会被缓存,exclude 表示任何名称匹配的组件都不会被缓存 ,其中 exclude 的
优先级比 include 高;对应两个钩子函数 activated 和 deactivated,当组件被激活时,触发钩子函数 
activated,当组件被移除时,触发钩子函数 deactivated。

ref 的作用?

1.获取 dom 元素例: this.$refs.box
2.获取子组件中的 data 例: this.$refs.box.msg
3.调用子组件中的方法例: this.$refs.box.open() 

vue-loader 是什么?用途有哪些?

解析后缀 .vue 文件的一个加载器。
用途:js 可以写es6、style 样式可以 scss 或 less、template 等。

scss 是什么?在 vue.cli 中的安装使用步骤?有哪几大特性?

使用步骤:
        1.先装 css-loader、node-loader、sass-loader 等加载器模块;
        2.在 build 目录找到 webpack.base.config.js,在 extends 属性中加一个拓展 .scss;
        3.在同一个文件,配置一个 module 属性;
        4.然后在组件的 style 标签加上 lang 属性 ,例如:lang=”scss”;
特性:
        1.可以用变量,例如($变量名称=值);
        2.可以用混合器;
        3.可以嵌套;

scoped 穿透

在做项目中,会遇到这么一个问题,即:引用了第三方组件,需要在组件中局部修改第三方组件的样式,而又不想去除
scoped属性造成组件之间的样式污染。那么有哪些解决办法呢?
  1.不使用scopeds省略(不推荐);
  2.在模板中使用两次style标签。
  3.scoped穿透:/deep/ >>>
例: 
   PostCSS:使用 JS 插件转换 CSS 的工具。这些插件可以支持变量和 mixins,转换将来的 css 语法,
   内联图像等。Autoprefixer 是一种非常流行的 PostCSS 插件。

vue 首屏加载优化

1.把不常改变的库放到 index.html 中,通过 cdn 引入然后找到 build/webpack.base.conf.js 文件,在 module.exports = { } 中添加以下代码:
    externals: {
        'vue': 'Vue',
        'vue-router': 'VueRouter',
        'element-ui': 'ELEMENT'
    },
2.vue 路由懒加载
3.不生成 map 文件,找到 config/index.js 文件,修改为 productionSourcceMap:false,
4.vue 组件尽量不要全局引入
5.开启 gzip 压缩这个优化是两方面的,前端将文件打包成 .gz 文件,然后通过 nginx的配置,让浏览器直接解析 .gz 文件。

防抖和节流

防抖(debounce):在事件被触发n秒后再执行回调,如果在这n秒内又被触发,则重新计时。
节流(throttle):规定在一个单位时间内,只能触发一次函数,如果这个单位时间内触发多次函数,只有一次生效。

Eventloop 事件循环机制

1.将"执行栈"最开始的同步代码(宏任务)执行完成;
2.检查是否有微任务。如有则执行所有的微任务;
3.取出"任务队列"中事件所对应的回调函数(宏任务)进入”执行栈“并执行完成;
4.再检查是否有微任务,如有则执行所有的微任务;
5.主线程不断重复上面的 3、4 步骤;
宏任务:同步代码,setTimeout,setInterval,requestAnimationFrame,I/O,UI rendering
微任务:process.nextTick,promise callback,MutationObserver
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,569评论 4 363
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,499评论 1 294
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,271评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,087评论 0 209
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,474评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,670评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,911评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,636评论 0 202
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,397评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,607评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,093评论 1 261
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,418评论 2 254
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,074评论 3 237
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,092评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,865评论 0 196
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,726评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,627评论 2 270