面试开发全靠它了---史上最强vue总结

vue框架篇

vue的核心是什么

vue是一套构建用户界面的MVVM框架。vue的核心值关注视图层。

核心思想:

  • 数据驱动(视图的内容随着数据的改变而改变)
  • 组件化(可以增加代码的复用性,可维护性,可测试性,提高开发效率,方便重复使用,体现了高内聚低耦合)

vue单页面的优缺点

优点:

  1. 数据驱动视图,对真实dom进行抽象出virtual dom(本质就是一个js对象),并配合diff算法,响应式和观察者、异步队列等手段以最小代价更新dom,渲染页面。
  2. 组件化,组件用单文件的形式进行代码的组织编写,使得我们可以在一个文件里编写html/css(scoped属性配置css隔离)/js,并且配合vue-loader之后,支持更强大的预处理器等功能
  3. 强大且丰富的API提供一系列的api能满足业务开发中各类需求
  4. 由于采用虚拟dom,让vue ssr(服务器端渲染) 先天不足
  5. 生命周期钩子函数,选项式的代码组织方式,写熟了还是蛮顺畅的,但是仍然有优化空间(vue3 composition-api)
  6. 生态好,社区活跃

缺点:

  1. 由于底层基于Object.defineProperty实现响应式,而这个api本身不支持IE8及以下浏览器
  2. csr的先天不足,首屏性能问题(白屏)
  3. 由于百度等搜索引擎爬虫无法爬取js中的内容,故spa先天就对SEO优化不好。

请详细说下你对vue生命周期的理解?

总共分为8个阶段创建前/后,载入前/后,更新前/后,销毁前/后。总结起来八个字:创建 加载 更新 销毁

创建前/后: 在beforeCreate阶段,vue实例的挂载元素el和数据对象data都为undefined,还未初始化。在created阶段,vue实例的数据对象data有了,el为undefined,还未初始化。

载入前/后:在beforeMount阶段,vue实例的$el和data都初始化了,但还是挂载之前为虚拟的dom节点,data.message还未替换。在mounted阶段,vue实例挂载完成,data.message成功渲染。

更新前/后:当data变化时,会触发beforeUpdate和updated方法

销毁前/后:在执行destroy方法后,对data的改变不会再触发周期函数,说明此时vue实例已经解除了事件监听以及和dom的绑定,但是dom结构依然存在

vue中组件如何通讯

父子组件:propsthis.$emit(自定义事件名,要发送的数据)
自定义事件:event.$on event.$off event.$emit Vue 实例自带api,可以定义一个全局vue实例。
还有 vuex插件 通讯。

请简述vue的单向数据流

父级prop的更新会向下流动到子组件中,每次父组件发生更新,子组件所有的prop都会刷新为最新的值

数据从父组件传递给子组件,只能单向绑定,子组件内部不能直接修改父组件传递过来的数据(可以使用data和computed解决)

vue双向绑定的原理

双向绑定就是:数据变化更新视图,视图变化更新数据

vue数据双向绑定是通过数据劫持和观察者模式来实现的。

数据劫持: object.defineproperty 它的目的是:当给属性赋值的时候,程序可以感知到,就可以控制改变属性值

观察者模式: 当属性发生改变的时候,使用该数据的地方也发生改变

双向数据绑定v-model的实现原理

  • input 元素的 value = this.name
  • 绑定input事件this.name = $event.target.value
  • data更新触发re-render

vue中常用的修饰符有哪些

// 输入框修饰符:
.lazy 改变后触发,光标离开input输入框的时候值才会改变
.number 将输出字符串转为number类型
.trim 自动过滤用户输入的收尾空格

// 事件修饰符
.stop 阻止点击事件冒泡,相当于原生js中的event.stopPropagation()
.prevent 防止执行预设的行为,相当于原生js中的event.preventDefault()
.capture 添加事件侦听器时使用事件捕获模式,就是谁有改事件修饰符,就先触发谁。
.self 只会触发自己范围内的事件,不包括子元素
.once 只执行一次

// 键盘修饰符
.enter 回车键
.tab 制表键
.esc 返回键
.space 空格键
.up 向上键
.down 向下键
.left 向左键
.right 向右键

// 系统修饰符
.ctrl
.alt
.shift
.meta

vue中指令有哪些?

  • v-for: 循环数组,对象,字符串,数字
  • v-on: 绑定事件监听
  • v-bind: 动态绑定一个或者多个属性
  • v-model: 表单控件或者组件上创建双向绑定
  • v-if v-else v-else-if 条件渲染
  • v-show: 根据表达式真假,切换元素的display
  • v-html: 更新元素的innerHtml
  • v-text: 更新元素的textcontent
  • v-pre: 跳过这个元素和子元素的编译过程
  • v-clock:这个指令保持在元素上知道关联实例结束编译
  • v-once 只渲染一次

v-if 和 v-show 的区别

v-if 是根本不会渲染DOM节点。
v-show 是基于css的display属性值对DOM进行显示隐藏的。

v-if 与 v-for 优先级

首先不要把v-if与v-for用在同一个元素上,原因:v-for比v-if优先,如果每一次都需要遍历整个数组,将会影响速度,尤其是当之需要渲染很小一部分的时候。

vue循环的key作用

  • 必须用key,且不能是index和random
  • diff算法中通过tag和key来判断,是否是sameNode
  • 减少渲染次数,提升渲染性能。

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

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

如何定义一个过滤器

过滤器本质就是一个有参数返回值的方法

new Vue({
	filters: {
		myCurrency: function(myInput){
			return 处理后的数据
		}
	}
})

// 使用方法
<span>{{ 表达式 | 过滤器 }}</span>

过滤器高级用法:可以指定参数,告诉过滤器按照参数进行数据的过滤

什么是计算属性

计算属性是用来声明时的描述一个值依赖了其他的值,当它依赖的这个值发生改变时,就更新 DOM

当在模板中把数据绑定到一个计算属性上时, vue 会在它依赖的任何值导致该计算属性改变时更新 DOM
每个计算属性都包括一个 getter 和 setter,读取时触发 getter,修改时触发 setter

计算属性与watch区别

Computed watch 区别就是 computed 的缓存功能,当无关数据数
据改变时,不会重新计算,直接使用缓存中的值。计算属性是用来声明
式的描述一个值依赖了其他的值,当所依赖的值后者变量发生变化时,
计算属性也跟着改变,
Watch 监听的是在 data 中定义的变量, 当该变量变化时, 会触发 watch
中的方法

watch怎么深度监听对象变化

new Vue({
	el: "#first",
	data: { msg: {name: 'zz'} },
	watch:{
		msg: {
			handler(newMsg, oldMsg){
				console.log(newMsg);
			},
			immediate: true,
			deep: true
		}
	}
})

何时需要使用beforeDestory

  • 解除自定义事件 event.$off
  • 清除定时器
  • 解绑自定义的DOM事件,如window.onscroll等

在vue项目中如何引入第三方库(比如jQuery)?有哪些方法可以做到?

1.绝对路径直接引入。

在index.html中用`script`引入
<script src="./static/jquery-1.12.4.js"></script>
然后在webpack中配置external
externals:{'jquery': 'jQuery'}
在组件中使用时import
import $ from 'jquery'

2.在webpack中配置alias

resolve: { 
	extensions: ['.js','.vue','.json'], 
	alias: { 
		'@': resolve('src), 
		'jquery': resolve('static/jquery-1.12.4.js') 
	} 
}

然后在组件中import

3.在webpack中配置plugins

plugins: [new webpack.ProvidePlugin({ $: 'jquery' })]

全局使用,但在使用eslint情况下会报错,需要在使用了$的代码前添加 /*eslint-disable*/ 来去掉eslint的检查。

vue 高级特性

自定义v-model

参考官方文档:自定义组件的v-model

谈谈$nextTick的作用

Vue 是异步渲染,data改变之后,DOM不会立刻渲染,$nextTick会在DOM渲染之后被触发,以获取最新的DOM节点。

slot特性

  • 基本使用
  • 作用域插槽(不常用,但是需要知道)
  • 具名插槽

动态、异步组件

用法::is = "component-name"
异步组件: 使用时,再去加载组件 ()=> import(./components/tabs)

keep-alive

  • 缓存组件,频繁切换组件,不需要重复渲染。适用于Vue常见性能优化

mixin的优缺点

  • 多个组件有相同的逻辑,抽离出来

mixin 并不是完美的解决方案,会有一些问题。vue3 提出的Composition API 旨在解决这些问题。

  • 变量来源不明确,不利于阅读
  • 多mixin可能造成命名冲突
  • mixin和组件可能出现多对多的关系,复杂度较高。

Vue原理

  • 面试官为何要考察原理,又用不到?

知其然知其所以然,各行各业通用的道理
了解原理,才能应用的更好(竞争激烈,择优录取)
大厂造轮子(有钱有资源,业务定制,技术KPI)

  • 面试中如何考察Vue原理?以何种方式?

考察重点,而不是考察细节。掌握好2/8原则。
和使用相关联的原理,例如:vdom、模板渲染
整体流程是否全面?热门技术是否有深度?

响应式原理(数据驱动视图)

  • 核心API,Object.defineProperty(vue3使用Proxy,但是proxy兼容性不好,且无法polyfill)

Object.defineProperty实现响应式

  • 监听对象,监听数组
  • 复杂对象,深度监听
// 更新视图方法
function updateView(){
	console.log('视图更新');
}

// 重新定义数组原型
const oldArrayProperty = Array.prototype;

// 创建新对象,原型指向oldArrayProperty,再扩展新方法不会影响原型
const arrProto = Object.create(oldArrayProperty);

['push','pop','shift','unshift','splice'].forEach(methodName=>{
	arrProto[methodName] = function(){
		// 更新视图
		updateView()
		
		// 调用原生方法
		oldArrayProperty[methodName].call(this, ...arguments)
		// Array.prototype.push.call(this, ...arguments);
	}
})

// 重新定义属性,监听起来
function defineReactive(target, key, value){
    // 深度监听
    observer(value);
    
	// 核心API
	Object.defineProperty(target, key, {
		get(){
			return value
		},
		set(newValue){
			if(newValue !== value){
				// 深度监听
				observer(newValue)
			
				// 设置新值
				// 注意value一直在闭包中,此处设置完之后,再get时获取的是最新的值
				value = newValue
				
				// 触发更新视图
				updateView()
			}
		}
	})
}

// 监听对象属性
function observer(target){
	if(typeof target !== 'object' || target === null){
		// 不是对象或数组
		return target;
	}
	
	// 深度监听数组
	if(Array.isArray(target)){
		target.__proto__ = arrProto
	}
	
	// 重新定义各个属性(for in 也可以遍历数组)
	for(let key in target){
		defineReactive(target, key, target[key])
	}
}



const data = {
	name: 'krik',
	age: 18,
	info: {
		address: '豫'
	},
	nums: [10,20,30]
}

// 监听数据
observer(data)

// 测试
data.name = 'ime'
data.age = 19


data.x = '100' // 新增属性,监听不到,所以有Vue.set
delete data.name // 删除属性,监听不到,所以有Vue.delete
data.info.address = '上海' // 深度监听
data.nums.push(4)   // 监听数组

几个缺点:

  • 深度监听,需要递归到底,一次性计算量大
  • 无法监听新增属性/删除属性(Vue.set 和 Vue.delete)
  • 无法监听数组,需要特殊处理

虚拟DOM和diff算法

虚拟DOM库: (虚拟DOM库)[https://github.com/snabbdom/snabbdom]

  • 用JS模拟DOM结构
  • 新旧vnode对比,得出最小的更新范围,最后更新DOM
  • 数据驱动视图模式下,有效控制DOM操作

diff算法:是vdom中最核心,最关键的部分
diff算法能在日常使用vue react 中提现出来(如key)
diff算法实现代码细节

diff即对比,是一个广泛的概念,如linux diff命令,git diff等
两个js对象也可以做diff, 如https://github.com/cujojs/jiff

两棵树做diff,如这里的vdom diff

  • 树diff的时间复杂度 O(n^3)
  • 第一,遍历tree1; 第二,遍历tree2,第三,排序
  • 问题:1000个节点,要计算1亿次,算法不可用。

前端大佬针对前面的问题,提出了个解决办法:优化时间复杂度到O(n)

  • 只比较同一层级,不跨级比较
  • tag 不相同,则直接删除重建,不再深度比较
  • tag和key两者都相同,则认为是相同节点,不做深度比较

snabbdom 源码解读(细节不重要,了解流程即可):

  • patchVnode
  • addVnodes 和 removeVnodes
  • updateChildren

vdom核心概念很重要:h, vnode, patch, diff, key等
vdom存在的价值:数据驱动视图,控制DOM操作

模板编译

vue的模板不是html,有指令,插值,JS表达式,它到底是什么?

面试官不会直接问,但是会通过"组件渲染和更新过程"考察

前置知识:JS的with语法

// 使用with,能改变{}内自由变量的查找方式
// 将{}内自由变量,当做obj的属性来查找,找不到就会报错
// with 要慎用,它打破了作用域规则,易读性变差
const obj = {a: 1, b: 2}
console.log(obj.c)  // undefined
with(obj){
	console.log(a)
	console.log(b)
	console.log(c) // 会报错 !!!
}

vue template complier 将模板编译成render函数,执行render函数生成vnode
基于vnode再执行patch和diff

使用webpack vue-loader, 会在开发环境下编译模板(重要)

描述组件渲染/更新过程

  • 响应式原理(数据驱动视图)
  • 模板编译:模板到render函数,再到vnode
  • vnode diff算法

初次渲染过程=》更新过程=》异步渲染

初次渲染过程:解析模板为render函数(或在开发环境已完成,vue-loader),触发响应式,监听data属性getter和setter
执行render函数生成vnode,patch(elem,vnode)

更新过程:修改data,触发setter(此前getter中已被监听),重新执行render函数生成newVnode,patch(vnode,newValue)

前端路由原理

稍微复杂一点的SPA,都需要路由。vue-loader也是vue全家桶的标配之一。属于"和日常使用相关联的原理",面试常考。

路由模式:hash模式和history模式

// http://127.0.0.1:8081/01-hash.html?a=100&b=200#/aaa
location.protocol  // http:
location.hostname  // 127.0.0.1
location.host // 127.0.0.1:8081
location.port //8081
location.pathname // /01-hash.html
location.search // ?a=100&b=200
location.hash // #/aaa

hash 变化会触发网页跳转,即浏览器的前进、后退
hash 变化不会刷新页面,SPA必须的特点
hash 永远不会提交到server端,全权由前端去控制

前端实现hash路由

  • window.onhashchange
window.onhashchange = (event)=>{
	console.log('old url:',event.oldURL);
	console.log('new url:',event.newURL);
	
	console.log('hash:', location.hash);
}

document.addEventListener('DOMContentLoaded', ()=>{
	console.log('hash:', location.hash);
})

document.getElementById('#change-hash-btn').addEventListener('click', ()=>{
	location.href = '#/detail/id'
})

前端实现history路由

  • history.pushState
  • window.onpopstate
// 页面初次加载,获取path
document.addEventListener('DOMContentLoaded', ()=>{
	console.log('load', location.pathname);
})

// 打开一个新的路由
// 【注意】用pushState方式,浏览器不会刷新页面
document.getElementById('change-hash-btn').addEventListener('click', ()=>{
	const state = { name: 'page1' }
	console.log('切换路由到', 'page1');
	history.pushState(state, '', 'page1')
})


// 监听浏览器前进后退
window.onpopstate = (event) => {
	console.log('onpopstate', event.state, location.pathname);
}

两者选择
to B 的系统推荐使用hash,简单易用,对URL规范不敏感。
to C 的系统,可以考虑选择H5 history, 但需要服务端支持

能选择简单的,就别用复杂的,要考虑成本和收益。

vue路由篇

vue路由的实现

前端路由就是更新视图,但不请求页面。

利用锚点完成切换,页面不会刷新,官网推荐用vue-router.js来引入路由模块

定义路由,使用component进行路由映射组件,用name导航到对应路由。
创建router实例,传入routes配置,创建和挂载根实例,用router-link设置路由跳转。

vue中路由跳转方式(声明式/编程式)

Vue 中路由跳转有两种,分别是声明式和编程式

用 js 方式进行跳转的叫编程式导航 this.$router.push()方法

用 router-link 进行跳转的叫声明式 router-view 路由出口,路由模板显示的位置

路由中 name 属性有什么作用?
在 router-link 中使用 name 导航到对应路由
使用 name 导航的同时,给子路由传递参数

Route和router的区别

  1. router是VueRouter的一个对象,通过Vue.use(VueRouter)和VueRouter构造函数得到一个router的实例对象,这个对象中是一个全局的对象,他包含了所有的路由包含了许多关键的对象和属性。
  2. route是个跳转的路由对象,每个路由都会有一个route对象,是一个局部对象,可以获取对应的name,path,params,query等

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

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

用法上:query用path引入,params用name引入,接收参数都是类似的,分别是this. r o u t e . q u e r y . n a m e 和 t h i s . route.query.name和this. route.query.namethis.route.params.name

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

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

  • 全局守卫:beforeEach(to,from,next)和afterEach(to, from)
  • 路由独享守卫:beforeEnter
  • 组件内的守卫:路由进入/更新/离开之前 =》beforeRouterEnter/update/leave

对vue中keep-alive的理解

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

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

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

vuex 状态管理篇

vuex是什么?怎么使用?在那种场景下使用。

Vuex是一个专为vue.js应用程序开发的状态管理模式,通过创建一个集中的数据存储,方便程序中的所有组件进行访问,简单来说,vuex是vue的状态管理工具。

vuex有五个属性 stategettersmutationsactionsmodules

state就是数据源存放地,对应一般的vue对象的datastate里面存放的数据是响应式的,state数据发生改变,对应这个数据的组件也会发生改变,用this.$store.state.xxx调用。

getters 相当于store的计算属性,主要是对state中数据的过滤,用this.$store.getters.xxx调用。

mutations处理数据逻辑的方法全部放在mutations中,当触发事件想改变state数据的时候使用mutations,用this.$store.commit调用。给这个方法添加一个参数,就是mutation的载荷(payload)

actions 异步操作数据,但是是通过mutation来操作,用this.$store.dispatch来触发,actions也支持载荷

使用场景:组件之间的状态,登录状态,加入购物车,音乐播放

Vuex引入流程:下载vuex
在src下创建 store 以及 index.js
引入 vue 和 vuex, 使用 vuex ,导出实例对象
在 main.js 中引入,在.vue 文件中使用

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

vuex怎么请求异步数据

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

vuex中 action 如何提交给 mutation

action函数接收一个与store实例具有相同方法和属性的context对象
可以调用context.commit 提交一个mutation或者通过context.state和context.getters获取state和getters

vuex的state特性是?

state就是数据源的存放地,state里面的数据是响应式的,state中的数据改变,对应这个数据的组件也会发生改变。
state通过mapstate把全局的state和getters映射到当前组件的计算属性中

vuex的 Getter 特性是?

Getter可以对state进行计算操作,它就是store的计算属性。

Getter可以在多个组件之间复用,如果一个状态只在一个组件内使用,可以不用getters

vuex的 Mutation 特性是?

更改vuex store中修改状态的唯一办法就是提交mutation,可以在回调函数中修改store中的状态

vuex的actions特性是?

Action类似于mutation,不同的是action提交的是mutation,不是直接变更状态,可以包含任意异步操作。

vuex的优势

优点: 解决了非父子组件的通信,减少了ajax请求次数,有些可以直接从state中获取

缺点:刷新浏览器,vuex中的state会重新变为初始状态,解决办法是使用vuex插件vuex-persistedstate(数据持久化)

vue3.x版本

说说你对proxy的理解

vue的数据劫持有两个缺点:

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

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

vue3.0 如何变得更快的?(底层,源码)

  • diff方法优化
  • vue2.x中的虚拟dom进行全量的对比,而在vue3.0中新增了静态标记(patchFlag):在与上次虚拟结点进行对比的时候,值对比带有patchflag的节点,并且可以通过flag的信息得知当前节点要对比的具体内容化,hoistStatic 静态提升
  • vue2.x:无论元素是否参与更新,每次都会重新创建
  • vue3.x: 对不参与更新的元素,只会被创建一次,之后会在每次渲染时候被不停的复用。
  • cacheHandlers 事件监听器缓存

默认情况下onclick会被视为动态绑定,所以每次都会去追踪它的变化,但是因为是同一个函数,所以没有追踪变化,直接缓存起来复用即可。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值