VUE常见面试题

这篇具有很好参考价值的文章主要介绍了VUE常见面试题。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

1.为什么要使用Vue?

答:Vue是一款优秀的前端框架,它可以帮助我们快速构建高效、可复用、易维护的Web应用程序,并提供了丰富的API和生态系统。

2. Vue有哪些生命周期钩子函数?

答:Vue有8个生命周期钩子函数,分别是beforeCreate、created、beforeMount、mounted、beforeUpdate、updated、beforeDestroy、destroyed。

3. Vue中的v-if和v-show有什么区别?

答:v-if是根据条件动态地添加/删除DOM元素,而v-show则只是通过隐藏或显示DOM元素来控制其可见性。

4. Vue如何实现组件间通信?

答:Vue中可以通过props、事件和Vuex等方式实现组件间通信。

5. Vue中的mixins是什么?

答:mixins是一种可重用的代码的方式,它可以让我们在不同的Vue组件之间共享相同的Vue选项。

6. Vue中的computed和watch有什么区别?

答:computed是用于计算属性的,它会在依赖的数据发生变化时自动更新结果;而watch是监视某个数据的变化并执行回调函数,它适用于当需要在数据变化时执行异步或开销较大的操作时使用。

7. Vue中的父子组件如何进行通信?

答:可以通过props向子组件传递数据,也可以通过事件和$emit方法实现子组件向父组件传递数据。

8. Vue中的路由是什么?

答:Vue中的路由是指我们定义的URL与相关组件之间的映射关系,它提供了一种在单页应用程序(SPA)中构建导航的方式。

9. Vue中使用v-for时需要使用key属性吗?为什么?

答:是的,因为key属性可以帮助Vue快速地识别DOM元素的变化状态,从而提高渲染性能。

10. Vue中的单文件组件是什么?

答:Vue中的单文件组件(.vue文件)是将一个组件的HTML、CSS和JavaScript代码都写在同一个文件中的一种开发方式。

11. 什么是mixins(混入),什么时候应该使用它?

答:mixins是一种复用组件选项的方式,当多个组件有相似的选项时,可以将这些选项提取出来作为一个mixin,然后在组件中通过`mixins`属性引入。使用mixins可以让代码更可复用、更易维护,但过多的mixins也会增加代码的复杂度,所以需要根据具体情况使用。

12. Vue中,什么是模板(template)?

答:在Vue中,模板是指一段HTML代码,其中包含了Vue的特殊语法和指令。

13. Vue中,什么是组件(components)?应该如何创建一个组件?

答:在Vue中,组件是指可复用、自包含的Vue实例。创建一个组件可以通过调用`Vue.component()`方法来定义一个Vue构造器,然后使用这个构造器创建组件实例。

14. 在Vue中,如何访问子组件或父组件中的方法和数据?

答:在Vue中,可以通过`vm.$refs`属性来访问子组件,也可以通过props和$emit方法来实现子组件向父组件传递数据。如果需要访问祖先组件中的方法或数据,可以通过$parent或$root属性来实现。

15. 请解释v-model指令在表单元素中的作用。

答:v-model指令可以将表单元素和Vue实例中的数据进行双向绑定,当表单元素的值发生变化时,Vue实例中的数据也会相应地更新。

16. Vue中,什么是计算属性(computed property),它有什么作用?

答:计算属性是一种求值结果的方式,在Vue中,可以通过computed选项定义一个计算属性,它会根据依赖的数据动态地计算结果并缓存起来,从而提高渲染性能。

17. Vue中,什么是侦听器(Watchers),它有什么作用?

答:侦听器是一种对数据的监听机制,在Vue中,可以通过watch选项创建一个侦听器,当watch所依赖的数据发生变化时,回调函数就会被触发。

18. 在 Vue.js 中,forceUpdate()是什么?它有什么作用?

答:forceUpdate()方法可以强制组件重新渲染,应该避免在实际开发中使用该方法,而是尽量采用响应式数据来更新视图。

19. 如何向Vue组件的props传递布尔值(false)?

答:需要绑定属性值为字符串形式的’false’,如下所示:

<my-component :prop-name="false"></my-component>

20. computed 和 watch 有没有同时使用的情况?请举例说明。

答:computed和watch可以同时使用,例如,当需要在依赖数据改变后执行异步操作时,可以使用watch来监听依赖数据的变化,并在回调函数中调用异步操作,然后将结果赋给一个计算属性,从而实现数据的响应式更新和异步操作的执行。

21. 在Vue中,怎样理解父子组件的生命周期钩子函数执行顺序?

答:在Vue中,首先会先执行父组件的beforeCreate、created钩子函数,然后执行子组件的beforeCreate、created钩子函数,接着执行父组件的beforeMount钩子函数,再执行子组件的beforeMount钩子函数,然后依次执行mounted、beforeUpdate、update等钩子函数,最后执行destroyed钩子函数。

22.什么是动态组件?将其和静态组件进行对比

答:动态组件和静态组件都是Vue中的组件,但它们之间有一个关键的区别。

静态组件在Vue实例创建时就已经存在于模板中,不会被条件渲染或v-if等指令显示或隐藏。

动态组件则可以通过绑定is属性来动态地切换组件。这意味着相同的<span>标记可以在运行时渲染成不同的组件。

 需要注意的是,由于动态组件的性质,它不能在Vue模板编译期生成。所以,在使用动态组件时,Vue必须为其进行实时编译,以便在渲染期间使用。

23.请描述Vue 3和Vue 2之间的主要区别?

答:Vue 3相对于Vue 2有许多变化。这些变化包括:

  • 更好的TypeScript支持
  • 更快的渲染速度,通过静态提升提高组件的性能
  • Composition API提供了更灵活的逻辑复用和代码共享方式
  • 改进的响应式系统,以更好地支持复杂对象类型、数组和Map/Set等数据结构
  • 更好的逻辑分离,减少重复的模板代码量
  • 提供新的调试工具

24.请解释Vue 3中的Teleport组件? 

答:Vue 3中新增了Teleport组件,它是一种新的语法糖来实现Portal。可以使用Teleport组件将一个元素移动到指定的DOM节点下。

Teleport组件需要两个prop:todisabledto用于指示目标DOM节点,而disabled属性可以防止同时触发渲染操作。

<template>
  <div class="modal" v-if="isOpen">
    <teleport :to="document.body">
      <div class="modal-dialog">
        <!-- modal content here -->
      </div>
    </teleport>
  </div>
</template>

<script>
import { ref } from 'vue';

export default{
  setup(){
    const isOpen = ref(false);

    return {
      isOpen,
    };
  },
};
</script>

25. 请解释Vue 3中的Composition API?

答:在Vue 2中,一个组件的逻辑被分布在各种属性和生命周期钩子中,这可能会导致组件变得难以理解和维护。

Vue 3中引入了Composition API,这是一组API,可以让开发者更灵活地组织组件逻辑。使用Composition API,你可以将相关代码放在一起,并在不同的组件之间共享它们。

<template>
  <div>
    <p>Count: {{ count }}</p>
    <button @click="increment">Increment</button>
    <button @click="decrement">Decrement</button>
  </div>
</template>

<script>
import { reactive, toRefs } from 'vue'

export default {
  setup() {
    const state = reactive({
      count: 0
    })

    function increment() {
      state.count++
    }

    function decrement() {
      state.count--
    }

    return {
      ...toRefs(state),
      increment,
      decrement
    }
  }
}
</script>

26.什么是Vite,为什么它比Webpack更快?

答:Vite是一种新型构建工具,用于在开发期间提供快速的反应式开发体验。实际上,它能够取代Webpack(虽然Vite本身并没有这个目的)。

Vite通过使用ES modules并跳过打包来提供极快的代码转换速度。这样,当修改代码时,只需要转换被修改的部分,从而减少了重新编译整个项目的时间。

此外,通过使用原生浏览器支持的模块机制,可以更有效地利用缓存,并为浏览器提供更优化的资源加载策略。这也使得Vite在服务启动时具有更快的编译和热重载速度。

27. 请解释Vue 3中的Suspense组件?

 答:Suspense组件是一种新的特性,用于渲染异步组件和分割大型组件所需的子组件。它允许您在等待异步数据或按需加载内容时呈现备用占位符内容,例如加载 spinner 或骨架屏幕。

<template>
  <div>
    <Suspense>
      <template #default>
        <AsyncComponent />
      </template>
      <template #fallback>
        <div>Loading...</div>
      </template>
    </Suspense>
  </div>
</template>

<script>
import { defineAsyncComponent } from 'vue'

const AsyncComponent = defineAsyncComponent({
  loader: () => import('./MyComponent.vue'),
  delay: 200,
  timeout: 3000
})

export default {
  components: {
    AsyncComponent
  }
}
</script>

上述示例中,<AsyncComponent>元素被放置在<Suspense>中,同时定义了两个插槽defaultfallbackdefault插槽呈现异步组件,而fallback插槽则呈现一个简单的加载提示息。 在模块开始加载之后,使用 delay 属性可以控制占位符最小显示时间,同时 timeout属性可用于调整最长等待时间,防止渲染超时。 

28. Vue.js中如何处理用户输入和表单控件绑定?

答:Vue.js提供了v-model指令用于双向绑定输入框和Vue实例之间的数据。对于表单控件,可以使用v-bind绑定value值,同时监听input或change事件来更新相应的数据。 

29.Vuex是什么?它在Vue.js中的作用是什么?

 答:Vuex是一个专门为Vue.js设计的状态管理库。它可以将全局状态(如用户信息、登录状态、主题等)存储在一个统一的地方,从而方便多个组件之间共享和访问这些状态。

在Vue.js中,各个组件之间的通信是通过props和事件来实现的。但是,随着应用程序变得复杂,组件之间的通信也会变得复杂和混乱。而Vuex的出现,可以有效地解决这个问题。

Vuex采用了一种类似于Flux架构的状态管理模式,将数据流的方向变得更加清晰和可控。它将全局状态拆分成多个模块,每个模块可以有自己的状态、mutations、actions和getters。通过Vuex,我们可以更好地组织和管理应用程序中的状态,并实现更加高效和灵活的数据管理。

在Vue.js中,使用Vuex可以方便地管理组件之间共享的状态,同时也可以避免深层次的组件嵌套和复杂的事件传递。通过将状态提升到Vuex中,我们可以在不同的组件中快速访问和修改它们,从而提高应用程序的可维护性和可扩展性。

30.简答vue中keep-alive

答: Vue中的keep-alive组件是一个高阶组件,用于缓存组件实例并在后续使用中保留它们。这可以防止在多次渲染相同组件时,每次都重新实例化和重新渲染组件,而是从缓存中拿取组件实例。

使用keep-alive组件通过设置include或exclude属性来选择需要缓存的组件。同时,keep-alive还提供了activated和deactivated生命周期钩子函数,用于在组件激活和停用时执行相关逻辑。

使用keep-alive组件可以大幅提升应用的性能和流畅度,但需要注意在使用时避免出现缓存脏数据等问题。

31. mvvm框架是什么?它和其它框架(jquery)的区别是什么?哪些场景适合?

答:MVVM是Model-View-ViewModel的缩写,是一种用于前端开发的软件架构设计模式。它的基本思想是通过数据绑定将视图(view)和数据模型(model)分离开来,并通过ViewModel作为中间层来连接二者。

与其它框架(如jQuery)相比,MVVM框架更注重数据绑定和数据驱动,让UI界面根据数据的变化自动更新,从而实现更加灵活和响应式的开发。

在具体的场景中,MVVM框架适用于需要频繁操作DOM和大量数据展示的复杂应用程序,尤其是需要实现数据的双向绑定和组件化开发的应用场景。它能够提高开发效率、简化代码、降低维护难度,并支持代码的可测试性和可维护性。

32.Vue路由懒加载(按需加载路由) 

答:Vue路由懒加载是指将路由组件按需加载,而非全部一次性加载,提高应用的加载速度和性能。实现路由懒加载需要使用Vue的异步组件和webpack的动态import语法。

具体步骤如下:

1. 创建Vue路由配置文件并引入需要懒加载的组件。例如,在router.js中,我们需要懒加载Home组件和About组件:

import Vue from 'vue';
import Router from 'vue-router';

const Home = () => import('@/views/Home.vue');
const About = () => import('@/views/About.vue');

Vue.use(Router);

export default new Router({
  routes: [
    {
      path: '/',
      name: 'home',
      component: Home
    },
    {
      path: '/about',
      name: 'about',
      component: About
    }
  ]
});

2. 使用动态import语法进行懒加载。

在上面的代码中,我们使用了动态import语法来进行异步加载,如

const Home = () => import('@/views/Home.vue');

  由于动态import语法是ES6的一部分,所以必须使用支持ES6的浏览器或使用babel进行转换。

3. 优化代码追踪和性能

Vue路由懒加载会产生许多小文件,需要进行优化和代码追踪。可以使用webpack的magic comment注释来指定打包后的文件名,如:

const Home = () => import(/* webpackChunkName: "home" */ '@/views/Home');

这样,打包后的文件名就会以"home"命名,方便代码追踪和分析。

总结:

通过Vue路由懒加载,我们可以将应用的初始加载速度和性能提高,是Vue应用的一个常见优化技巧。 

33. vuex和pinia的区别

答:Vuex和Pinia都是Vue.js状态管理库,它们的主要区别在于实现方式和API设计。

Vuex是Vue.js官方提供的状态管理库,基于Flux架构设计,可以用于管理应用程序中的共享状态。它通过一个全局的状态树(也被称为store)来存储应用程序的所有状态,并提供了一些API来读取、更新和响应状态的变化。在Vuex中,状态是通过mutation或action来进行修改的,这些修改必须是同步的或异步的。

Pinia是一个使用Vue.js 3的新型状态管理库,它使用Composition API作为实现方式,提供了一个基于类的API设计。 Pinia的主要特点是它的API设计更加简单和易于理解,相对于Vuex,它提供了更少的API,但是每个API的作用更加清晰。Pinia通过一个实例化的store来管理状态,每个store都是独立的,而且可以动态地创建和销毁。另外,在Pinia中,状态可以通过getter和setter来进行读取和修改,这样可以更好地支持响应式的状态变化。

简而言之,Vuex和Pinia都是非常好的状态管理库,选择哪一个取决于你的个人喜好和项目需求。如果你喜欢Flux架构和想要一个丰富的API来管理全局状态,那么使用Vuex可能更加适合;而如果你更喜欢Composition API和更简单、清晰的API设计,并且想要更好地支持响应式的状态变化,那么使用Pinia可能更适合。

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

答:在Vue组件中,data选项用于声明组件内部数据。但是,为什么它需要以一个函数的形式来声明呢?

这是因为组件在被调用的时候,会被创建多个实例。如果data选项仅仅只是一个对象,则所有的组件实例将共享相同的数据对象,这会导致一个组件实例修改数据也会影响到其他组件实例的数据。为了避免这种情况,我们需要将data选项改写为一个函数,以便每次创建一个组件实例时都可以返回一个新的数据对象,从而保证每个组件实例都有自己独立的数据。

35.Vue中组件怎么传值 

 答:在 Vue 中,父子组件通常被用来构建复杂的 UI 交互。有以下四种父子组件:

1. 父组件向子组件传递数据:父组件通过 props 向子组件传递数据,子组件通过接收 props 来渲染数据。

2. 子组件向父组件传递数据:子组件通过 $emit 事件向父组件传递数据。

3. 父组件和子组件通过事件总线传递数据:可以通过事件总线(event bus)在父组件和子组件之间传递数据。

4. 父组件和子组件通过 Vuex 进行状态管理:可以使用 Vuex 管理应用的状态,使父组件和子组件都能够访问全局状态。

36.Vue单页面的优缺点

 答:Vue单页面的优点包括:

  1. 用户体验良好。使用Vue单页面应用程序时,页面不会频繁刷新,因为所有的操作都在同一个页面上完成,这使得用户感觉到应用程序的速度非常快。

  2. 开发效率高。使用Vue来构建单页面应用程序可以大大提高开发效率,因为它提供了许多便捷的工具和组件。

  3. 更好的代码组织方式。采用单页面的开发方式有助于更好地组织代码,这使得代码更易于理解和维护。

  4. 跨平台和设备兼容性强。由于单页应用是基于Web的,因此它们可以在各种设备和平台上运行,并且能够很好地适应不同的屏幕大小和分辨率。

        Vue单页面的缺点包括:

  1. SEO难度大。由于单页应用只有一个HTML文件,通常很难被搜索引擎正确索引。

  2. 初次加载时间长。由于单页应用需要把所有内容都加载到一个HTML文件中,所以初次加载时间可能比较长。

  3. 浏览器兼容性问题。部分老旧浏览器对一些新的前端框架支持不足,可能无法正常渲染Vue单页面应用。

  4. 复杂度高。Vue单页面应用相对于传统的多页应用,开发难度较大,加之代码必须采用组件化的方式编写,在整体设计上也需要注意层级关系和数据流动。

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

 答:可以,v-on指令可以绑定多个方法。可以通过在v-on指令中使用"."来指定多个事件处理程序。示例如下:

<button v-on:click.stop="method1; method2"></button>

以上代码会将method1和method2两个方法绑定到按钮的点击事件上,在用户点击按钮时,method1先执行,然后是method2。

需要注意的是,绑定多个方法时,每个方法之间要用分号 ";" 分隔开来。

38.Vue常用的事件修饰符有哪些

 答:Vue常用的事件修饰符包括:

1. .prevent:阻止默认行为
2. .stop:阻止事件冒泡
3. .capture:添加事件侦听器时使用事件捕获模式
4. .self:只当事件在该元素本身(而不是子元素)触发时触发回调
5. .once:事件将只会触发一次
6. .passive:滚动事件的默认行为 (即滚动) 将会立即触发,不能被取消,同时也不能调用 preventDefault()
7. .native:监听组件根元素的原生事件

这些修饰符可以与v-on指令一起使用。例如,使用.prevent修饰符可以阻止默认行为,如下所示:

<button v-on:click.prevent>提交</button>

39.Vue的路由钩子函数/路由守卫有哪些 

 答:Vue的路由钩子函数(也被称为路由守卫)是在路由导航过程中触发的一组回调函数,通过这些函数我们可以对路由进行拦截和控制,以实现一些常见的场景,如:用户登录、页面权限控制等。

Vue 2.x 中提供了三种类型的路由钩子函数:

  1. 全局前置守卫(beforeEach):在路由跳转前执行,可用来进行全局的身份验证、登陆状态检测等操作。
  2. 路由独享的守卫(beforeEnter): 在单个路由配置中设置独享的守卫,用于特定路由的情况。
  3. 组件内的守卫(beforeRouteEnter、beforeRouteUpdate、beforeRouteLeave):在进入路由前、路由更新前或路由离开组件时执行,可用于进行当前视图的访问权限控制及页面数据的加载与卸载等操作。

在Vue 3.x中新增了一个全局后置钩子函数(afterEach),该函数会在每次成功完成导航后被调用,无论是从A导航到B还是从B导航到A。

使用 Vue 的路由钩子函数能够更加灵活地控制路由跳转过程,在特定的场景下解决问题并提高用户体验。

40.Vuex流程 

 答:Vuex是一个状态管理库,用于管理Vue.js应用程序中的共享状态。Vuex的基本流程如下:

1. 在Vue.js应用程序中创建一个store对象,该对象包含应用程序的所有状态。
2. 在store对象中定义一个state对象,该对象包含所有需要共享的状态。
3. 定义一个getter函数,该函数从state对象中获取值并返回。
4. 定义一个mutation函数,该函数用于修改state对象的值。
5. 在Vue.js组件中使用$store对象来访问state和getter,以及调用mutation函数来修改state对象的值。
6. 在需要异步操作时,可以定义一个actions函数,该函数可以调用mutation函数来异步修改state对象的值。

整个流程就是:定义状态 -> 定义getter函数 -> 定义mutation函数 -> 在组件中访问和修改状态 -> 在需要异步操作时定义actions函数。这些步骤会让你的应用程序更加可维护,易于调试,更容易扩展。

 文章来源地址https://www.toymoban.com/news/detail-465515.html

 

 

到了这里,关于VUE常见面试题的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • vue本地运行开发,为什么要配置changeOrigin: true

    changeOrigin: true 是在配置反向代理时常见的一个选项,通常用于解决跨域请求的问题。Vue本地运行时,可能会涉及到前端应用与后端服务不在同一个域的情况,这就会触发浏览器的同源策略,阻止跨域请求。 使用Vue CLI(或其他类似的工具)在本地运行时,可以通过配置代理来

    2024年01月18日
    浏览(40)
  • 为什么vue打印的对象在浏览器中显示...

    1.现象 当在vue中打印对象的时候会发现有一些属性或者全部属性都是显示的...,点击展开后才能看到真正的值是什么. 2.原因 因为在vue中对象都是用了代理重写了get,由于get重写也就导致了浏览器不能直接获取到具体的值,因此才会在打印的时候为...,手动点击展开才显示具体的值

    2024年04月28日
    浏览(30)
  • Vue 和 JQuery 的区别在哪?为什么 JQuery 会被 Vue 取代?

    在 Web 前端开发领域,我们经常会遇到一些不同的工具和框架,其中 Vue 和 JQuery, JQuery 是曾经备受欢迎的选择,而现在 Vue 是大多数人的选择。本文将探讨 Vue 和 JQuery 之间的区别,并讨论为什么越来越多的开发人员放弃 JQuery 而选择 Vue。 1. 声明式 vs. 命令式 Vue 是一种声明式框

    2024年02月11日
    浏览(52)
  • 为什么defineProps宏函数不需要从vue中import导入?

    我们每天写 vue 代码时都在用 defineProps ,但是你有没有思考过下面这些问题。为什么 defineProps 不需要 import 导入?为什么不能在非 setup 顶层使用 defineProps ? defineProps 是如何将声明的 props 自动暴露给模板? 我们来看几个例子,分别对应上面的几个问题。 先来看一个正常的例

    2024年03月13日
    浏览(41)
  • vue js 回调函数 异步处理 为什么要 let that = this

    1 异步就是开个事务( 只有主线程 等主线程空闲 ),用that 值 做处理,然后返回处理结果,而that的值是开启 事务那一刻 的this的值.而在主线程处理的时候,this的一直在变化, that的值保留在那一刻 ps 或是将本obj 传递给其他的obj使用处理 ps 开启新事务或开启新子线程都是 在新的ob

    2024年02月11日
    浏览(54)
  • 为什么要使用卷积

    1. 卷积这个名词是怎么解释?“卷”是什么意思?“积”又是什么意思? 卷积的“卷”,指的的函数的翻转,从  g(t)  变成  g(-t)  的这个过程;同时,“卷”还有滑动的意味在里面(吸取了网友李文清的建议)。如果把卷积翻译为“褶积”,那么这个“褶”字就只有翻转的

    2024年02月09日
    浏览(43)
  • 为什么使用AutoMapper

    类库

    2024年02月14日
    浏览(51)
  • RABBITMQ为什么要使用

    面试官问这个问题,肯定是想知道你们公司有一个什么场景需要使用到这个Mq,这个场景有一个什么技术挑战导致必须要用这个mq,用了这个mq之后有什么好处。mq经典的使用场景有 解耦,异步,削锋 。 异步通信: 当一个系统收到请求,需要在自己系统处理数据,处理完后,

    2024年02月04日
    浏览(51)
  • 为什么要使用Token

            我们知道,http协议是一种无状态的协议,这就意味着当用户向我们的应用提供了用户名和密码进行用户认证,那么在下一次登录的时候,用户还要再进行验证,因为根据http协议,浏览器并不知道是谁发出的请求,所以为了能够让浏览器识别出是哪个用户发出的请求

    2024年02月09日
    浏览(38)
  • 为什么要使用线程池

    线程池主要是 控制运行的线程的数量 ,处理过程中将任务放入队列,然后在线程创建后启动这些任务,如果线程数量超过了最大数量,超出数量的线程排队等候,等其他线程执行完毕,再从队列中取出任务来执行。 Java线程的 创建 非常昂贵,需要 JVM 和 OS (操作系统)配合

    2023年04月09日
    浏览(62)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包