面试 Vue 框架八股文十问十答第五期
相信看了本文后,对你的面试是有一定帮助的!关注专栏后就能收到持续更新!
⭐点赞⭐收藏⭐不迷路!⭐
1)Vue的基本原理
Vue.js是一款用于构建用户界面的渐进式JavaScript框架。其基本原理包括:
- 响应式数据: Vue通过使用数据劫持和观察者模式实现了响应式数据。当数据发生变化时,相关的视图会自动更新。这是通过Object.defineProperty()或Proxy来实现的,具体取决于浏览器的支持情况。
- 虚拟DOM: Vue使用虚拟DOM来提高渲染效率。组件的状态变化时,Vue首先计算出虚拟DOM的变化,然后再将变化的部分更新到实际的DOM中,而不是直接操作真实的DOM。这减少了对实际DOM的直接操作,提高了性能。
- 组件化: Vue提倡组件化开发,将页面拆分为多个独立的组件。每个组件都有自己的状态和视图,可以组合成一个完整的应用。组件之间通过props和events进行通信。
- 指令: Vue通过指令(Directives)扩展了HTML,为页面添加了一些交互行为。常见的指令有
v-bind
、v-model
、v-if
、v-for
等。
2)双向数据绑定的原理
双向数据绑定是指视图层的变化会自动同步到数据层,反之亦然。在Vue中,双向数据绑定是通过v-model
指令来实现的。其基本原理如下:
- 数据劫持: Vue使用数据劫持(Object.defineProperty或Proxy)监听数据变化。当数据发生变化时,会触发相应的getter和setter。
- 观察者模式: Vue实现了一个观察者(Watcher)机制。每个数据都有一个对应的Watcher,负责监听该数据的变化。当数据发生变化时,Watcher会通知订阅了该数据的视图进行更新。
- 事件监听: 在表单元素上使用
v-model
时,Vue会为该元素绑定input事件监听器。当用户输入时,触发input事件,通过事件监听器更新数据,反之亦然。
3) 使用 Object.defineProperty() 来进行数据劫持有什么缺点?
使用Object.defineProperty()
进行数据劫持有一些缺点:
- 只能监听对象的属性:
Object.defineProperty()
只能劫持对象的属性,而不是整个对象。因此,需要逐个定义对象的每个属性,如果对象的嵌套层级很深,需要递归定义,增加了代码复杂性。 - 初始值必须是对象: 使用
Object.defineProperty()
时,被劫持的属性必须是对象,初始值不能是基本类型。如果初始值是基本类型,需要额外处理。 - 无法监听数组变化:
Object.defineProperty()
无法直接监听数组的变化,因为数组的一些操作(例如通过索引直接设置元素值)不会触发setter。 - 性能开销: 在大规模数据变化时,使用
Object.defineProperty()
可能会带来性能开销,因为每个属性的变化都会触发相应的getter和setter。
4)MVVM、MVC、MVP的区别
这三个是设计模式,用于组织前端应用的代码结构,其中MVVM、MVC、MVP分别代表:
- MVVM (Model-View-ViewModel): MVVM模式将应用程序分为三个主要组成部分。
Model
表示数据和业务逻辑,View
表示用户界面,ViewModel
充当View和Model之间的中介,处理View的用户输入,并更新Model。Vue.js是一个典型的MVVM框架。 - MVC (Model-View-Controller): MVC是一种将应用程序分为三个组件的模式。
Model
表示数据和业务逻辑,View
表示用户界面,Controller
处理用户输入并更新Model和View。AngularJS是一个使用MVC模式的框架。 - MVP (Model-View-Presenter): MVP模式也是一种将应用程序分为三个主要组成部分的模式。
Model
表示数据和业务逻辑,View
表示用户界面,Presenter
处理用户输入并更新Model和View。React框架通常被认为是一个采用了MVP模式的库。
区别主要在于各个组件之间的交互方式和关注点分离程度。
5)Computed 和 Watch 的区别
在Vue中,computed
和watch
都是用于观察数据变化的工具,但它们之间有一些关键的区别:
-
Computed:
computed
是用于声明派生状态的属性,它依赖于其他响应式数据,只有在相关依赖发生变化时才会重新计算。computed
的值会被缓存,只有当依赖改变时才会重新计算。通常用于处理一些基于状态的复杂计算。<template> <div>{{ fullName }}</div> </template> <script> export default { data() { return { firstName: 'John', lastName: 'Doe', }; }, computed: { fullName() { return `${this.firstName} ${this.lastName}`; }, }, }; </script>
- Watch: watch用于观察特定数据的变化并执行副作用,可以在数据变化时执行异步或复杂操作。watch 更灵活,但可能需要手动处理一些逻辑,例如处理异步请求。
<template>
<>
6)Computed 和 Methods 的区别
在Vue中,computed
和methods
都用于处理逻辑,但它们有几个关键的区别:
- 缓存:
- Computed: 计算属性(
computed
)是基于它的依赖缓存的。只有相关依赖发生改变时,计算属性的值才会重新计算,而之后的访问会直接返回缓存的结果。 - Methods: 方法(
methods
)每次被调用时都会执行函数体,不会缓存结果。
- Computed: 计算属性(
- 调用方式:
- Computed: 在模板中,可以像访问数据属性一样直接访问计算属性,不需要在模板中添加括号。
- Methods: 方法需要在模板中通过方法名加括号的方式调用。
<template>
<div>
<p>Computed Property: {{ computedProperty }}</p>
<p>Method: {{ methodResult() }}</p>
</div>
</template>
<script>
export default {
data() {
return {
dataValue: 5,
};
},
computed: {
computedProperty() {
return this.dataValue * 2;
},
},
methods: {
methodResult() {
return this.dataValue * 2;
},
},
};
</script>
7)slot是什么?有什么作用?原理是什么?
Slot(插槽) 是Vue.js中一种机制,用于在组件的模板中扩展子组件的内容。它允许父组件将任意内容插入子组件中的特定位置。
作用:
- 允许组件接受父组件传递的内容,使组件更加灵活。
- 可以在父组件的模板中插入任意内容,不仅限于普通数据传递。
原理:
-
默认插槽:如果子组件没有具名插槽,父组件传递的内容将被插入子组件中
<slot>
标签的位置。<!-- 子组件 --> <template> <div> <slot></slot> </div> </template>
<!-- 父组件 -->
<template>
<child-component>
<p>Hello from parent!</p>
</child-component>
</template>
-
具名插槽:父组件可以使用
<slot>
元素的name
属性定义具名插槽,子组件通过<slot>
元素的name
属性匹配插槽。<!-- 子组件 --> <template> <div> <slot name="header"></slot> <div>Other content...</div> <slot name="footer"></slot> </div> </template>
<!-- 父组件 -->
<template>
<child-component>
<template v-slot:header>
<p>Header content</p>
</template>
<template v-slot:footer>
<p>Footer content</p>
</template>
</child-component>
</template>
8)过滤器的作用,如何实现一个过滤器
过滤器的作用:
过滤器用于在模板中对数据进行格式化处理,常见的场景包括文本格式化、日期格式化等。它可以在模板表达式中使用,以管道符(|
)的形式应用在数据上。
如何实现一个过滤器:
在Vue中,可以通过Vue.filter
方法全局注册过滤器,也可以在组件内部通过filters
选项注册局部过滤器。
<template>
<div>
<p>{{ message | capitalize }}</p>
<p>{{ currentDate | formatDate }}</p>
</div>
</template>
<script>
export default {
data() {
return {
message: 'hello world',
currentDate: new Date(),
};
},
filters: {
capitalize(value) {
if (!value) return '';
return value.charAt(0).toUpperCase() + value.slice(1);
},
formatDate(value) {
if (!value) return '';
const options = { year: 'numeric', month: 'long', day: 'numeric' };
return new Date(value).toLocaleDateString('en-US', options);
},
},
};
</script>
在上述例子中,capitalize
和formatDate
就是两个过滤器,分别用于将字符串首字母大写和格式化日期。
9)如何保存页面的当前的状态
保存页面的当前状态通常有以下几种方式:
- 使用路由参数: 在使用路由的情况下,可以将页面状态以参数的形式传递到URL中,使得页面刷新时仍能保持状态。
- 使用本地存储: 使用浏览器提供的
localStorage
或sessionStorage
将页面状态存储在客户端,以便在刷新后重新加载。 - 通过Vuex管理状态: 在Vue应用中使用Vuex来管理全局状态,将需要保持的状态存储在Vuex中。这样,无论页面是否刷新,状态都可以被恢复。
- 使用Cookie: 将页面状态存储在Cookie中,这样可以在客户端和服务器之间传递状态信息。
具体选择哪种方式取决于应用的需求和复杂性。
10)常见的事件修饰符及其作用
Vue.js是一个流行的JavaScript框架,它提供了一些方便的事件修饰符来处理用户交互。下面是一些常见的事件修饰符及其作用:
.stop
:阻止事件冒泡,即阻止事件向父元素传播。.prevent
:阻止事件的默认行为,比如阻止表单提交或者超链接的跳转。.capture
:使用事件捕获模式,而不是默认的事件冒泡模式。.self
:只在事件触发的元素自身上触发事件,而不是其子元素。.once
:事件只会触发一次,之后会自动移除事件监听器。.passive
:告诉浏览器该事件监听器不会调用preventDefault()
,可以提高滚动性能。.native
:监听组件根元素的原生事件,而不是组件内部的自定义事件。.left
:只在鼠标左键点击时触发事件。.right
:只在鼠标右键点击时触发事件。.middle
:只在鼠标中键点击时触发事件。
开源项目地址:https://gitee.com/falle22222n-leaves/vue_-book-manage-system
已 300 + Star!
⭐点赞⭐收藏⭐不迷路!⭐