【知识总结】前端高频Vue面试题合集

460 阅读8分钟

v-if 和v-show的区别

共同点

  • 都能控制元素的显示和隐藏

不同点

  • v-show:通过css的display:none控制隐藏,只会编译一次
  • v-if:动态的向DOM树添加或者删除DOM元素,若初始值为false,就不会编译了

v-if不停的销毁和创建比较消耗性能。所以如果要频繁切换某节点,使用v-show(切换开销比较小,初始开销较大);如果不需要频繁的切换某节点使用就使用v-if(初始渲染开心较小,切换开销较大)

v-if和v-for的优先级

  • v-for优先于v-if被解析。
  • 如果同时出现,每次渲染都会先执行循环再判断条件,无论如何循环都不可避免,浪费了性能。要避免这种情况,则在外层嵌套template,在这一层进行v-if判断,然后在内部进行v-for循环。
  • 如果条件出现在循环内部,可通过计算属性提前过滤掉那些不需要显示的项。

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

如果data是一个函数的话,这样每次复用一次组件,就会返回一个新data,类似于给每个组件实例创建一个私有的数据空间,让各个组件实例维护各自的数据。

而单纯的写成对象形式,就使得所有组件实例公用一份data,就会造成一个变了全部都变的结果。所以说vue组件的data必须是函数。

js本身的面向对象编程也是基于原型链和构造函数,应该会注意原型链上添加一般都是函数方法,而不会去添加一个对象。

vuex中actions与mutations的区别

actions

  • 用于通过提交mutation改变数据
  • 会默认将自身封装为一个promise
  • 可以包含任意的异步操作

mutations

  • 通过提交commit改变数据
  • 只是一个单纯的函数
  • 不要使用异步操作,会导致变量不能追踪

如何在vuex中使用异步修改

在调用vuex中的方法action的时候,使用promise实现异步修改

const actions = {
	asyncLogin({commit},n){
		return new Promise(resolve=>{
			setTimeout(()=>{
				commit(type.UserLogin,n);
				resolve();
			},3000)
		})
	}
}

vue有哪些组件间的通信方式

父子组件通信、隔代组件通信、兄弟组件通信

方法一: props/$emit

父组件A通过props的方式向子组件B传递,B to A通过B组件中的$emit,A组件中v-on的方式实现。

总结:父组件通过props向下传递数据给子组件。(子组件的数据共有三种形式:data、props、computed);子组件通过events给父组件发送消息,实际上就是子组件把自己的数据发送到父组件。

方法二:emit/on

这种方式通过一个空的vue实例作为中央事件总线(事件中心),用它来触发事件和监听事件,巧妙而轻量地实现了任何组件间的通信,包括父子、兄弟、跨级。当我们的项目比较大时,可以选择更好的状态管理解决方案vuex。

var App = new Vue();
App.$emit(事件名,数据);
App.$on(事件名,data=>{});

方法三:vuex与localStorage

vuex是vue的状态管理器,存储的数据是响应式的,但是并不会保存起来,刷新之后就会回到初始状态,具体做法应该在vuex里,数据改变的时候把数据拷贝一份保存到localStorage里面,刷新之后,如果localStorage里有保存的数据,取出来再替换store里的state。

vue中双向数据绑定是如何实现的

  1. vue.js 采用的是数据劫持结合发布订阅模式的方式。
  2. 通过Object.defineProperty()来劫持各个属性的setter和getter。
  3. 在数据变动时发布消息给订阅者,触发相应的监听回调。
var obj = {};
Object.defineProperty(obj,'name',{
	get:function(){
		console.log('我被获取了');
		return val;
	},
	set:function(){
		console.log
	}
})
obj.name = 'fei'; //在给obj设置name属性的时候,出发了set方法
var val =obj.name; //在得到obj的name属性,会触发get方法

单页面应用和多页面应用区别及优缺点

单页面应用(SPA),通俗点说就是指只有一个主页面的应用,浏览器一开始要加载所有必须的html、css、js。所有的页面内容都包含在这个所谓的主页面中。但在写的时候,还是会分开写,然后在交互的时候由路有程序动态加载,单页面的页面跳转,仅刷新局部资源。多应用于pc端。

多页面(MPA),就是指一个应用中有多个页面,页面跳转时整页刷新。

单页面优点

  • 用户体验好,快。内容的改变不需要重新加载整个页面,基于这一点spa对服务器压力较小
  • 前后端分离
  • 页面效果会比较炫酷(比如切换页面内容时专场动画)

单页面缺点

  • 不利于seo
  • 导航不可用,如果一定要导航需要自行实现前进、后退
  • 初次加载时耗时多
  • 页面复杂度提高很多

vue事件的修饰符

  • .stop:等同于event.stopPropagation(),防止事件冒泡
  • .prevent:等同于event.proventDefault(),防止执行预设的行为
  • .capture:与事件冒泡的方向相反,事件捕获由外到内
  • .self:只会触发自己范围内的事件,不包含子元素
  • .once:只触发一次
  • .passsive:passive表示listener函数不会调用preventDefault()

passive主要用于移动端的scroll事件,来提高浏览器相应速度,提升用户体验。因为passive=true等于提前告诉浏览器,touchstart和touchmove不会阻止默认事件,手刚开始触摸,浏览器就可以立刻给予响应。

vue的两个核心是什么

数据驱动

在vue中,数据的改变会驱动视图的自动更新。传统的做法是需要手动改变dom来使得视图更新,而vue只需要改变数据。

组件

组件化开发,优点很多,可以很好的降低数据之间的耦合度。将常用的代码封装组件之后,就能高度的复用,提高代码的可重用性。一个页面/模块可以由多个组件所组成。

v-model的原理

v-model本质是一个语法糖,可以看成是value + input 方法的语法糖。可以通过model属性的prop和event属性来进行自定义。

原生的v-model,会根据标签的不同生成不同的事件和属性。

v-model在内部为不同的输入元素使用不同的属性并抛出不同的事件,如下:

  1. text和textarea元素使用value属性和input事件
  2. checkbox和radio使用checked属性和change事件
  3. select字段将value作为prop并将change作为事件

nextTick的实现原理是什么

在下次DOM更新循环结束之后执行延迟回调。nextTick主要是使用了宏任务和微任务。根据执行环境分别尝试采用

  • promise
  • mutationObserver
  • setImmediate
  • 如果以上方法都不行则采用setTimeout

定义了一个异步方法,多次调用nextTick会将方法存入队列中,通过这个异步方法清空当前队列。

谈谈Computed和watch

computed本质是一个具备缓存的watcher,依赖的属性发生变化就会更新视图。

适用于计算比较消耗性能的计算场景。当表达式过于复杂时,在模版中放入过多逻辑会让模版难以维护,可以将复杂的逻辑放入计算属性中处理。

watch没有缓存性,更多的是观察的的作用,可以监听某些数据执行回调。

当我们需要深度监听对象中的属性时,可以打开deep:true选项,这样便会对对象中的每一项进行监听。

这样会带来性能问题,优化的话可以使用字符串形式监听,如果没有写到组件中,不要忘记使用unWatch手动注销。

v-text与{{}}与v-html的区别

  • {{}}将数据解析为纯文本,不能显示输出html
  • v-html可以渲染输出html
  • v-text将数据解析为纯文本,不能输出真正的html,与花括号的区别是在页面加载时不显示双花括号

v-text:操作网页元素中的纯文本内容。{{}}是它的另一种写法。

v-text与{{}}的区别:v-text与{{}}等价,{{}}叫模版插值,v-text叫指令。有一点区别就是,在渲染的数据比较多的时候,可能会把大括号显示出来,俗称屏幕闪动。

v-on可以绑定多个方法吗

可以,如果绑定多个事件,可以用键值对的形式(事件类型:事件名);如果绑定的是多个相同事件,直接用逗号分隔就行。

vue中路有跳转方式

  • 声明式:用router-link进行跳转,router-view路由出口,路由模版显示的位置。
  • 编程式:this.$router.push()

路由的name属性有什么作用:

  • 在router-link中使用name导航到对应路由
  • 使用name导航的同时,给子路由传递参数

vue跨域的解决方式

  • 后台更改header
  • 使用jq提供jsonp
  • 用http-proxy-middleware(配置代理服务器的中间件)

vue的生命周期请简述

vue的生命周期就是vue实例创建到实例销毁的过程。期间会8个钩子函数的调用

  • beforeCreate:创建实例
  • created:创建完成
  • beforeMount:开始创建模版
  • mounted:创建完成
  • beforeUpdate:开始更新
  • updated:更新完成
  • beforeDestroy:开始销毁
  • destroyed:销毁完成

DOM渲染在哪个生命周期阶段内完成

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

vue路由模式hash和histroy,简单讲一下

Hash模式地址栏有#,history没有,history模式下刷新,会出现404情况,需要后台配置。

使用JavaScript来对loaction.hash进行赋值,改变URL的hash值。可以使用hashchange事件来监听hash值的变化。

HTML5提供了History API来实现URL的变化。其中最重要的API有以下两个:history.pushState()history.replaceState()。这两个API可以在不进行刷新的情况下,操作浏览器的历史记录。唯一不同的是,前者新增一个历史记录,后者直接替换当前的历史记录。

vue路由传参的两种方式params和query区别

动态路由也可以叫做路由传参,就是根据不同的选择在同一组件渲染不同的内容。

用法上:query用path引入,params用name引入,接收参数都是类似的,分别是this.$route.query.namethis.$route.params.name

展示上:params类似于post,query类似与get,也就是安全问题。params传值相对于更安全一点,query通过url传参,刷新页面还在,params刷新页面不在了。

vue的路由钩子函数/路由守卫有哪些

全局守卫

beforeEach(to, from, next)after(to,from)

路由独享守卫

beforeEnter

组件内的守卫

路由进入/更新/离开之前 beforeRouterEnter/update/leave

对vue中keep-alive的理解

概念:keep-alive是vue的内置组件,当它动态包裹组件时,会缓存不活动的组件实例,它自身不会渲染成一个DOM元素也不会出现在父组件链中。

作用:在组件切换过程中将状态保留在内存中,防止重复渲染DOM,减少加载时间以及性能消耗,提高用户体验。

生命周期函数:Activated在keep-alive组件激活时调用,deactivated在keep-alive组件停用时调用。

如何让组件中的css在当前组件生效

在styled中加上scoped

vue组件中的data为什么是函数

Data是一个函数时,每个组件实例都有自己的作用域,每个实例相互独立,不会相互影响。如果时引用类型(对象),当多个组件公用一个数据源时,一处数据改变,所有的组件数据都会改变,所以要利用函数通过return返回对象的拷贝,让每个实例都有自己的作用域,相互不影响。

vuex流程

在vue组件里面,通过dispatch来触发actions提交修改数据的操作,然后通过actions的commit触发mutations来修改数据,mutations接收到commit的请求,就会自动通过mutate来修改state,最后由store出发每一个调用它的组件的更新。

vuex怎么请求异步数据

  1. 首先在state中创建变量
  2. 然后在action中调用封装好的axios请求,异步接收数据,commit提交给mutations
  3. mutations中改变state中的状态,将从action中获取到的值赋值给state

vue在created和mounted这两个生命周期中请求数据有什么区别

看实际情况,一般在created(或beforeRouter)里面就可以,如果涉及到需要页面加载完成之后的话就用mounted。

在created的时候,视图中的html并没有渲染出来,所以此时如果直接去操作html的dom节点,一定找不到相关的元素,而在mounted中,由于此时html已经渲染出来的了,所以可以直接操作dom节点。

说说你对proxy的理解

vue的数据劫持有两个缺点

  • 无法监听通过索引修改数组的值的变化
  • 无法监听object对象的值的变化,所以vue2.x中才会有$set属性的存在

proxy是es6中推出的新api,可以弥补以上两个缺点,所以vue3.x版本用proxy替换object.defineProperty