昨天面试的时候被提问到的问题集合。

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

1、vue的双向绑定原理是什么?里面的关键点在哪里?
2、实现水平垂直居中的方式?
3、常用伪元素有哪一些?
4、移动端如何适配不同屏幕尺寸?
5、本地存储有哪一些?他们三者有什么区别?
6、JS的数据类型?如何判断js的数据类型?
7、说一下ES6的新特性有哪些?
8、Let、const、var三者有什么区别?
9、数组去重有哪些办法?
ES6新增构造函数set,利用set具有天然去重功能
数组迭代
10、说一下深拷贝和浅拷贝,如何自己实现一个深拷贝?
11、Vue的生命周期有哪一些?说一下它们每个阶段做什么操作?
12、组件通讯方式有哪一些?
13、Vuex有几个属性及作用?
14、Vue的监听属性和计算属性有什么区别?
15、说一下防抖和节流。怎么实现?
16、Vue的导航守卫有哪一些?
17、你的登录拦截怎么实现的?
18、有用过图表吗?用的多吗?
19、闭包是什么?如何实现?
20、Vue2.0和vue3.0有什么区别?
21、Vue常用的指令有哪些?
22、v-If和v-show有什么区别?
23、v-for为什么要加一个key?
24、你是如何封装一个组件的?
25、有自己从0到1搭建过项目吗?
26、有用过uni-app吗?
27、你会写后台吗?有搞过服务端渲染吗?
28、说一下你项目中遇到的难点,如何解决?
29、Url到浏览器的一个过程有哪些步骤?
30、如何实现小程序的request封装及拦截?
31、在vue的项目应用中,不使用框架,怎么封装?
32、什么是Js原型?原型链是什么?
33、组件通讯方式有哪些?
34、用闭包的原理做过哪些?
35、作用域是什么?
36、操作数组的方式有哪些?
37、0.1 + 0.2 等于 0.3吗?为什么?如何解决?
38、keep-alive是什么?有哪几个生命周期阶段?
39、判断一个变量是否是数组,有哪些办法?
40、判断一个变量是否是对象,有哪些办法?
41、对象/数组常用方法有哪些?
42、创建一个空数组/空对象有哪些方式?
43、哪些遍历方式会改变原数组?
44、Set和Map各是什么?
45、介绍一下promise。
46、Promise通常会解决三种问题
(1)链式回调
(2)同时发起几个异步请求,谁先有结果就拿谁的
(3)发起多个请求,等到所有请求后再做下一步处理
这三种方式promise是怎么处理的?
47、如何改变一个函数a的上下文?
48、Call和replay有什么区别?
49、Evenbus是什么东西?
50、Vue中普通的生命周期大概有哪些?
51、父子组件生命周期执行顺序是怎么样的?
52、mixins有几个生命周期阶段?
53、弹性布局,一行两列,一列固定宽,如何实现?
54、Flex:1 包含哪三种属性

1、vue的双向绑定原理是什么?里面的关键点在哪里?

Vue的双向绑定是指数据的变化可以自动反映到视图上,同时视图的变化也可以自动更新到数据上。这种双向绑定的实现是Vue框架的核心特性之一。

Vue的双向绑定原理主要包括以下几个关键点:

  1. 数据劫持(Data Observation):Vue通过使用Object.defineProperty()方法来劫持(监听)数据对象的属性。当数据对象的属性被访问或修改时,Vue会触发相应的getter和setter方法。

  2. 响应式系统(Reactivity System):Vue通过响应式系统来追踪数据的变化。当数据对象的属性被修改时,Vue会通知相关的视图进行更新。

  3. 模板编译(Template Compilation):Vue使用模板编译器将Vue模板转换为渲染函数。在编译过程中,Vue会解析模板中的指令和表达式,并生成对应的渲染函数。

  4. 虚拟DOM(Virtual DOM):Vue使用虚拟DOM来提高渲染性能。当数据发生变化时,Vue会生成新的虚拟DOM,并与旧的虚拟DOM进行比较,找出需要更新的部分,然后只更新需要更新的部分。

  5. 数据绑定(Data Binding):Vue使用指令(如v-model)来实现数据的双向绑定。指令会将数据对象的属性与视图元素进行绑定,当数据发生变化时,视图会自动更新;当视图发生变化时,数据也会自动更新。

总结起来,Vue的双向绑定原理是通过数据劫持、响应式系统、模板编译、虚拟DOM和数据绑定等机制来实现的。这些机制相互配合,使得数据的变化可以自动反映到视图上,同时视图的变化也可以自动更新到数据上,从而实现了双向绑定的效果。

2、实现水平垂直居中的方式?

3、常用伪元素有哪一些?常用伪类有哪一些?

常用的伪元素有以下几种:

  1. ::before:在元素内容之前插入一个伪元素。
  2. ::after:在元素内容之后插入一个伪元素。
  3. ::first-letter:选择元素内容的第一个字母。
  4. ::first-line:选择元素内容的第一行。
  5. ::selection:选择用户选中的文本部分。
  6. ::placeholder:选择表单元素的占位符文本。
  7. ::marker:选择列表项的标记部分。
  8. ::backdrop:选择模态框的背景部分。
  9. ::cue:选择音频或视频元素的提示部分(如字幕)。
  10. ::spelling-error:选择拼写错误的文本部分。
  11. ::grammar-error:选择语法错误的文本部分。

这些伪元素可以通过CSS的选择器来选择和样式化,它们可以用来在元素的特定位置插入内容、样式化选中的文本、样式化表单元素的占位符文本等,为页面提供更多的样式化和交互效果。

常用的伪类有以下几种:

  1. :hover:选择鼠标悬停在元素上的状态。
  2. :active:选择元素被激活(鼠标按下)的状态。
  3. :focus:选择元素获得焦点的状态。
  4. :visited:选择已访问过的链接。
  5. :first-child:选择父元素的第一个子元素。
  6. :last-child:选择父元素的最后一个子元素。
  7. :nth-child(n):选择父元素的第n个子元素。
  8. :nth-last-child(n):选择父元素的倒数第n个子元素。
  9. :nth-of-type(n):选择父元素的第n个指定类型的子元素。
  10. :nth-last-of-type(n):选择父元素的倒数第n个指定类型的子元素。
  11. :not(selector):选择不匹配给定选择器的元素。
  12. :empty:选择没有子元素的元素。
  13. :checked:选择被选中的表单元素(如复选框、单选框)。
  14. :disabled:选择被禁用的表单元素。
  15. :enabled:选择可用的表单元素。

这些伪类可以通过CSS的选择器来选择和样式化,它们可以用来根据元素的状态、位置、类型等进行选择和样式化,为页面提供更多的样式化和交互效果。

4、移动端如何适配不同屏幕尺寸?

5、本地存储有哪一些?他们三者有什么区别?

6、JS的数据类型?如何判断js的数据类型?

在JavaScript中,有以下几种数据类型:

  1. 基本数据类型(Primitive Data Types):

    • String(字符串):表示文本数据,使用引号(单引号或双引号)括起来。
    • Number(数字):表示数值数据,包括整数和浮点数。
    • Boolean(布尔值):表示逻辑值,只有两个值:true(真)和false(假)。
    • Undefined(未定义):表示未定义的值,通常是声明了变量但未给其赋值。
    • Null(空值):表示空值或不存在的对象。
  2. 引用数据类型(Reference Data Types):

    • Object(对象):表示复杂的数据结构,可以包含多个键值对。
    • Array(数组):表示有序的集合,可以包含多个元素。
    • Function(函数):表示可执行的代码块。
    • Date(日期):表示日期和时间。
    • RegExp(正则表达式):表示文本模式的匹配规则。

判断JavaScript数据类型的方法有多种:

  1. 使用typeof操作符:typeof操作符可以返回一个变量的数据类型,返回的结果是一个字符串。例如:typeof variable

  2. 使用instanceof操作符:instanceof操作符可以判断一个对象是否属于某个类或构造函数的实例。例如:variable instanceof Object

  3. 使用Object.prototype.toString方法:通过调用Object.prototype.toString方法,可以返回一个对象的具体类型。例如:Object.prototype.toString.call(variable)

  4. 使用typeof和null判断:由于typeof null返回"object",可以通过判断变量是否为null来判断是否为null类型。

  5. 使用Array.isArray方法:Array.isArray方法可以判断一个变量是否为数组类型。例如:Array.isArray(variable)

需要注意的是,typeof对于基本数据类型可以准确判断,但对于引用数据类型(除了函数)会返回"object",无法准确判断具体的引用数据类型。因此,结合多种方法可以更准确地判断JavaScript的数据类型。

7、说一下ES6的新特性有哪些?

ES6(ECMAScript 2015)是JavaScript的一个重要版本,引入了许多新的语法和功能。以下是ES6的一些主要特性:

  1. 块级作用域(Block Scope):引入了let和const关键字,可以在块级作用域中声明变量,解决了var关键字的变量提升和作用域问题。

  2. 箭头函数(Arrow Functions):使用箭头(=>)定义函数,简化了函数的写法,并且自动绑定了this。

  3. 模板字符串(Template Strings):使用反引号(`)包裹字符串,可以在字符串中插入变量和表达式,提供了更方便的字符串拼接方式。

  4. 解构赋值(Destructuring Assignment):可以从数组或对象中提取值,并赋给变量,简化了变量的声明和赋值过程。

  5. 默认参数(Default Parameters):在函数定义时可以为参数设置默认值,简化了函数调用时的参数传递。

  6. 扩展运算符(Spread Operator):使用三个点(…)可以将数组或对象展开,方便地进行数组合并、对象合并等操作。

  7. 类(Classes):引入了class关键字,可以使用面向对象的方式定义类和构造函数,并进行继承和方法的定义。

  8. 模块化(Modules):引入了import和export关键字,可以将代码分割成多个模块,方便地进行模块的导入和导出。

  9. Promise:提供了一种更优雅的处理异步操作的方式,解决了回调地狱的问题。

  10. 箭头函数:使用箭头(=>)定义函数,简化了函数的写法,并且自动绑定了this。

  11. 迭代器和生成器(Iterators and Generators):引入了迭代器和生成器的概念,可以更方便地进行迭代操作。

  12. 模块化(Modules):引入了import和export关键字,可以将代码分割成多个模块,方便地进行模块的导入和导出。

这只是ES6的一部分特性,还有其他一些特性如Map、Set、Promise、Symbol等。ES6的引入大大提升了JavaScript的开发效率和代码质量,成为了现代前端开发的基础。

8、Let、const、var三者有什么区别?

letconstvar是JavaScript中用于声明变量的关键字,它们之间有以下区别:

  1. 作用域:letconst都是块级作用域,而var是函数级作用域。块级作用域指的是在{}内部声明的变量只在该块内部有效,而函数级作用域指的是在函数内部声明的变量在整个函数内部都有效。

  2. 变量提升:letconst不存在变量提升,即在声明之前使用会报错,而var存在变量提升,即可以在声明之前使用变量。

  3. 重复声明:letconst不允许重复声明同一个变量,而var允许重复声明同一个变量。

  4. 可变性:letvar声明的变量可以被重新赋值,而const声明的变量是常量,不可被重新赋值。

  5. 全局对象属性:letconst声明的变量不会成为全局对象的属性,而var声明的变量会成为全局对象的属性。

综上所述,推荐使用letconst来声明变量,因为它们具有更严格的作用域和更好的代码可读性,而var在现代JavaScript中使用较少,主要是为了保持向后兼容性。

9、数组去重有哪些办法?ES6新增构造函数set,利用set具有天然去重功能 数组迭代

有多种方法可以对数组进行去重:

  1. 使用Set:将数组转换为Set,Set会自动去除重复的元素,然后再将Set转换回数组。
const arr = [1, 2, 2, 3, 3, 4, 5];
const uniqueArr = [...new Set(arr)];
console.log(uniqueArr); // [1, 2, 3, 4, 5]
  1. 使用filter和indexOf:遍历数组,使用indexOf方法判断当前元素在数组中的索引是否与当前索引相等,如果相等则保留,否则去除。
const arr = [1, 2, 2, 3, 3, 4, 5];
const uniqueArr = arr.filter((item, index) => arr.indexOf(item) === index);
console.log(uniqueArr); // [1, 2, 3, 4, 5]
  1. 使用reduce和includes:遍历数组,使用includes方法判断当前元素是否已经存在于结果数组中,如果不存在则添加到结果数组中。
const arr = [1, 2, 2, 3, 3, 4, 5];
const uniqueArr = arr.reduce((result, item) => {
  if (!result.includes(item)) {
    result.push(item);
  }
  return result;
}, []);
console.log(uniqueArr); // [1, 2, 3, 4, 5]
  1. 使用Map:遍历数组,使用Map数据结构来存储已经出现过的元素,然后将Map的键转换为数组。
const arr = [1, 2, 2, 3, 3, 4, 5];
const uniqueArr = Array.from(new Map(arr.map(item => [item, item])).values());
console.log(uniqueArr); // [1, 2, 3, 4, 5]

这些方法都可以实现数组去重,选择哪种方法取决于具体的需求和性能要求。

10、说一下深拷贝和浅拷贝,如何自己实现一个深拷贝?

深拷贝和浅拷贝是在复制对象或数组时的两种不同方式:

  • 浅拷贝:浅拷贝是指创建一个新的对象或数组,然后将原始对象或数组的引用复制给新对象或数组。这意味着新对象或数组与原始对象或数组共享相同的内存地址,当修改其中一个对象或数组时,另一个对象或数组也会受到影响。

  • 深拷贝:深拷贝是指创建一个新的对象或数组,并递归地复制原始对象或数组的所有属性或元素。这意味着新对象或数组与原始对象或数组完全独立,修改其中一个对象或数组不会影响另一个对象或数组。

要实现一个深拷贝,可以使用递归和判断数据类型的方法来复制对象或数组的所有属性或元素。下面是一个简单的实现示例:

function deepClone(obj) {
  // 判断是否为对象或数组
  if (typeof obj !== 'object' || obj === null) {
    return obj;
  }
  
  // 创建新的对象或数组
  const clone = Array.isArray(obj) ? [] : {};
  
  // 递归复制属性或元素
  for (let key in obj) {
    clone[key] = deepClone(obj[key]);
  }
  
  return clone;
}

使用示例:

const obj = {
  name: 'John',
  age: 30,
  hobbies: ['reading', 'coding'],
  address: {
    city: 'New York',
    country: 'USA'
  }
};

const cloneObj = deepClone(obj);
console.log(cloneObj);

这样就可以实现一个简单的深拷贝函数。需要注意的是,该实现只适用于普通的对象和数组,对于包含函数、正则表达式等特殊类型的对象可能会出现问题。在实际开发中,可以使用第三方库如lodash的cloneDeep方法来实现更完善的深拷贝功能。

11、Vue的生命周期有哪一些?说一下它们每个阶段做什么操作?

Vue 的生命周期包括以下几个阶段:

  1. beforeCreate:在实例初始化之后,数据观测 (data observer) 和 event/watcher 事件配置之前被调用。在这个阶段,实例的属性和方法还没有被初始化。

  2. created:在实例创建完成后被调用。在这个阶段,实例的属性和方法已经被创建,可以访问和操作。

  3. beforeMount:在挂载开始之前被调用。在这个阶段,模板编译已经完成,但是还没有将模板渲染到页面上。

  4. mounted:在挂载完成后被调用。在这个阶段,实例已经被挂载到页面上,可以进行 DOM 操作。

  5. beforeUpdate:在数据更新之前被调用,发生在虚拟 DOM 重新渲染和打补丁之前。在这个阶段,可以对数据进行修改。

  6. updated:在数据更新之后被调用,发生在虚拟 DOM 重新渲染和打补丁之后。在这个阶段,可以执行一些操作,比如访问更新后的 DOM。

  7. beforeDestroy:在实例销毁之前被调用。在这个阶段,实例仍然完全可用,可以执行一些清理操作。

  8. destroyed:在实例销毁之后被调用。在这个阶段,实例的所有事件监听器和子组件都被移除,可以进行一些最终的清理工作。

这些生命周期钩子函数可以用来在不同的阶段执行一些操作,比如初始化数据、发送网络请求、订阅事件、操作 DOM 等。通过在对应的生命周期函数中编写代码,可以实现更精细的控制和操作。

12、组件通讯方式有哪一些?

在 Vue 中,组件之间可以通过以下几种方式进行通讯:

  1. Props 和事件:父组件可以通过 props 将数据传递给子组件,子组件可以通过 $emit 触发事件并将数据传递给父组件。

  2. 自定义事件:可以使用 $emit 和 $on 在组件之间传递消息和触发事件。

  3. 中央事件总线:可以创建一个全局的 Vue 实例作为事件总线,通过 $emit 和 $on 在任意组件之间传递消息和触发事件。

  4. Vuex:Vuex 是 Vue 的官方状态管理库,可以用于管理应用的状态。通过在 Vuex 中定义状态和操作,不同组件可以通过读取和修改共享的状态来进行通讯。

  5. $refs:可以使用 $refs 来访问子组件的属性和方法。

  6. provide 和 inject:父组件可以通过 provide 提供数据,子组件可以通过 inject 注入数据。这种方式可以实现跨层级的组件通讯。

  7. EventBus:可以使用一个独立的事件总线对象来进行组件之间的通讯。

  8. $parent 和 $children:可以使用 $parent 和 $children 来访问父组件和子组件的属性和方法。

以上是常用的组件通讯方式,根据具体的场景和需求,选择合适的方式进行组件之间的通讯。

13、Vuex有几个属性及作用?

14、Vue的监听属性和计算属性有什么区别?

15、说一下防抖和节流。怎么实现?

16、Vue的导航守卫有哪一些?

17、你的登录拦截怎么实现的?

18、有用过图表吗?用的多吗?

19、闭包是什么?如何实现?

20、Vue2.0和vue3.0有什么区别?

21、Vue常用的指令有哪些?

22、v-If和v-show有什么区别?

23、v-for为什么要加一个key?

24、你是如何封装一个组件的?

25、有自己从0到1搭建过项目吗?

26、有用过uni-app吗?

27、你会写后台吗?有搞过服务端渲染吗?

28、说一下你项目中遇到的难点,如何解决?

29、Url到浏览器的一个过程有哪些步骤?

30、如何实现小程序的request封装及拦截?

31、在vue的项目应用中,不使用框架,怎么封装?

32、什么是Js原型?原型链是什么?

33、组件通讯方式有哪些?

34、用闭包的原理做过哪些?

35、作用域是什么?

36、操作数组的方式有哪些?

37、0.1 + 0.2 等于 0.3吗?为什么?如何解决?

38、keep-alive是什么?有哪几个生命周期阶段?

39、判断一个变量是否是数组,有哪些办法?

40、判断一个变量是否是对象,有哪些办法?

41、对象/数组常用方法有哪些?

42、创建一个空数组/空对象有哪些方式?

43、哪些遍历方式会改变原数组?

44、Set和Map各是什么?

45、介绍一下promise。

46、Promise通常会解决三种问题

(1)链式回调

(2)同时发起几个异步请求,谁先有结果就拿谁的

(3)发起多个请求,等到所有请求后再做下一步处理

这三种方式promise是怎么处理的?

47、如何改变一个函数a的上下文?

48、Call和replay有什么区别?

49、Evenbus是什么东西?

50、Vue中普通的生命周期大概有哪些?

51、父子组件生命周期执行顺序是怎么样的?

52、mixins有几个生命周期阶段?

53、弹性布局,一行两列,一列固定宽,如何实现?

54、Flex:1 包含哪三种属性

工具大全:https://aiburgeon.com/siteCollection/

昨天面试的时候被提问到的问题集合。,前端文章来源地址https://www.toymoban.com/news/detail-688737.html

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

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

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

相关文章

  • 软件测试面试一定会被问到的10个技术问题(附答案)

    本文记得熟读并背诵,99%通过技术二 范例回答: 一般都是让你对一个“书本”“水杯”“电梯”这些老例子做测试用例,这些答案百度一下全部都是,掌握好测试用例的方法,换成什么例子都可以讲的全面。 对方还会根据这个问题衍生出:你觉得什么样算是好测试用例,好

    2024年02月13日
    浏览(52)
  • 【Linux驱动开发100问】Linux驱动开发工程师在面试中常被问到的问题汇总

    🥇今日学习目标:什么是Kconfig?如何使用Kconfig? 🤵‍♂️ 创作者:JamesBin ⏰预计时间:10分钟 🎉个人主页:嵌入式悦翔园个人主页 🍁专栏介绍:Linux驱动开发100问 什么是Linux内核? 如何编译Linux内核? 什么是模块?如何编写和使用模块? 什么是Makefile?如何编写Makefi

    2024年02月06日
    浏览(135)
  • 若依前端问题集合[前后端分离版本]

    目录 1.若依前后端分离页面改变title 1.修改icon 2.修改title文字 2.若依关闭Login页面验证码 1.关闭验证码 登录杂项 3.若依前端替换代理地址 4.侧边菜单和全局样式 1.侧边菜单 2.侧边栏顶部logo替换或删除 3.全局样式 修改背景色 修改浏览器title和icon图标 在项目 public 文件夹中有

    2024年02月07日
    浏览(51)
  • 嵌入式面试提问

      现总结下:首先是时钟源输入时钟信号到单片机,然后单片机对输入的时钟信号进行倍频和分频处理,再将处理后的时钟信号输出至系统,外设或外部接口。   先看这张图,最外面的线上的方格是时钟相关的外部接口,OSC接口用于连接外部石英晶振时钟电路,最下面的

    2024年01月24日
    浏览(37)
  • 如何向面试官正确地提问?

    你好,我是朱显杰。今天我们来聊一聊面试时,如何向面试官正确提问。 我做过8年面试官,面试过500多人。在面试的过程中,我发现了一个普遍现象,就是大部分候选人都不知道如何向面试官正确提问。要么不问,白白浪费一次表现的机会;要么乱问,不但没有加分,还可

    2024年02月02日
    浏览(20)
  • TCP和UDP面试题提问

    @ 目录 TCP UDP 总结 应用 TCP(传输控制协议)和UDP(用户数据报协议)是两种计算机网络通信协议,它们在网络通信中起着不同的作用。 TCP 是面向连接的协议,它在数据传输之前需要在发送端和接收端建立一条连接。 TCP 提供可靠的数据传输,它使用确认和重传机制来确保数

    2024年02月19日
    浏览(37)
  • 【面试】Java面试频繁问到的题最新整理(附答案)

    封装 :对象只需要 选择性的对外公开一些属性和行为 。 继承 :子对象 可以继承父对象的属性和行为 ,并且可以在其之上进行修改以适合更特殊的场景需求。 多态 : 允许不同类的对象对同一消息做出响应 。 数据类型 占用字节 byte 1 short 2 int 4 long 8 float 4 double 8 char 2 boo

    2024年02月07日
    浏览(45)
  • 前端面试问题-JavaScript

    1 闭包 闭包就是能够读取其他函数内部变量的函数 闭包是指有权访问另⼀个函数作⽤域中变量的函数,创建闭包的最常⻅的⽅式就是在⼀个函数内创建另⼀个函数,通过另⼀个函数访问这个函数的局部变量,利⽤闭包可以突破作⽤链域 闭包的特性: 函数内再嵌套函数 内部函

    2024年02月15日
    浏览(46)
  • 前端面试:【前端安全】安全性问题与防范措施

    嗨,亲爱的前端开发者!在构建Web应用程序时,确保安全性是至关重要的。本文将深入讨论前端开发中的安全性问题,并提供一些防范措施,以确保你的应用程序和用户数据的安全性。 前端安全性问题: 跨站脚本攻击(XSS): XSS攻击发生在恶意用户将恶意脚本注入到网页中

    2024年02月11日
    浏览(44)
  • Lucene全文检索,阿里面试100%会问到的JVM

    全文检索大体分两个过程,索引创建(Indexing):将现实世界中所有的结构化和非结构化数据提取信息,搜索索引(Search):通过用户的查询请求搜索创建的索引,然后返回查询结果的过程。 Lucene实现全文检索的也同样需要这两个过程,其具体实现如下: 创建索引: 获得文档,表

    2024年03月20日
    浏览(48)

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

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

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

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

二维码1

领取红包

二维码2

领红包