本站消息

站长简介/公众号

  出租广告位,需要合作请联系站长


+关注
已关注

分类  

暂无分类

标签  

暂无标签

日期归档  

2024-11(5)

前端面试题综合

发布于2021-05-30 12:06     阅读(1432)     评论(0)     点赞(11)     收藏(1)


1: http有几种请求方式?

 8种

   Get:请求指定的页面信息,并返回实体主体

   Post:向指定资源提交数据进行处理请求(例如提交表单或者上传文件)。数据被包含在请求体中,post请求可能会导致新的资源的建立和/或已有资源的修改

   Head:类似于get请求,只不过返回的响应中没有具体的内容,用于获取报头

   Options:允许客户端查看服务器的性能

   Put:从客户端向服务器传送的数据取代指定的文档的内容

   Delete:请求服务器删除指定的页面

   Trace:回显服务器收到的请求,主要用于测试或诊断

   Connect:http/1.1协议中预留给能够将连接改为管道方式的代理服务器

2:常用布局有哪些?

Flex弹性布局:**row column 其中justify-content决定主轴上的对齐方式

Grid布局:grid-template-columns / grid-template-rows  row-gap行间距,column-gap是列间距,gap是行列间距 justify-items属性设置单元格内容即子元素的水平位置(左中右),align-items属性设置单元格内容的垂直位置(上中下)

多列布局(Multi-column Layout):column-width / column-count / columns   ,column-rule / column-rule-color /column-rule-style / column-rule-width

这几个属性控制每一个列之间的分割线的样式

流式布局(百分比布局): 百分比是基于元素父级的大小计算得来的;元素的水平或者竖直间距都是相对于父级的宽度计算的.(margin&padding); 边框不能用百分比设置‘

定位布局:1:(fixed固定布局)position: fixed;left: 50%;top: 50%;   2:(绝对定位)父元素relative 子元素position: absolute;left: 50%;top: 20%;

浮动布局:1:固定布局 div1:float: left; div2:float: left; 2:流体布局写法 div1:float: left; div2:margin-left:??px;2:浮动加两侧流体: div1:float: left; div2:margin-left: 浮动布局一定要记得清除浮动影响..
clearfix:after {
				content: '';
				display: table;
				clear: both;
			}

3:CSS选择器有哪些?哪些属性可以继承?CSS优先级算法如何计算?

(1)类选择器、ID选择器、标签选择器、通用选择器
(2)css继承特性主要是指文本方面的继承,盒模型相关的属性基本没有继承特性。
不可继承的:
display、margin、border、padding、background、height、min-height、max-height、width、min-width、max-width、overflow、position、top、bottom、left、right、z-index、float、clear、 table-layout、vertical-align、page-break-after、page-bread-before和unicode-bidi。
所有元素可继承的:
visibility和cursor
终极块级元素可继承的:
text-indent和text-align
内联元素可继承的:
letter-spacing、word-spacing、white-space、line-height、color、font、font-family、font-size、font-style、font-variant、font-weight、text-decoration、text-transform、direction
列表元素可继承的:
list-style、list-style-type、list-style-position、list-style-image
(3)第一等:代表内联样式,如: style=””,权值为1000。
第二等:代表ID选择器,如:#content,权值为0100。
第三等:代表类,伪类和属性选择器,如.content,权值为0010。
第四等:代表类型选择器和伪元素选择器,如div p,权值为0001。
通配符、子选择器、相邻选择器等的。如*、>、+,权值为0000。
继承的样式没有权值。

4:盒模型

盒子模型有两种:IE 盒子模型(IE5.5及以下),W3C标准盒子模型。
盒子模型: 内容(content)、填充(padding)、边框(border)、边界(margin) 。

不同:
(1)W3C标准盒子模型的width和height,是content的宽高;
(2)IE盒模型的width和height,是content、padding、border三部分合起来的宽高。

5:css样式优先级

// 同权重下,权限由高到低: 
1.元素标签里(行内样式/内联样式)
2.写在<style>标签里(嵌入样式)
3.写在单独的 CSS 样式表中(链接样式)
4.在样式表中链接其他样式表:@import url(css/styles2.css)

// 不同权重计算
!important >  id > class > tag:

6:CSS3有哪些新特性?

1:圆角 (border-radius:8px)
2:新增各种CSS选择器、伪类 (经常用到 :nth-child):
3:文字渲染 (Text-decoration)转化为简写属性,可设置text-decoration-color, text-decoration-style, text-decoration-line三个属性,默认值为currentcolor solid none。
4:透明色 & 透明度(opacity):
5:旋转 (transform)旋转 rotate,缩放 scale,倾斜 skew,平移 translate
6:动画(animation) & 过渡效果(transition):
7:阴影(box-shadow, text-shadow)
box-shadow: x-offset y-offset blur-radius spread-radius color;
text-shadow: x-offset y-offset blur-radius color;
8:新的布局方式,如 多列布局 multi-columns 、 弹性布局 flexible box 与 网格布局 grid layouts:
9:线性渐变(gradient)
10:多背景(background-image可以设置多个url或linear-gradient):
11:媒体查询(@media MDN) (可以看看这个)
12:边框可以设置图片(border-image)
...

7:水平居中

已知宽度

(1)用margin:0 auto属性
	width:200px;
	margin:0 auto;
(2)绝对定位的div居中
	position: absolute;
	width: 300px;
	height: 300px;
	margin: auto; /* 这一步很关键 */
	top: 0;
	left: 0;
	bottom: 0;
	right: 0;

未知宽度

(1)(兼容性很差。)
    width: fit-content;
    margin: auto;
(2) inline-block
    display: inline-block;
(3)用float或inline-block,使容器大小为内容大小,而非默认的100%
 	display: inline-block;
	position: relative;
	left: 50%;

8:水平垂直居中

(1)确定高宽的

相对或绝对定位, 设置外边距margin为自身高度的一半。
div {
	position: relative / fixed; /* 相对定位或绝对定位均可 */
	width:500px;
	height:300px;
	top: 50%;
	left: 50%;
	margin: -150px 0 0 -250px;  /* 外边距为自身宽高的一半 */
 }

(2)不确定容器宽高

绝对定位,利用 transform 属性。
div {
	position: absolute/fixed; /* relative会让width变成100%,所以不行 */
	top: 50%;
	left: 50%;
	transform: translate(-50%, -50%);
	background-color: pink; /* 方便看效果 */
}

(3)宽高确定无所谓

flex布局。
.div{
	display: flex;
	align-items: center; 		/* 垂直居中 */
	justify-content: center;	/* 水平居中 */
}
inline-block.
.container {
    height: 200px; /* 垂直居中 */
    line-height: 200px; /* 垂直居中 */
    text-align: center; /* 水平居中 */
}
.container div {
    display: inline-block; /* 核心:宽度自适应,高度可居中 */
    line-height: 20px; /* 会自动继承,必须设置不同的值来覆盖 */
    vertical-align: middle; /* 垂直居中 */
}  

9:判断数据类型

(() => {
	//数组类型
	let a = Array.from("123");
	console.log(typeof(a));
	console.log(a instanceof Array); //不适用判断原始值类型,只能判断原型对象的从属关系
	console.log(a.__proto__.constructor == Array); //原理:每一个实例对象都可通过constructor来访问它的构造函数,其实也是根据原型链的原理来的
	console.log(Object.prototype.toString.call(a)); //Object.prototype.toString方法返回对象的类型字符串
})()

10:是否可以中止promise请求?

就是pending进入reject,不能中止

增加知识点:Promise :异步编程
					三个状态【pending(进行中)、fulfilled(已成功)和rejected(已失败)】
					全对走all,遇到第一个修改的就触发race
					走了第一个resolve回调后,接下来再写就失效。

11:中止ajax请求?

(1)jquery: $.ajax({}).abort()

var request = $.ajax({  
           type:'POST',  
           beforeSend:function(){},  
           url:'test.php',  
           data:'username=xxx',  
           dataType:'JSON',  
           error:function(){alert('error')},  
           success:function(data){alert(data)}  
    });  
  if(request) {request.abort();}  

(2)axios: axios.CancelToken

var CancelToken = axios.CancelToken;
var source = CancelToken.source();

axios.get('/user/12345', {
  cancelToken: source.token
}).catch(function(thrown) {
  if (axios.isCancel(thrown)) {
    console.log('Request canceled', thrown.message);
  } else {
    // 处理错误
  }
});

// 取消请求(message 参数是可选的)
source.cancel('Operation canceled by the user.');

12:闭包

闭包简单来说就是函数嵌套函数,内部函数引用来外部函数的变量,从而导致垃圾回收机制没有把当前变量回收掉,这样的操作带来了内存泄漏的影响,当内存泄漏到一定程度会影响你的项目运行变得卡顿等等问题。因此在项目中我们要尽量避免内存泄漏。
本质:当前环境中存在指向父级作用域的引用
一般如何产生闭包:返回函数;函数当做参数传递

13:作用域、作用域链

什么是作用域?
ES5 中只存在两种作用域:全局作用域和函数作用域。在 JavaScript 中,我们将作用域定义为一套规则,这套规则用来管理引擎如何在当前作用域以及嵌套子作用域中根据标识符名称进行变量(变量名或者函数名)查找

什么是作用域链?
首先要了解作用域链,当访问一个变量时,编译器在执行这段代码时,会首先从当前的作用域中查找是否有这个标识符,如果没有找到,就会去父作用域查找,如果父作用域还没找到继续向上查找,直到全局作用域为止,,而作用域链,就是有当前作用域与上层作用域的一系列变量对象组成,它保证了当前执行的作用域对符合访问权限的变量和函数的有序访问。

14:基本数据类型

基本类型:Number、Boolean、String、null、undefined、symbol(ES6 新增的),BigInt(ES2020) 
引用类型:Object,
对象子类型(Array,Function)

15:函数中的arguments是数组吗?类数组转数组的方法了解一下?

是类数组,是属于鸭子类型的范畴,长得像数组,
... 运算符
Array.from
Array.prototype.slice.apply(arguments)

16:知道 ES6 的 Class 嘛?Static 关键字有了解嘛

为这个类的函数对象直接添加方法,而不是加在这个函数对象的原型对象上

17:数组扁平化(手写)

function flatten(arr) {
  let result = [];

  for (let i = 0; i < arr.length; i++) {
    if (Array.isArray(arr[i])) {
      result = result.concat(flatten(arr[i]));
    } else {
      result = result.concat(arr[i]);
    }
  }

  return result;
}
const a = [1, [2, [3, 4]]];
console.log(flatten(a));

18:数组去重

Array.from(new Set([1, 1, 2, 2]))

19:变量提升

函数在运行的时候,会首先创建执行上下文,然后将执行上下文入栈,然后当此执行上下文处于栈顶时,开始运行执行上下文。
在创建执行上下文的过程中会做三件事:创建变量对象,创建作用域链,确定 this 指向,其中创建变量对象的过程中,首先会为 arguments 创建一个属性,值为 arguments,然后会扫码 function 函数声明,创建一个同名属性,值为函数的引用,接着会扫码 var 变量声明,创建一个同名属性,值为 undefined,这就是变量提升。

20:箭头函数和普通函数有啥区别?箭头函数能当构造函数吗?

普通函数通过 function 关键字定义, this 无法结合词法作用域使用,在运行时绑定,只取决于函数的调用方式,在哪里被调用,调用位置。(取决于调用者,和是否独立运行)
箭头函数使用被称为 “胖箭头” 的操作 => 定义,箭头函数不应用普通函数 this 绑定的四种规则,而是根据外层(函数或全局)的作用域来决定 this,且箭头函数的绑定无法被修改(new 也不行)。

箭头函数常用于回调函数中,包括事件处理器或定时器
箭头函数和 var self = this,都试图取代传统的 this 运行机制,将 this 的绑定拉回到词法作用域
没有原型、没有 this、没有 super,没有 arguments,没有 new.target
不能通过 new 关键字调用

一个函数内部有两个方法:[[Call]] 和 [[Construct]],在通过 new 进行函数调用时,会执行 [[construct]] 方法,创建一个实例对象,然后再执行这个函数体,将函数的 this 绑定在这个实例对象上
当直接调用时,执行 [[Call]] 方法,直接执行函数体
箭头函数没有 [[Construct]] 方法,不能被用作构造函数调用,当使用 new 进行函数调用时会报错。

21:函数

函数声明

//ES5
function getSum(){}
function (){}//匿名函数
//ES6
()=>{}//如果{}内容只有一行{}和return关键字可省,

函数表达式

//ES5
var sum=function(){}
//ES6
let sum=()=>{}//如果{}内容只有一行{}和return关键字可省,

构造函数

var sum=new GetSum(num1,num2)
注意:箭头函数不可以当构造函数使用
三种对比:
1.函数声明有预解析,而且函数声明的优先级高于变量;
2.使用Function构造函数定义函数的方式是一个函数表达式,这种方式会导致解析两次代码,影响性能。第一次解析常规的JavaScript代码,第二次解析传入构造函数的字符串

22:this指向

(1)包括函数名()和匿名函数调用,this指向window
(2)对象.方法名(),this指向对象
(3)new 构造函数名(),this指向构造函数
(4)间接调用:利用call和apply来实现,this就是call和apply对应的第一个参数,如果不传值或者第一个值为null,undefined时this指向window

23:bind

bind是function的一个函数扩展方法,bind以后代码重新绑定了func内部的this指向,不会调用方法,不兼容IE8


var name = '李四';
var foo = {
		name: "张三",
		logName: function(age) {
			console.log(this.name, age);
		}
}
var fooNew = foo.logName;
var fooNewBind = foo.logName.bind(foo);
fooNew(10); //10
fooNewBind(11); //张三,11  因为bind改变了fooNewBind里面的this指向

24:两个函数实现继承

function Animal(name){   
  this.name = name;   
  this.showName = function(){   
    console.log(this.name);   
  }   
}   
function Cat(name){  
  Animal.call(this, name);  
}    
var cat = new Cat("Black Cat");   
cat.showName(); //Black Cat

25:数组 Array.prototype

为类数组(arguments和nodeList)添加数组方法push,pop
(function(){
  Array.prototype.push.call(arguments,'王五');
  console.log(arguments);//['张三','李四','王五']
})('张三','李四')
合并数组
let arr1=[1,2,3]; 
let arr2=[4,5,6]; 
Array.prototype.push.apply(arr1,arr2); //将arr2合并到了arr1中
console.log(arr1)
console.log(arr1.concat(arr2)); //将arr2合并到了arr1中
console.log([...arr1,...arr2]) //将arr2合并到了arr1中
求数组最大值
console.log(Math.max.apply(null, ary)); //322
console.log(eval("Math.max(" + ary + ")")); //322
console.log(Math.max(...ary));//322
判断字符类型
Object.prototype.toString.call({})

26:原型、原型链

原型:
JavaScript中的对象都有一个特殊的 prototype 内置属性,其实就是对其他对象的引用
几乎所有的对象在创建时 prototype 属性都会被赋予一个非空的值,我们可以把这个属性当作一个备用的仓库
当试图引用对象的属性时会出发get操作,第一步时检查对象本身是否有这个属性,如果有就使用它,没有就去原型中查找。一层层向上直到Object.prototype顶层。

原型链:
原型链实际上在上面原型的问题中就有涉及到,在原型的继承中,我们继承来多个原型,这里再提一下实现完美
继承的方案,通过借助寄生组合继承,PersonB.prototype = Object.create(PersonA.prototype)
这是当我们实例化PersonB得到实例化对象,访问实例化对象的属性时会触发get方法,它会先在自身属性上查
找,如果没有这个属性,就会去__proto__中查找,一层层向上直到查找到顶层对象Object,这个查找的过程
就是原型链来。

掘金原型链

27:常见设计模式

工厂模式

//1:局限:使用工厂创建对象,使用的构造函数都是object,导致开发者无法区分多种不同类型的对象,如狗类为object人也是object,升级版为构造函数
//2:使用:创建人和狗都是object

function createPerson(name, age) {(创建人)
	// 创建一个新对象
	var obj = new Object();
	obj = {
		name: name,
		age: age,
		sayname: () => {
			console.log(this.name);
		}
	}
	//将新对象返回
	return obj;
}
var obj2 = createPerson("O--p1", 10);
var obj3 = createPerson("O--p2", 10);
console.log(obj2); //{name: "O--p1", age: 10, sayname: ƒ}
console.log(obj3); //{name: "O--p2", age: 10, sayname: ƒ}

function createDog(name, age) {(创建狗)
....


// 构造函数创建人
function Person(name) {
		// console.log(this); //Person{}
		this.name = name;

};
var per1 = new Person("G--p1");
var per2 = new Person("G--p2");
console.log(per1); //Person {name: "G--p1"}
console.log(per2); //Person {name: "G--p2"}
//创建狗
...

// instanceof可以检查一个对象是否是一个类的实例!!构造函数就是一个类
console.log(gd1 instanceof Dog); //true       (构造函数的狗)
console.log(gd1 instanceof Person); //false    (构造函数的人)
console.log(obj2 instanceof Object); //true		(工厂人)
console.log(gd1 instanceof Object); //true		(构造函数的狗)

单例模式

// 单体模式
var Singleton = function(name){
    this.name = name;
};
Singleton.prototype.getName = function(){
    return this.name;
}
// 获取实例对象
var getInstance = (function() {
    var instance = null;
    return function(name) {
        if(!instance) {//相当于一个一次性阀门,只能实例化一次
            instance = new Singleton(name);
        }
        return instance;
    }
})();
// 测试单体模式的实例,所以a===b
var a = getInstance("aa");
var b = getInstance("bb");  

发布者订阅模式:(vue采用)
代码实现逻辑是用数组存贮订阅者, 发布者回调函数里面通知的方式是遍历订阅者数组,并将发布者内容传入订阅者数组

//发布者与订阅模式
    var shoeObj = {}; // 定义发布者
    shoeObj.list = []; // 缓存列表 存放订阅者回调函数
 // 增加订阅者
    shoeObj.listen = function(fn) {
        shoeObj.list.push(fn); // 订阅消息添加到缓存列表
    }

// 发布消息
    shoeObj.trigger = function() {
            for (var i = 0, fn; fn = this.list[i++];) {
                fn.apply(this, arguments);//第一个参数只是改变fn的this,
            }
        }
// 小红订阅如下消息
    shoeObj.listen(function(color, size) {
        console.log("颜色是:" + color);
        console.log("尺码是:" + size);
    });

// 小花订阅如下消息
    shoeObj.listen(function(color, size) {
        console.log("再次打印颜色是:" + color);
        console.log("再次打印尺码是:" + size);
    });
    shoeObj.trigger("红色", 40);
    shoeObj.trigger("黑色", 42);  

28:vue原理

Vue是采用数据劫持配合发布者-订阅者模式,通过Object.defineProperty来()来劫持各个属性的getter和setter
在数据发生变化的时候,发布消息给依赖收集器,去通知观察者,做出对应的回调函数去更新视图。

具体就是:
MVVM作为绑定的入口,整合Observe,Compil和Watcher三者,通过Observe来监听model的变化
通过Compil来解析编译模版指令,最终利用Watcher搭起Observe和Compil之前的通信桥梁
从而达到数据变化 => 更新视图,视图交互变化(input) => 数据model变更的双向绑定效果。

29:Vue路由守卫有哪些,怎么设置,使用场景等

常用的两个路由守卫:router.beforeEach 和 router.afterEach

每个守卫方法接收三个参数:

to: Route: 即将要进入的目标 路由对象

from: Route: 当前导航正要离开的路由

next: Function: 一定要调用该方法来 resolve 这个钩子。

在项目中,一般在beforeEach这个钩子函数中进行路由跳转的一些信息判断。
判断是否登录,是否拿到对应的路由权限等等。

30:说一说SessionStorage和localStorage还有cookie

共同点:都是保存在浏览器端、且同源的
不同点:
    1.cookie数据始终在同源的http请求中携带(即使不需要),即cookie在浏览器和服务器间来回传递。
    cookie数据还有路径(path)的概念,可以限制cookie只属于某个路径下
    sessionStorage和localStorage不会自动把数据发送给服务器,仅在本地保存。
    2.存储大小限制也不同,cookie数据不能超过4K,sessionStorage和localStorage可以达到5M
    3.sessionStorage:仅在当前浏览器窗口关闭之前有效;
    localStorage:始终有效,窗口或浏览器关闭也一直保存,本地存储,因此用作持久数据;
    cookie:只在设置的cookie过期时间之前有效,即使窗口关闭或浏览器关闭
    4.作用域不同
    sessionStorage:不在不同的浏览器窗口中共享,即使是同一个页面;
    localstorage:在所有同源窗口中都是共享的;也就是说只要浏览器不关闭,数据仍然存在
    cookie: 也是在所有同源窗口中都是共享的.也就是说只要浏览器不关闭,数据仍然存在

31:vue通信

1.props和$emit
2.中央事件总线 EventBus(基本不用)
3.vuex(官方推荐状态管理器)
4.$parent和$children
当然还有一些其他办法,但基本不常用,或者用起来太复杂来。 介绍来通信的方式,还可以扩展说一下使用
场景,如何使用,注意事项之类的。

(1)父子组件传值:(二种传值:一个是props,一个是refs)
props:
父: <v-header  :msg="msg" :fatherFunction="fatherFunction"  //父组件传递方法时不加()  :home="this"   ></v-header>
子:props: { msg: String, fatherFunction: Function, home: Object },  
	console.log(this.home.msg); //获得父组件的内容
     this.home.fatherFunction("我是父组件的方法"); //执行父组件的方法
     
refs:
父: <v-header :msg="msg" :fatherFunction="fatherFunction" :home="this" ref="header"></v-header>
	1:调用子组件的时候定义一个ref;
    2:在父组件拿到子组件的内容/方法通过
     `this.$refs.header.属性  
      this.$refs.header.方法` 
 子:
	1:调用子组件的时候定义一个ref;
    2:在子组件拿到父组件的内容/方法 
    `this.$parent.数据   
     this.$parent.方法`

(2)非父子组件传值:(一种传值:$emit)
1:新建一个js文件,例:VueEvent.js 引入vue 实例化vue 暴露这个实例
import Vue from 'vue';
var VueEvent=new Vue();//新建这个实例
export default VueEvent;//暴露这个实例
2:在需要广播的地方引入这个实例
import VueEvent from "../model/VueEvent.js";
发送: 通过VueEvent.$emit(名,数据)
 VueEvent.$emit("to-home", this.msg);
接收: 通过VueEvent.$on(名,方法)
 VueEvent.$on("to-home", (data) => {
      console.log(data);
 });


32:陈述输入URL回车后的过程

1.读取缓存: 
        搜索自身的 DNS 缓存。(如果 DNS 缓存中找到IP 地址就跳过了接下来查找 IP 地址步骤,直接访问该 IP 地址。)
2.DNS 解析:将域名解析成 IP 地址
3.TCP 连接:TCP 三次握手,简易描述三次握手
           客户端:服务端你在么? 
           服务端:客户端我在,你要连接我么? 
           客户端:是的服务端,我要链接。 
           连接打通,可以开始请求来
4.发送 HTTP 请求
5.服务器处理请求并返回 HTTP 报文
6.浏览器解析渲染页面
7.断开连接:TCP 四次挥手

关于第六步浏览器解析渲染页面又可以聊聊如果返回的是html页面
根据 HTML 解析出 DOM 树
根据 CSS 解析生成 CSS 规则树
结合 DOM 树和 CSS 规则树,生成渲染树
根据渲染树计算每一个节点的信息
根据计算好的信息绘制页面

33:http

(1)基本概念:
HTTP,全称为 HyperText Transfer Protocol,即为超文本传输协议。是互联网应用最为广泛的一种网络协议
所有的 www 文件都必须遵守这个标准。

(2)http特性:
HTTP 是无连接无状态的
HTTP 一般构建于 TCP/IP 协议之上,默认端口号是 80
HTTP 可以分为两个部分,即请求和响应。

(3)http请求:
HTTP 定义了在与服务器交互的不同方式,最常用的方法有 4 种
分别是 GET,POST,PUT, DELETE。URL 全称为资源描述符,可以这么认为:一个 URL 地址
对应着一个网络上的资源,而 HTTP 中的 GET,POST,PUT,DELETE 
就对应着对这个资源的查询,修改,增添,删除4个操作。

HTTP 请求由 3 个部分构成,分别是:状态行,请求头(Request Header),请求正文。
HTTP 响应由 3 个部分构成,分别是:状态行,响应头(Response Header),响应正文。
HTTP 响应中包含一个状态码,用来表示服务器对客户端响应的结果。
状态码一般由3位构成:
1xx : 表示请求已经接受了,继续处理。
2xx : 表示请求已经处理掉了。
3xx : 重定向。
4xx : 一般表示客户端有错误,请求无法实现。
5xx : 一般为服务器端的错误。




所属网站分类: 技术文章 > 博客

作者:听说你很拽

链接:http://www.qianduanheidong.com/blog/article/115973/e288be1ed558d4681266/

来源:前端黑洞网

任何形式的转载都请注明出处,如有侵权 一经发现 必将追究其法律责任

11 0
收藏该文
已收藏

评论内容:(最多支持255个字符)