## 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
- 3.子传父:子组件通过 $emit() 给父组件传递事件,父组件通过v-on绑定事件,接收子组件传来的数据。
- 2.父传子孙: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”;
+ 特性:
+ 可以用变量,例如($变量名称=值);
+ 可以用混合器;
+ 可以嵌套;
+ 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
网友评论