• 前端面试练习24.3.13


    1.请描述下对vue生命周期的理解

    Vue 组件的生命周期是指组件从创建、挂载到销毁的整个过程中所经历的一系列钩子函数的调用顺序。

    在vue3 中,我们使用了组合式的API,使用了setup语法糖,提供了更灵活的方式来组织组件的逻辑,不再依赖于固定的生命周期钩子函数。

    在vue2 中的一些生命周期钩子函数:

    1. 创建阶段(Creation)

      • beforeCreate:实例刚在内存中创建,但是尚未初始化数据、事件等。
      • created:实例已经完成数据观测、属性和方法的运算,但尚未挂载到页面上。
    2. 挂载阶段(Mounting)

      • beforeMount:在挂载开始之前被调用,相关的 render 函数首次被调用。
      • mounted:实例已经挂载到页面上,此时组件已经可见。
    3. 更新阶段(Updating)

      • beforeUpdate:数据更新时调用,发生在虚拟 DOM 重新渲染和打补丁之前。
      • updated:数据更新完成,DOM 重新渲染完成。
    4. 销毁阶段(Destroying)

      • beforeDestroy:实例销毁之前调用。此时实例仍然完全可用。
      • destroyed:实例销毁后调用,所有的事件监听器会被移除,所有的子实例也会被销毁。

    在vue3 中生命周期钩子函数有了一些修改和引入:

    1. 创建阶段(Creation)

      • beforeCreate
      • created
      • beforeMount (此钩子函数也可以在创建阶段执行)
    2. 挂载阶段(Mounting)

      • onBeforeMount
      • onMounted
    3. 更新阶段(Updating)

      • onBeforeUpdate
      • onUpdated
    4. 卸载阶段(Unmounting)

      • onBeforeUnmount (Vue 2 中的 beforeDestroy 功能的扩展)
      • onUnmounted (Vue 2 中的 destroyed 功能的扩展)
    5. 错误处理阶段(Error Handling)

      • onErrorCaptured (捕获子组件错误)


    2.双向数据绑定是什么

    通俗的讲就是页面随着数据的变化而变化,数据也会因为页面的改变而变化

     

    双向数据绑定是指数据模型(通常是应用的状态)和视图(用户界面)之间的一种机制,其中数据的变化会影响视图的更新,同时视图中用户的操作(如输入、点击等)也会反过来影响数据模型的变化。在双向数据绑定中,数据的变化会自动反映到视图中,而视图中的变化也会同步更新到数据模型中,实现了数据和视图的同步更新。


    3.Vue组件之间的通信方式都有哪些?

    1. Props 和 Events

      • Props:父组件通过 props 把数据传递给子组件,子组件通过 props 接收父组件传递的数据。
      • Events:子组件通过触发事件并传递数据给父组件,来实现子组件向父组件通信。
    2. $emit 和 $on

      • $emit:在子组件中使用 $emit 方法触发一个自定义事件,并传递数据给父组件。
      • $on:在父组件中使用 $on 方法监听子组件触发的自定义事件,并处理传递过来的数据。
    3. $refs:父组件可以通过 ref 给子组件添加一个引用,然后直接通过这个引用访问子组件的属性和方法。

    4. Provide 和 Inject

      • Provide:父组件通过 provide 提供数据或方法,然后子组件通过 inject 注入到自身,以便访问这些数据或方法。
      • Inject:子组件通过 inject 注入父组件提供的数据或方法,并在组件内部使用。
    5. Event Bus:可以创建一个全局的事件总线实例,然后在不同的组件中使用该实例来触发和监听事件,实现组件之间的通信。

    6. Vuex:Vuex 是 Vue.js 的状态管理库,用于管理应用的所有组件的状态。通过在不同的组件中触发 mutations 来改变状态,然后通过 getters 获取状态,实现了组件之间的通信和状态共享。

    7. $parent 和 $children:可以通过 $parent 访问父组件的属性和方法,通过 $children 访问子组件的属性和方法。不过这种方式一般不推荐使用,因为会使得组件的耦合度增加,不利于组件的复用和维护。


    4.为什么data属性是一个函数而不是一个对象?

    在 Vue 组件中,data 选项可以是一个函数,也可以是一个对象。但是推荐将 data 选项定义为一个函数的形式,而不是一个对象。这是因为 Vue 组件的实例是可复用的,如果 data 是一个对象,则所有的实例都会共享同一个对象,这样会导致状态的共享和污染。而如果将 data 定义为一个函数,每次创建组件实例时,都会调用该函数,返回一个新的数据对象,从而保证了每个组件实例都有独立的数据对象,不会相互影响。


    5.动态给vue2的data添加一个新的属性时会发生什么?怎样解决?

    在 Vue 2 中,如果在组件实例创建之后动态给 data 添加一个新的属性,这个属性不会被响应式地追踪,也就是说 Vue 不会自动检测到这个新属性的变化,从而不会触发视图的更新。

     

    1. export default {
    2. data() {
    3. return {
    4. message: 'Hello'
    5. };
    6. },
    7. created() {
    8. this.$data.newProperty = 'World';
    9. }
    10. };

    可以使用 Vue.set 或者 this.$set 方法来手动将属性添加到数据对象中,并使其成为响应式的。

    1. export default {
    2. data() {
    3. return {
    4. message: 'Hello'
    5. };
    6. },
    7. created() {
    8. this.$set(this.$data, 'newProperty', 'World');
    9. }
    10. };


    6.v-if和v-for的优先级是什么

    在 Vue.js 中,v-if 指令和 v-for 指令可以同时存在于同一个 DOM 元素上,但它们的优先级是不同的。

    v-ifv-for 同时存在于同一个 DOM 元素上时,v-for 拥有更高的优先级。这意味着 v-for 指令将在 v-if 指令之前被解析。

    这意味着当 v-if 条件为 false 时,v-for 指令仍然会对其进行迭代,但是由于 v-if 的条件为假,因此渲染的结果将被隐藏。因此,如果你的意图是在满足一定条件时渲染多个项目,你应该在包含 v-for 的父元素上使用 v-if


    7.v-show和v-if有什么区别?使用场景分别是什么?

    区别:

    1. v-show

      • v-show 是一种简单的指令,它仅通过 CSS 控制元素的显示和隐藏。
      • 当条件为真时,元素会显示在 DOM 中,当条件为假时,元素会被设置为 display: none;,并保留在 DOM 中。
      • v-show 适用于需要频繁切换显示和隐藏的情况,因为元素会保留在 DOM 中,这样可以减少 DOM 的频繁创建和销毁。
    2. v-if

      • v-if 是一种更为灵活的指令,它会完全销毁和重建元素及其内部组件。
      • 当条件为真时,元素会被添加到 DOM 中,当条件为假时,元素会从 DOM 中移除。
      • v-if 适用于需要根据条件动态添加或移除元素的情况,因为它会真正地销毁和重建元素,可以节省 DOM 的内存占用。

    使用场景:

    • v-show 的使用场景

      • 当需要频繁切换显示和隐藏元素时,可以使用 v-show,因为它只是通过 CSS 控制元素的显示和隐藏,不会频繁地创建和销毁 DOM 元素。
      • 例如,用于实现显示/隐藏菜单、折叠面板等。
    • v-if 的使用场景

      • 当需要根据条件动态添加或移除元素时,可以使用 v-if,因为它会真正地销毁和重建元素,可以节省 DOM 的内存占用。
      • 例如,用于实现条件性渲染组件、根据权限动态显示或隐藏某些内容等。

    总的来说,如果需要频繁切换显示和隐藏元素,可以使用 v-show;如果需要根据条件动态添加或移除元素,可以使用 v-if


    8.你知道vue中key的原理吗?说说你对它的理解

    在 Vue 中,key 是用于标识 Vue 实例中的节点的特殊属性。每个 key 必须是唯一的,并且用于帮助 Vue 识别节点的身份,从而在 DOM 更新时尽可能地复用和移动现有元素,而不是创建新的元素或销毁现有元素。

    原理:

    1. DOM Diff 算法:Vue 使用一种称为 Virtual DOM 的技术来高效地更新真实 DOM。在更新过程中,Vue 会比较新旧虚拟 DOM 树的节点,找出节点的差异,并根据这些差异来更新真实 DOM。key 就是在这个比较过程中用来识别节点的标识符。

    2. 节点标识:当 Vue 更新虚拟 DOM 时,它会使用节点的 key 来判断是否是相同的节点。如果新节点和旧节点的 key 相同,则 Vue 认为它们是同一个节点,可以尝试复用现有的 DOM 元素。如果没有提供 key,Vue 会使用节点的索引来进行匹配,但这种方法可能导致 DOM 的不必要更新和重新渲染。

    3. 性能优化:使用 key 可以帮助 Vue 优化 DOM 更新性能,减少不必要的 DOM 操作和重新渲染。特别是在列表渲染中,使用 key 可以确保正确地复用现有的 DOM 元素,从而提高渲染性能。

    理解:

    • key 的作用不仅仅是为了性能优化,更重要的是确保组件在进行增删操作时,能够正确地定位和识别每个节点。通过唯一的 key,Vue 可以更好地跟踪每个节点的状态和变化,确保组件的行为和预期一致。

    • 在实际开发中,需要注意确保每个 key 是唯一的,并且尽量避免使用动态生成的索引作为 key,因为这可能导致不稳定的渲染结果和性能问题。


    9.说说你对vue的mixin的理解,有什么应用场景

    在 Vue 中,Mixin 是一种用于组件复用的机制,它允许将一些公共的功能和逻辑封装在一个对象中,然后在多个组件中进行复用。Mixin 可以包含任意组件选项,例如 data、methods、computed、watch 等,当组件使用 Mixin 时,它会将 Mixin 中的选项合并到组件自身的选项中,从而实现了代码的复用和分离。

    理解:

    1. 代码复用:Mixin 可以将一些通用的功能和逻辑封装起来,然后在多个组件中进行复用,避免了代码的重复编写。

    2. 代码分离:将公共的功能和逻辑抽离到 Mixin 中,使得组件的代码更加清晰和易于维护。

    3. 灵活性:Mixin 可以根据需要组合多个 Mixin,并且可以在组件中进行局部覆盖,从而实现更加灵活和精细的功能定制。

    应用场景:

    1. 公共功能封装:将一些常用的功能封装成 Mixin,如表单验证、数据请求、权限控制等,可以在多个组件中进行复用。

    2. 代码复用:当多个组件具有相似的功能或行为时,可以将这些共同的部分提取出来作为 Mixin,避免代码的重复编写。

    3. 代码分离:将不同组件中相似但又不完全相同的部分提取出来作为 Mixin,可以使组件的代码更加清晰和易于维护。

    4. 功能扩展:Mixin 可以用于扩展组件的功能,为组件提供一些额外的功能或特性。

    5. 跨项目复用:将一些通用的功能封装成 Mixin,可以在不同的项目中进行复用,提高了代码的可复用性和扩展性。

    1. // 定义一个 mixin
    2. const logMixin = {
    3. created() {
    4. console.log('Component created');
    5. },
    6. methods: {
    7. logMessage(message) {
    8. console.log('Message:', message);
    9. }
    10. }
    11. };
    12. // 在组件中使用 mixin
    13. Vue.component('my-component', {
    14. mixins: [logMixin],
    15. template: ''
    16. });

    在上面的示例中,我们定义了一个名为 logMixin 的 mixin,它包含了一个 created 钩子函数和一个 logMessage 方法。然后,在组件中使用了这个 mixin,并在模板中绑定了一个点击事件,当按钮被点击时会调用 logMessage 方法。

    通过使用 mixin,我们可以在多个组件中复用 logMixin 中定义的功能和逻辑,从而减少了代码的重复编写,并且使得组件的代码更加清晰和易于维护。


    10.Vue常用的修饰符有哪些有什么应用场景

    .prevent:阻止默认行为,

    即调用 event.preventDefault() 方法。常用于阻止表单提交或超链接跳转。

    <a href="#" v-on:click.prevent="doSomething">Click mea>
    

    .stop:阻止事件冒泡,

    即调用 event.stopPropagation() 方法。常用于防止事件向上传播到父元素。

    <div v-on:click.stop="doSomething">Click mediv>
    

    .capture:添加事件监听器时使用事件捕获模式。

    常用于在父组件中捕获子组件触发的事件。

    <div v-on:click.capture="doSomething">Click mediv>
    

    .self:只当事件是从侦听器绑定的元素本身触发时才触发回调。

    常用于在列表渲染中避免子元素的事件冒泡到父元素。

    <div v-on:click.self="doSomething">Click mediv>
    

    .once:只触发一次的事件监听器。

    常用于只需要触发一次的事件处理逻辑。

    <div v-on:click.once="doSomething">Click mediv>
    

    .passive

    滚动事件的默认行为通常是不能被取消的,而添加 .prevent 会导致滚动事件的默认行为被阻止。在使用 v-on 监听滚动事件时,可以使用 .passive 修饰符,表示不会调用 event.preventDefault() 方法,可以提高滚动性能。

    <div v-on:scroll.passive="handleScroll">Scroll mediv>
    


    11.Vue中的$nextTick有什么作用?

    $nextTick 是 Vue 提供的一个异步方法,它用于在 DOM 更新之后执行一段代码。它的主要作用是在更新数据之后等待 Vue 完成 DOM 更新,然后执行一段回调函数。这样可以确保在 DOM 更新完成后再进行一些操作,比如获取更新后的 DOM 元素的状态或进行其他操作。

    具体来说,$nextTick 的作用包括:

    等待 DOM 更新

    Vue 在更新数据后并不会立即更新 DOM,而是将 DOM 更新放入异步队列中,然后继续执行同步任务。使用 $nextTick 可以等待 Vue 更新 DOM 完成后再执行一段代码,确保在 DOM 更新后进行操作。

    获取更新后的 DOM 元素状态

    有时我们需要在更新后获取 DOM 元素的状态或进行一些 DOM 操作,但直接在更新数据之后执行可能无法得到最新的 DOM 状态,此时可以使用 $nextTick 来确保在 DOM 更新完成后再进行操作。

    避免异步更新问题

    在某些情况下,直接在更新数据后进行操作可能会导致一些异步更新的问题,比如在更新数据后立即获取更新后的 DOM 元素状态可能会获取到之前的状态。使用 $nextTick 可以避免这些问题,确保在更新后进行操作。

    总的来说,$nextTick 是用于在 Vue 更新 DOM 完成后执行一段代码的方法,它可以确保在 DOM 更新后再进行操作,避免了一些异步更新的问题,提高了代码的可靠性和稳定性。


    12.Vue实例挂载的过程

    Vue 实例的挂载过程指的是将 Vue 实例与 DOM 元素建立关联,并将 Vue 实例的模板渲染到页面上的过程。这个过程包括了初始化 Vue 实例、编译模板、创建虚拟 DOM、将虚拟 DOM 渲染到页面等步骤。

    下面是 Vue 实例挂载的主要过程:

    创建 Vue 实例

    首先,我们需要创建一个 Vue 实例。可以使用 new Vue() 构造函数来创建一个 Vue 实例,并传入相应的选项。

    初始化选项

    在创建 Vue 实例时,Vue 会初始化实例选项,包括数据对象、计算属性、方法、生命周期钩子函数等。

    编译模板

    Vue 实例中的模板(template)会经过 Vue 的编译器编译成渲染函数。编译过程会将模板转换为虚拟 DOM 树。

    创建虚拟 DOM

    通过渲染函数,Vue 将模板转换为虚拟 DOM(Virtual DOM)。虚拟 DOM 是一个 JavaScript 对象,它是对真实 DOM 的抽象表示。

    挂载虚拟 DOM

    接下来,Vue 将虚拟 DOM 挂载到页面上的一个真实的 DOM 元素上。可以使用 el 选项指定要挂载到的 DOM 元素,或者使用 $mount 方法手动挂载。

    数据初始化

    在挂载前,Vue 会对数据进行初始化,将数据对象中的属性转换为响应式数据,建立数据与视图的关联。

    渲染视图

    一旦 Vue 实例挂载到页面上,就会触发首次渲染。Vue 会根据虚拟 DOM 中的描述来创建真实的 DOM 元素,并将其插入到指定的挂载元素中,完成页面的初始化渲染。

    监听数据变化

    Vue 实例会开始监听数据的变化,当数据发生变化时,Vue 会重新渲染虚拟 DOM,并将更新的内容更新到页面上,从而实现了数据驱动视图的更新。

    总的来说,Vue 实例的挂载过程是一个初始化数据、编译模板、创建虚拟 DOM、渲染视图的过程。通过这个过程,Vue 实现了数据与视图的绑定,并且能够根据数据的变化动态地更新页面内容。


    13.你了解vue的diff算法吗?

    Vue 使用的 Virtual DOM 的 diff 算法是一种高效的算法,用于比较新旧虚拟 DOM 树的差异,并根据这些差异来更新真实 DOM。这个算法的核心思想是尽量复用已有的 DOM 元素,减少不必要的 DOM 操作,从而提高页面的性能和响应速度。

    Vue2 的 diff 算法主要包括以下几个步骤:

    1. 深度优先遍历:首先,Vue 会对新旧虚拟 DOM 树进行深度优先遍历,比较相同层级的节点。

    2. 同级别比较:在比较过程中,Vue 会首先比较两个节点是否是同一类型的节点。如果不是同一类型的节点,直接将旧节点替换成新节点;如果是同一类型的节点,则继续比较子节点。

    3. 节点复用:在比较子节点时,Vue 会尽可能地复用已有的 DOM 元素。通过给节点添加 key 属性,Vue 可以识别出哪些节点是相同的节点,从而可以复用这些节点。

    4. 更新差异:在比较完成后,Vue 会得到两个虚拟 DOM 树的差异。根据这些差异,Vue 会生成一组最小的 DOM 操作指令,然后将这些指令应用到真实 DOM 上,完成页面的更新。

    通过这样的 diff 算法,Vue 能够高效地更新页面,并且尽量减少不必要的 DOM 操作,从而提高页面的性能和响应速度。同时,通过合理使用 key 属性,开发者可以更好地控制节点的复用,避免一些意外的问题。Vue 的 diff 算法是 Vue 实现高效响应式的重要基础之一。

     

    Vue 2 中的 diff 算法:

    1. 递归遍历:Vue 2 中的 diff 算法采用的是递归遍历的方式,逐层比较新旧虚拟 DOM 树的节点。

    2. 同级比较:在比较过程中,Vue 2 首先比较两个节点是否是同一类型的节点,然后继续比较子节点,直到比较完成。

    3. 节点复用:Vue 2 中使用 key 属性来帮助识别哪些节点是相同的节点,从而实现节点的复用。

    Vue 3 中的 diff 算法:

    1. 编译优化:Vue 3 中引入了编译优化,包括静态模板提升技术和更好的标记算法,可以提高模板编译的性能。

    2. 双端比较:Vue 3 中引入了双端比较(Two-Ended Diffing)的技术,在比较过程中同时从新旧节点的两端开始比较,以减少比较的层级,提高 diff 算法的效率。

    3. 优化策略:Vue 3 中对 diff 算法的一些细节进行了优化,例如增加了更高效的节点比较策略、提高了复用节点的几率等,从而进一步提高了 diff 算法的性能。

    总的来说,Vue 3 在 diff 算法方面进行了一些改进和优化,包括引入编译优化和双端比较等技术,从而提高了 diff 算法的性能和效率。这些改进使得 Vue 3 在大型应用和大规模节点更新的场景下有了明显的性能提升。


    14.Vue中组件和插件有什么区别?

    Vue 中的组件和插件是两种不同的概念,它们在 Vue 应用中扮演着不同的角色和功能:

    1. 组件(Component):

      • 组件是 Vue 应用中的基本构建块,用于封装可复用的 HTML 元素和功能。
      • 组件通常包含了模板(template)、脚本(script)和样式(style)等内容,用于定义组件的外观和行为。
      • 组件可以在应用中被多次实例化和复用,使得应用的结构更加清晰和模块化。
    2. 插件(Plugin):

      • 插件是一种 Vue 的扩展机制,用于扩展 Vue 的全局功能和行为。
      • 插件可以通过 Vue.use() 方法来注册到 Vue 实例中,从而为应用提供全局可用的功能。
      • 插件通常包含了一些全局的功能或工具,如路由器、状态管理、数据验证、UI 库等。
      • 插件可以访问 Vue 实例,并在其上注册全局方法、指令、混入等,以扩展 Vue 的功能。

    简而言之,组件是用于封装 UI 元素和功能的可复用单元,而插件是用于扩展 Vue 的全局功能和行为的机制。在 Vue 应用中,我们既可以使用现有的组件来构建界面,也可以使用插件来扩展 Vue 的功能,从而实现更丰富和强大的应用。


    15.Vue项目中你是如何解决跨域的呢?

    使用代理(Proxy)

    • 在项目的配置文件(vue.config.js)中配置代理。通过将API请求代理到与前端应用程序相同的域,可以绕过浏览器的同源策略。
    • 例如,如果你的Vue应用运行在 http://localhost:8080,而API服务器运行在 http://api.example.com,你可以配置代理将API请求发送到 /api 路径,然后让开发服务器将这些请求代理到正确的地址上。
    1. module.exports = {
    2. devServer: {
    3. proxy: {
    4. '/api': {
    5. target: 'http://api.example.com',
    6. changeOrigin: true,
    7. pathRewrite: {
    8. '^/api': ''
    9. }
    10. }
    11. }
    12. }
    13. }

    设置后端服务允许跨域请求

    • 如果你有权限修改后端服务的配置,可以在后端服务中配置允许跨域请求。这可以通过设置响应头中的 CORS(Cross-Origin Resource Sharing)来实现。
    • 在Node.js中,你可以使用 cors 中间件来简化跨域请求的设置。
    1. const express = require('express');
    2. const cors = require('cors');
    3. const app = express();
    4. app.use(cors());

    使用JSONP(仅限GET请求)

    • JSONP(JSON with Padding)是一种在不受同源策略限制的情况下获取数据的方法。它通过动态创建