高频
vue是什么?有什么特点?
vue是一个创建单页应用的Web开源框架,基于数据驱动MVVM,实时响应数据更新,并动态渲染DOM。
React与Vue的区别?
- 数据变化的原理不同,vue通过数据劫持结合发布者订阅者模式实现数据的精准更新, 不需要特别的优化就能达到很好的性能;React通过单向数据流刷新页面,可能导致大量不必要的VDOM的重新渲染。
- 在Vue中我们组合不同功能的方式是通过mixin,而在React中我们通过HOC(高阶组件)。
什么是SPA(单页面应用)?
它通过动态重写当前页面来与用户交互,避免了页面之间切换打断用户体验。
有没有做过组件封装?
比如做小游戏时会封装一些Toast和Dialog,放到Common文件夹下。 将简单的组件抽离出来还是蛮有必要的。
hash和history模式是什么?
带#号,后面就是 hash 值的变化。改变后面的 hash 值,它不会向服务器发出请求,因此也就不会刷新页面。 一旦 URL 的哈希部分发生变化,它就会根据新的哈希值找到对应的路由配置,并动态地加载所需的组件并更新页面内容,形成页面无刷新的效果。 Vue 路由会创建一个全局的监听器,监听浏览器的 hashchange 事件。缺点是地址栏不优雅,有#存在,不利于seo,记忆困难。
History 模式依赖 HTML5 的 History API,它通过修改浏览器的历史记录来实现前端路由的切换。 但需要服务器配置支持,确保在每个路由都返回正确的页面,即使在刷新页面或直接访问某个子路由时也能正常工作。
- 缺点:history模式,兼容性较差,刷新页面,页面会404,需要服务器端配置支持
- 优点:地址栏更优雅,方便记忆,有利于有seo
vue的双向绑定原理是什么?
- vue2的双向数据绑定是通过数据劫持结合发布者订阅者模式的方式来实现。 通过object.defineProperty来劫持各个属性的setter,getter,在数据变化时发布消息给订阅者,触发相应的监听回调来渲染视图。
- Vue3利用Proxy代理来处理双向数据绑定。可以直接监听对象而非属性,可以直接监听数组的变化。
在 get 方法中收集订阅者(computed,watch也会有订阅), 在 set 方法中触发信息。收集依赖的意思是找到所有用到这个数据的地方,触发依赖的意思是将所有找到的依赖进行更新。
Vue2 无法检测 property 的添加或移除。Vue2 不能检测数组元素的变动,修改数组长度也不行。 Vue.js 2.x没有直接对数组进行劫持,而是通过重写数组的原型方法来实现对数组的响应式支持。 Vue对数组的7个变异方法(push、pop、shift、unshift、splice、sort、reverse)实现了响应式。 出于对性能原因的考虑,没有去实现它。而不是不能实现。 对于对象而言,每一次的数据变更都会对对象的属性进行一次枚举,一般对象本身的属性数量有限,所以对于遍历枚举等方式产生的性能损耗可以忽略不计,但是对于数组而言呢?数组包含的元素量是可能达到成千上万,假设对于每一次数组元素的更新都触发了枚举/遍历,其带来的性能损耗将与获得的用户体验不成正比,故vue无法检测数组的变动。 但vue对数组的变异方法实现了响应式。
对于Object来说,可以使用Vue.set(object, propertyName, value) 方法向嵌套对象添加响应式 property,对于根级属性依然没有方法。
对于Array也可以使用Vue.set(vm.items, indexOfItem, newValue)来更新数组
对于根property,若要使其获得响应式能力,一定要在data中声明这个property,对于嵌套对象,可以使用Vue.set方法增加新的具备响应式能力的property,或者直接给这个嵌套对象重新赋值。
vue的生命周期?
Vue生命周期总共可以分为8个阶段:创建前后, 载入前后,更新前后,销毁前销毁后。
- onBeforeMount:在挂载之前被调用,与 Vue 2.0 中的 beforeMount 类似。
- onMounted:在挂载之后被调用,与 Vue 2.0 中的 mounted 类似。
- onBeforeUpdate:在更新之前被调用,与 Vue 2.0 中的 beforeUpdate 类似。
- onUpdated:在更新之后被调用,与 Vue 2.0 中的 updated 类似。
- onBeforeUnmount:在卸载之前被调用,与 Vue 2.0 中的 beforeDestroy 类似。
- onUnmounted:在卸载之后被调用,与 Vue 2.0 中的 destroyed 类似。
v-if
与v-show
的区别?
v-show
隐藏则是为该元素添加display:none
,dom元素依旧还在。v-if
显示隐藏是将dom元素整个添加或删除,因此有较高的切换消耗v-if
是真正的条件渲染,一开始为false就不会渲染,但v-show
一定会渲染,因此v-show有较高的初始渲染消耗v-if
切换会触发生命周期的一些事件;v-show
只是简单的基于css切换
v-if和v-for为什么不能放到一起?
因为vue的官网有明确的说明:v-for的优先级比v-if高,先循环再做判断会造成性能浪费,使用过程中不要把它们放在同一个元素上。
在vue2中,为什么data属性是一个函数而不是一个对象?
在 Vue 2 中,组件的 data 选项必须是一个函数,而不是一个对象。这个函数返回一个新的数据对象,这样每个实例可以维护一份被返回对象的独立的拷贝。如果 data 直接是一个对象,那么由于 JavaScript 中对象是引用类型,所有的组件实例将共享同一个数据对象,当在一个组件实例中改变数据,其他所有的组件实例的数据也会被改变。
vue中,父子/兄弟/非关系组件之间消息的传递方式有哪些?
- 父子关系组件,可以通过props传递参数,回调函数实现消息传递。
- 可以通过vue自带的emit实现消息传递。
- 可以通过第三方消息库实现消息传递。
- 可以通过第三方数据管理库例如vuex。pina实现消息传递。
你知道vue中key的原理吗?说说你对它的理解
- 如果不用key,Vue会采用就地复地原则:最小化element的移动,并且会尝试尽最大程度在同适当的地方对相同类型的element,做patch或者reuse。
- 如果使用了key,Vue会根据keys的顺序记录element,曾经拥有了key的element如果不再出现的话,会被直接remove或者destoryed。
比如插入情况,就能只有一次插入操作,将效率发挥到极致。
如何插入原始HTML?
文本插值使用的是双大括号语法,双大括号会将数据解释为纯文本,而不是 HTML。若想插入 HTML,你需要使用 v-html 指令:
<span v-html="rawHtml"></span>
注意: 在网站上动态渲染任意 HTML 是非常危险的,因为这非常容易造成 XSS 漏洞。请仅在内容安全可信时再使用 v-html,并且永远不要使用用户提供的 HTML 内容。
如何响应式地绑定一个属性?
v-bind 指令:
<div v-bind:myId="dynamicId"></div>
如果绑定的值是 null 或者 undefined,那么该 attribute 将会从渲染的元素上移除。布尔型 Attribute,当其为其他假值时 attribute 将被忽略(但空字符串不会)。
因为 v-bind 非常常用,我们提供了特定的简写语法:
<div :myId="dynamicId"></div>
3.4+有同名写法:
<div :myId></div>
动态绑定多个值:
const objectOfAttrs = {
id: 'container',
class: 'wrapper'
}
<div v-bind="objectOfAttrs"></div>
如何绑定一个click事件?
指令是带有 v- 前缀的特殊 attribute。Vue 提供了许多内置指令,包括上面我们所介绍的 v-bind 和 v-html。
某些指令会需要一个“参数”,在指令名后通过一个冒号隔开做标识。例如用 v-bind 指令来响应式地更新一个 HTMLv-bind:href="url"
。
<a v-on:click="doSomething"> ... </a>
<!-- 简写 -->
<a @click="doSomething"> ... </a>
计算属性如何使用?
const publishedBooksMessage = computed(() => {
return author.books.length > 0 ? 'Yes' : 'No'
})
Vue 的计算属性会自动追踪响应式依赖。它会检测到 publishedBooksMessage 依赖于 author.books, 所以当 author.books 改变时,任何依赖于 publishedBooksMessage 的绑定都会同时更新。
若我们将同样的函数定义为一个方法而不是计算属性,两种方式在结果上确实是完全相同的,然而,不同之处在于计算属性值会基于其响应式依赖被缓存。一个计算属性仅会在其响应式依赖更新时才重新计算。
Vue常用的修饰符有哪些有什么应用场景?
修饰符是以点开头的特殊后缀,表明指令需要以一些特殊的方式被绑定。例如 .prevent 修饰符会告知 v-on 指令对触发的事件调用 event.preventDefault()。
- 表单修饰符 lazy,trim,number
- 事件修饰符 stop,prevent,self,
- 鼠标按键修饰符
- 键值修饰符
- v-bind修饰符
如何进行Class/Style绑定?
<div :class="{ active: isActive }"></div>
上面的语法表示 active 是否存在取决于数据属性 isActive 的真假值。
:class 指令也可以和一般的 class attribute 共存。
<div :class="[activeClass, errorClass]"></div>
绑定数组
对于只有一个根元素的组件,当你使用了 class attribute 时,这些 class 会被添加到根元素上并与该元素上已有的 class 合并。 如果你的组件有多个根元素,你将需要指定哪个根元素来接收这个 class。
<div :style="{ color: activeColor, fontSize: fontSize + 'px' }"></div>
<div :style="[baseStyles, overridingStyles]"></div>
当你在 :style 中使用了需要浏览器特殊前缀的 CSS 属性时,Vue 会自动为他们加上相应的前缀。
如何列表渲染?
<li v-for="(item, index|key, [index]) in items" :key="item.id">
{{ parentMessage }} - {{ index }} - {{ item.message }}
</li>
你也可以使用 of 作为分隔符来替代 in,这更接近 JavaScript 的迭代器语法:
<div v-for="item of items" :key="item.id"></div>
注意此处 n 的初值是从 1 开始而非 0。
<span v-for="n in 10">{{ n }}</span>
v-model指令是做什么用的?
用于表单数据的双向绑定,是:value和@input的结合体:
<input v-model="text">
v-model 会忽略任何表单元素上初始的 value、checked 或 selected attribute。
它将始终将当前绑定的 JavaScript 状态视为数据的正确来源。
但antd好像是v-model:value
<input v-model.trim="msg" />
对于需要使用 IME 的语言 (中文,日文和韩文等),你会发现 v-model 不会在 IME 输入还在拼字阶段时触发更新。 如果你的确想在拼字阶段也触发更新,请直接使用自己的 input 事件监听器和 value 绑定而不要使用 v-model。
默认情况下,v-model 会在每次 input 事件后更新数据 (IME 拼字阶段的状态例外)。你可以添加 lazy 修饰符来改为在每次 change 事件后更新数据
侦听器watch怎么用?
// 可以直接侦听一个 ref
watch(question, async (newQuestion, oldQuestion) => {
...
})
注意,你不能直接侦听响应式对象的属性值
watch(() => obj.count, (count) => {}, { immediate: true })
直接给 watch() 传入一个响应式对象,会隐式地创建一个深层侦听器——该回调函数在所有嵌套的变更时都会被触发
我们可以通过传入 immediate: true 选项来强制侦听器的回调立即执行
模版引用如何解决?
const input = ref(null)
<input ref="input" />
如何父子组件传参?
const props = defineProps(['foo'])
console.log(props.foo)
中级
Vue 插件是什么?与组件有什么区别?
- 插件 (Plugin) 是用来增强你的技术栈的功能模块,它的目标是 Vue 本身,例如添加全局方法或者属性,添加 Vue 实例方法。
app.use(plugin)
例如i18n传入一个$translate方法
- 组件 (Component) 是用来构成你的 App 的业务模块,它的目标是 App.vue。
vue2和vue3的双向绑定原理?
- Object.definePropertyvue2中双向数据绑定的原理,用于定义对象属性,允许我们精确地控制属性的行为,包括读取、写入和删除等操作。
- Proxy是vue3中双向数据绑定的原理,是ES6中一种用于创建代理对象的特殊对象,它允许我们拦截并自定义目标对象的操作,例如属性访问、赋值、函数调用等。
NextTick是什么?
在下次 DOM 更新循环结束之后执行延迟回调。在修改数据之后立即使用这个方法,将获取更新后的 DOM。
数据在发现变化的时候,vue并不会立刻去更新Dom,而是将修改数据的操作放在了一个异步操作队列中, 如果我们一直修改相同数据,异步操作队列还会进行去重, 等待同一事件循环中的所有数据变化完成之后,会将队列中的事件拿来进行处理,进行DOM的更新,
说说你对slot的理解?slot使用场景有哪些?
Slot 艺名插槽,花名“占坑”,我们可以理解为solt在组件模板中占好了位置,当使用该组件标签时候,组件标签里面的内容就会自动填坑(替换组件模板中slot位置),作为承载分发内容的出口。
说说你对keep-alive的理解是什么?
keep-alive是vue中的内置组件,能在组件切换过程中将状态保留在内存中,防止重复渲染DOM, keep-alive 包裹动态组件时,会缓存不活动的组件实例,而不是销毁它们。
高级
vue的mixin是什么?
本质其实就是一个js对象,它可以包含我们组件中任意功能选项,如data、components、methods、created、computed等等, 我们只要将共用的功能以对象的方式传入 mixins选项中,当组件使用 mixins对象时所有mixins对象的选项都将被混入该组件本身的选项中来。
Mixin类通常作为功能模块使用,在需要该功能时“混入”,有利于代码复用又避免了多继承的复杂。在日常的开发中,我们经常会遇到在不同的组件中经常会需要用到一些相同或者相似的代码,这些代码的功能相对独立, 这时,可以通过Vue的mixin功能将相同或者相似的代码提出来。
Mobx原理
mobx 每次都是修改的同一个状态对象,基于响应式代理,也就是 Object.defineProperty 代理 get、set 的处理,get 时把依赖收集起来,set 修改时通知所有的依赖做更新。和 vue2 的响应式代理很类似。
nexttick是什么?怎么用?
nextTick 方法是 Vue.js 实例的一个方法,它接收一个回调函数作为参数。当 DOM 更新完成之后,Vue.js 会调用这个回调函数。这个回调函数会在当前事件循环的末尾执行,这意味着在这个回调函数中获取到的 DOM 元素的属性一定是更新后的最新值。
nextTick 函数维护了一个 callbacks 数组和一个 pending 变量。callbacks 数组用于存储需要在 DOM 更新之后执行的回调函数,pending 变量用于表示当前是否有回调函数在等待执行。
nextTick 函数的核心是 timerFunc 函数,它根据当前环境的支持情况选择合适的定时器函数。在现代浏览器中,如果支持 Promise 对象,则使用 Promise 对象的 then 方法实现定时器函数,如果不支持 Promise 对象,则使用 MutationObserver 对象实现定时器函数,如果都不支持,则使用 setTimeout 函数实现定时器函数。