小言_互联网的博客

【面试】2021年最新web前端经典面试题试题及答案(持续更新)-html/css、js、vue、http、web安全、前端性能、浏览器、js算法

304人阅读  评论(0)

阅读目录


webpack、gulp、grunt

11、前端技术体系
(1)多版本/覆盖
时间戳
发布新版本回滚
(2)ssr & 同构
(3)webpack
vendor:commonchunk
external:全局变量
默认css处理

  • webpack

webpack优化方式?

待完善

24、webpack在使用层面,对插件和loader不够理解。

  • gulp

1、

  • grunt

1、

grunt和gulp的区别?

1、易用:Gulp相比Grunt更简洁,而且遵循代码优于配置策略,维护Gulp更像是写代码。
2、高效:Gulp相比Grunt更有设计感,核心设计基于Unix流的概念,通过管道连接,不需要写中间文件。
3、高质量:Gulp的每个插件只完成一个功能,这也是Unix的设计原则之一,各个功能通过流进行整合并完成复杂的任务。例如:Grunt的imagemin插件不仅压缩图片,同时还包括缓存功能。他表示,在Gulp中,缓存是另一个插件,可以被别的插件使用,这样就促进了插件的可重用性。目前官方列出的有673个插件。
4、易学:Gulp的核心API只有5个,掌握了5个API就学会了Gulp,之后便可以通过管道流组合自己想要的任务。
5、流:使用Grunt的I/O过程中会产生一些中间态的临时文件,一些任务生成临时文件,其它任务可能会基于临时文件再做处理并生成最终的构建后文件。而使用Gulp的优势就是利用流的方式进行文件的处理,通过管道将多个任务和操作连接起来,因此只有一次I/O的过程,流程更清晰,更纯粹。
6、代码优于配置:维护Gulp更像是写代码,而且Gulp遵循CommonJS规范,因此跟写Node程序没有差别。


node

(1)nodejs 实践
(2)nodejs性能高在哪里
高并发非阻塞
IO 密集
(3)stream pipe
说不出背压机制
6、node
线上oom(通过重启,打profile,复现寻找bug点)。
基本的node性能监控
alinode等profile工具
浏览器渲染帧率、动画、性能相关,h5页面优化实践,
对小程序深度性能分析优化等方面很感兴趣
13、node服务线上的稳定,日志,安全,监控都有一定的了解,也有一定的线上运维经验


  • koa

14、koa源码了解


web安全

Web攻击方式有哪几种?

1、CSRF
2、XSS
3、SQL注入攻击

就是通过把SQL命令插入到Web表单递交或输入域名或页面请求的查询字符串,最终达到欺骗服务器执行恶意的SQL命令。

  • CSRF

CSRF基本概念和缩写?

CSRF,Cross-site request forgery,通常被称为跨站请求伪造。

CSRF攻击原理?


1、前提:①用户在注册网站A登录过,②接口有漏洞。
2、引诱点击,往往是一个链接(这个链接自动携带cookie,不会带token),指向网站A的api,接口是get类型。浏览了A,浏览器自动生成新的cookie,网站A拿到cookie,接口运行。

CSRF防御措施?

1、token验证。
注册网站,或者访问网站,服务器自动向本地存储一个token。
2、refer验证。
服务器判断页面是不是我这个站点来的页面。
3、隐藏令牌。
http的head头,不会放在链接上。

  • XSS

XSS基本概念和缩写?

XSS,cross-site scripting ,跨域脚本攻击。

XSS攻击原理?

原理:向页面注入html标签或js脚本。
eg:提交区(评论区)写img标签,script标签,利用合法渠道向页面注入js

XSS防御措施?

宗旨:让xss不可执行。
1、前端替换关键字,如替换<&lt; >&gt;
2、后台替换。
3、任何内容写到页面之前都必须加以encode,避免不小心把html tag 弄出来。

  • CSRF ,XSS的区别

CSRF ,XSS的区别?

1、XSS是向页面注入js去运行,然后在js函数体中做他想做的事情。
CSRF是利用网站漏洞,自动执行接口。用户需要登陆网站。
2、XSS是获取信息,不需要提前知道其他用户页面的代码和数据包。
CSRF是代替用户完成指定的动作,需要知道其他用户页面的代码和数据包。

  • SQL注入

SQL注入防御措施?

1、永远不要信任用户的输入,要对用户的输入进行校验,可以通过正则表达式,或限制长度,对单引号和双"-"进行转换等。
2、永远不要使用动态拼装SQL,可以使用参数化的SQL或者直接使用存储过程进行数据查询存取。
3、永远不要使用管理员权限的数据库连接,为每个应用使用单独的权限有限的数据库连接。
4、不要把机密信息明文存放,请加密或者hash掉密码和敏感的信息。


前端性能

1、原则
(1)多使用内存、缓存或者其他方法。
(2)减少cpu占用,减少网络。

提升页面性能的方法有哪些?

一、加载页面和静态资源
1、静态资源压缩合并,减少http请求。

(1)减少http请求数量
(2)减少请求资源大小
2、非核心代码异步加载。
3、静态资源缓存:通过链接名称控制缓存,只有内容改变的时候,链接名称才会改变。
4、利用浏览器缓存
5、使用cdn让资源加载更快
6、预解析dns
7、使用ssr后端渲染,数据直接输出到html中(ssr:server site render)

二、页面渲染
1、css、js及放置位置
(1)尽量避免在HTML标签中写style属性
(2)css放前面,js放后面。
(3)避免使用CSS Expression

2、图片
(1)避免图片和iFrame等的空Src。空Src会重新加载当前页面,影响速度和效率
(2)懒加载(图片懒加载,下拉加载更多)

<img id="img1" src="preview.jpg" data-realsrc="abc.jpg">
<script type="text/javascript">
var img1 = document.getElementById('img1');
img1.src = img1.getAttribute('data-realsrc');
</script>

3、dom操作
(1)减少dom查询,对dom查询做缓存。

// 未缓存dom查询
var i;
for (i = 0; i < document.getElementsByTagName('p').length; i++) {\
	// todo
}
// 缓存了dom查询
var pList = document.getElementByTagName('p');
var i;
for (i = 0; i < pList.length; i++) {
 // todo
}

(2)减少dom操作,多个操作尽量合并在一起执行。

var frag = document.createDocumentFragment(); // 片段,循环插入dom,改成先插入到片段,再append到文档流

(3)用innerHTML代替DOM操作,减少DOM操作次数,优化javascript性能
4、事件
(1)尽早执行操作(如DOMContentLoaded)
(2)事件节流

var textarea = document.getElementById('text');
var timeoutId;
textarea.addEventListener('keyup', function() {
	if(timeoutId) {
		clearTimeout(timeoutId);
	}
	timeoutId = setTimeout(function() {
		// 触发change事件
	}, 100)
})

5、代码细节优化
(1)用hash-table来优化查找
(2)多个变量声明合并
(3)少用全局变量
(4)避免全局查询
(5)避免使用with(with会创建自己的作用域,会增加作用域链长度)
(6)用setTimeout来避免页面失去响应

三、移动端性能优化
1、css
(1)不滥用Float。Float在渲染时计算量比较大,尽量减少使用
(2)不滥用Web字体。Web字体需要下载,解析,重绘当前页面,尽量减少使用。
(3)避免使用css3渐变阴影效果。
2、css动画
(1)尽量使用css3动画,开启硬件加速。
可以用transform: translateZ(0)来开启硬件加速。
CSS中的属性(CSS3 transitions、CSS3 3D transforms、Opacity、Canvas、WebGL、Video)会触发GPU渲染,请合理使用。过渡使用会引发手机过耗电增加
3、合理使用requestAnimationFrame动画代替setTimeout
4、适当使用touch事件代替click事件。

  • 非核心代码异步加载

异步加载的方式?

1、动态脚本加载
script标签,加入到body中
2、defer
加载js的时候,script标签加defer和async
3、async

异步加载的区别?

1、defer是在html解析完之后才会执行,如果是多个,按照加载的顺序依次进行。
2、async是在加载完之后立即执行,如果是多个,执行顺序和加载顺序无关。

  • 预解析dns

预解析dns的方式?

1、

<link rel="dns-prefetch" href="//host_name_to_prefetch.com">

2、强制打开a标签的dns预解析

<meta http-equiv="x-dns-prefetch-control" content="on">

页面中所有a标签,默认打开了dns预解析,如果链接是https开头的,默认关闭dns预解析


浏览器
浏览器缓存、浏览器渲染机制、浏览器渲染过程、重排reflow、重绘repaint、浏览器兼容

  • 浏览器缓存

浏览器缓存的分类?

1、强缓存

// Expires:
Expires:Thu, 21 Jan 2017 23:39:02 GMT // value值表示的是绝对时间,一般都是服务器时间,可能与客户端时间不一样
// Cache-Control:
Cache-Control: max-age=3600 // value值是以客户端时间为准

如果服务器这两个时间都下发了,以后者为准
2、协商缓存:与服务器协商是否要用,是否过期
(1)Last-Modified/ If-Modified-Since
Last-Modified: Web, 26 Jan 2017 00:35:11 GMT
(2)Etag/ If-None-Match
if-none-match的值就是服务器发过来的etag的值

与浏览器缓存相关的http头有哪些?

Expires、Cache-Control、Last-Modified、If-Modified-Since、Etag、If-None-Match

浏览器缓存的原理?

待完善

浏览器缓存的区别/ 请描述一下cookies,sessionStorage和localStorage的区别?

1、cookie
(1)本身用于客户端和服务端通信
(2)但是它有本地存储的功能,于是就被“借用”
(3)document.cookie = …获取和修改即可
(4)cookie用于存储的缺点
①存储量太小,只有4kb
②所有http请求都带着,会影响获取资源的效率
③api简单,需要封装才能用document.cookie
2、localStorage,sesseionStorage
(1)html5专门为存储而设计,最大容量5M
(2)api简单易用
(3)lcoalStorage.setItem(key, value);localStorage.getItem(key);
(4)ios safari隐藏模式下:localStorage.getItem会报错,建议统一使用try-catch封装
3、sessionStorage用于本地存储一个会话(session)中的数据,这些数据只有在同一个会话中的页面才能访问并且当会话结束后数据也随之销毁。因此sessionStorage不是一种持久化的本地存储,仅仅是会话级别的存储。而localStorage用于持久化的本地存储,除非主动删除数据,否则数据是永远不会过期的。

localstorage的超出,容错,替换方案?

1、localstorage超出:
localStorage存储空间是每个域5M,如果超出了这个空间,就会报错:QuotaExceededError
2、容错、替换方案
(1)超了申请其他的域,修改nigix配置, postmessge通信往其他域上存取。

A、B页面引用C页面,C最好是主域。
iframe.contentWindow.postMessage()
window.parent.postMessage()
(2)indexDB
(2)最简单粗暴的方法,把之前的缓存都给删了。(不推荐)

如果 localStorage 存满了,再往里存东西,或者要存的东西超过了剩余容量,会发生什么?

存不进去并报错(QuotaExceededError)

  • 浏览器渲染机制

什么是DOCTYPE及作用?

1、定义:DTD(document type definition,文档类型定义)是一系列的语法规则,用来定义XML或(X)HTML的文件类型。浏览器会使用它来判断文档类型,决定使用何种协议来解析,以及切换浏览器模式。
2、作用:DOCTYPE是用来声明文档类型和DTD规范的,一个主要的用途便是文件的合法性验证。如果文件代码不合法,那么浏览器解析时便会出一些差错。

常见的doctype有哪些?

1、HTML5: <!DOCTYPE html>
2、HTML4.01 Strict:该DTD包含所有html元素和属性,但不包括展示性的和启用的元素,如font
3、HTML 4.01 Transitional :该DTD包含所有html元素和属性,包括展示性的和启用的元素,如font

h5的doctype怎么写?

<!DOCTYPE html>

  • 浏览器渲染过程

加载资源的形式?

1、输入url(或跳转页面)加载html
http://coding.m.imooc.com
2、加载html中的静态资源

<script src="/static/js/jquery.js"></scrip>

在浏览器中输入url,从输入url到html的详细过程/加载一个资源的过程?

1、dns解析:浏览器根据dns服务器得到域名的ip地址
2、发送到服务器:向这个ip的机器发送http/https请求
3、服务器响应:服务器收到、处理并返回http/https请求
4、浏览器渲染:浏览器得到并返回内容

浏览器渲染页面的过程?

1、根据html结构生成dom Tree
2、根据css生成cssom(om:object model)
3、将dom和cssom整合行程renderTree
4、浏览器根据renderTree开始渲染和展示
5、遇到<script>,会执行并阻塞渲染

  • 重排Reflow

1、定义
也叫回流,DOM结构中的各个元素都有自己的盒子(模型),这些都需要浏览器根据各种样式来计算并根据计算结果将元素放到它该出现的位置,这个过程称之为reflow

触发reflow?

1、增加、删除、修改dom结点时,会导致reflow或repaint
2、移动dom的位置,或是搞个动画的时候
3、修改css样式
4、resize窗口的时候(移动端没有这个问题),或者是滚动的时候,有可能会触发。
5、修改网页的默认字体时

如何避免回流?

1、属性替代:避免使用触发回流的css属性
2、新建图层:将频繁重绘回流的dom元素单独作为一个独立图层,那么这个dom元素的重绘和回流的影响只会在这个图层中

  • 重绘Repaint

1、定义
当各种盒子的位置、大小及其他属性,如颜色、字体大小等都确定下来后,浏览器于是便把这些元素都按照各自的特性绘制了一遍,也是页面的内容出现了,这个过程称之为repaint
即页面呈现的内容统统画在屏幕上。

触发repaint?

1、dom改动
2、css改动

如何尽量减少repaint?

1、向浏览器中一次repaint一个节点

回流重绘的优化?

1、translate替换top,left, margin等位移属性。
top会触发回流但是translate不会
2、opacity替换visibility,但是要同时有translate3d 或 translateZ 这些可以创建的图层的属性存在才可以阻止回流。
visibility会触发重绘但不会触发回流
3、不要一条一条修改dom样式,预先定义好class,然后修改dom的class
4、可以将dom离线操作,如先display:none(会有一次reflow),但是接下来的操作都不会重绘,等离线操作结束后,再显示。
5、不要把dom节点的属性值(如offsetWidth,offsetHeight, clientWidth, clientHeight)放在循环里,当成循环的变量,

浏览器回流的缓冲机制,即多个回流会保存在一个栈里面,当这个栈满了浏览器便会一次性触发所有样式的更改且刷新这个栈。但是如果你多次获取这些元素的实际样式,浏览器为了给你一个准确的答案便会不停刷新这个缓冲栈,导致页面回流增加。
所以为了避免这个问题,应该用一个变量保存在循环体外。
offsetWidth/ offsetHeight,会强制刷新缓冲机制
6、不要使用table,table的每一行改变,甚至一个单元格的样式更新,都会导致整个table回流
7、动画实现速度的选择
8、动画新建图层
9、使用gpu加速,位置变换时,用translate,persepective
cpu走主线到gpu,会有传输损耗

触发页面回流重绘的属性?

1、盒子模型相关:
width、height、padding、border、margin、display、border-width、min-height
2、定位属性及浮动:
top、right、bottom、left、position、float、clear
3、节点内部文字结构,行内属性
text-align、overflow、line-height、vertical-align、font-weight、white-space、font-size

只触发页面重绘的属性?

color、border-style、border-radius、visibility、background、box-shadow、outline

  • 浏览器兼容

你做的页面在哪些流览器测试过, 这些浏览器的内核分别是什么?

IE6、7、8、FF、Opera、Safari、Chrome、Maxthon
IE: trident内核。除 IE 外,众多的 IE Shell(如 Maxthon )都使用trident这个内核。
Firefox:gecko内核
Safari:webkit内核
Opera:以前是presto内核,Opera现已改用Google Chrome的Blink内核
Chrome:Blink(基于webkit,Google与Opera Software共同开发)

经常遇到的浏览器兼容问题?

1、在有的浏览器中,默认字体大小为12px,所以在设字体大小的时候,最小设为12px,如果在做的过程中,发现字体小于12,可直接作为图片使用
2、a标签对里不能嵌套a标签对
3、若给a标签内的内容样式加上样式,需要设置display:block;(在IE中如果设置宽高会自动变成块,在FF中则不会),但如果设置了float属性,就不需要设置display:block。
4、ul,ol在FF默认情况下,有list-style-type样式和padding值,dl在IE和FF默认情况下,有padding值,所以应该事先声明ul,li,ol,dl,dd,dd{margin:0;padding:0}。
5、作为外部 wrapper 的 div 不要定死高度, 最好还加上 overflow: hidden.以达到高度自适应
6、关于手形光标cursor: pointer而hand 只适用于 IE.
7、css布局中的居中问题:在父级元素定义TEXT-ALIGN: center;这个的意思就是在父级元素内的内容居中;对于IE这样设定就已经可以了。但在mozilla中不能居中。解决办法就是在子元素定义时候设定时再加上“margin-right: auto;margin-left: auto; ”需要说明的是,如果你想用这个方法使整个页面要居中,建议不要套在一个DIV里,你可以依次拆出多个div,只要在每个拆出的div里定义margin-right: auto;margin-left: auto; 就可以了。
8、浮动ie产生的双倍距离

#box{ float:left; width:100px; margin:0 0 0 100px; // 这种情况之下IE会产生200px的距离,这时需要设置display:inline; 使浮动忽略}

算法相关

通常情况下,搞金融的都会考算法。
一、排序

快速排序:https://segmentfault.com/a/1190000009426421
选择排序:https://segmentfault.com/a/1190000009366805
希尔排序:https://segmentfault.com/a/1190000009461832
二、堆栈、队列、链表
堆栈:https://juejin.im/entry/58759e79128fe1006b48cdfd
队列:https://juejin.im/entry/58759e79128fe1006b48cdfd
链表:https://juejin.im/entry/58759e79128fe1006b48cdfd
(1)js数组本身就具备堆栈和队列特性。
(2)堆栈:先进后出。
三、递归
递归:https://segmentfault.com/a/1190000009857470
(1)60%的算法题都用到递归。
四、波兰式和逆波兰式
理论:http://www.cnblogs.com/chenying99/p/3675876.html
源码:https://github.com/Tairraos/rpn.js/blob/master/rpn.js

手写一个冒泡排序?

1、比较两个相邻的元素,如果后一个比前一个大,则交换位置。
2、 第一轮的时候最后一个元素应该是最大的一个。
3、按照第一步的方法进行两个相邻的元素的比较,由于最后一个元素已经是最大的了,所以最后一个元素不用比较。

 function bubbleSort(arr) {
    let len = arr.length;
    for (let i = 0; i < len; i++) {
       for (let j = 0; j < len - i - 1; j++) { // j=0时,得到最大的元素,放在了最后面
         if (arr[j] > arr[j+1]) {
           [arr[j], arr[j+1]] = [arr[j+1], arr[j]];
         }
       }
    }
    return arr;
  }
  let arr = [3,5,1,2,7,8,4,5,3,4];
  let sortedArr = bubbleSort(arr);
  console.log(sortedArr);

快速排序的思想?

1、在数据集之中,找一个基准点,将数据分成两个部分,一部分比另外一部分所有的数据都要小,
2、建立两个数组,分别存储左边和右边的数组
3、利用递归进行下次比较

手写一个快速排序?

 function quickSort(arr) {
    if (arr.length <= 1) { // 如果数组长度小于等于1无需判断直接返回即可
      return arr;
    }
    var pivotIndex = Math.floor(arr.length / 2); // 取基准点
    var pivot = arr.splice(pivotIndex, 1)[0]; // 取基准点的值,splice(index,1)函数可以返回数组中被删除的那个数
    var left = []; // 存放比基准点小的数组
    var right = []; // 存放比基准点大的数组
    for (var i = 0; i < arr.length; i++) {  // 遍历数组,进行判断分配
      if (arr[i] < pivot) {
        left.push(arr[i]); // 比基准点小的放在左边数组
      } else {
        right.push(arr[i]); // 比基准点大的放在右边数组
      }
    }
    //递归执行以上操作,对左右两个数组进行操作,直到数组长度为<=1;
    return quickSort(left).concat([pivot], quickSort(right));
  };
  var arr = [1, 2, 3, 55, 7, 99, 8, 100, 1021];
  var sortedArr = quickSort(arr);
  console.log(sortedArr);

设计模式

用过哪些设计模式?

1、工厂模式:

主要好处就是可以消除对象间的耦合,通过使用工程方法而不是new关键字。将所有实例化的代码集中在一个位置防止代码重复。
工厂模式解决了重复实例化的问题 ,但还有一个问题,那就是识别问题,因为根本无法搞清楚他们到底是哪个对象的实例。

function createObject(name,age,profession){//集中实例化的函数var obj = newObject();
    obj.name =name;
    obj.age = age;
    obj.profession= profession;
    obj.move =function () {
        returnthis.name + ' at ' + this.age + ' engaged in ' + this.profession;
    };
    return obj;
}
var test1 = createObject('trigkit4',22,'programmer');//第一个实例
var test2 =createObject('mike',25,'engineer');//第二个实例

2、构造函数模式
使用构造函数的方法 ,即解决了重复实例化的问题 ,又解决了对象识别的问题,该模式与工厂模式的不同之处在于:
①构造函数方法没有显示的创建对象 (new Object());
②直接将属性和方法赋值给 this 对象;
③没有 renturn 语句。

  • MVVM

对mvvm的理解?

1、MVVM 是 Model-View-ViewModel 的缩写。
2、Model代表数据模型,也可以在Model中定义数据修改和操作的业务逻辑。
3、View 代表UI 组件,它负责将数据模型转化成UI 展现出来。
4、ViewModel 监听模型数据的改变和控制视图行为、处理用户交互,简单理解就是一个同步View 和 Model的对象,连接Model和View。
5、在MVVM架构下,View 和 Model 之间并没有直接的联系,而是通过ViewModel进行交互,Model 和 ViewModel 之间的交互是双向的, 因此View 数据的变化会同步到Model中,而Model 数据的变化也会立即反应到View 上。
ViewModel 通过双向数据绑定把 View 层和 Model 层连接了起来,而View 和 Model 之间的同步工作完全是自动的,无需人为干涉,因此开发者只需关注业务逻辑,不需要手动操作DOM, 不需要关注数据状态的同步问题,复杂的数据状态维护完全由 MVVM 来统一管理。

mvvm框架实现的三要素/ vue的三要素?

1、响应式:vue如何监听到data的每个属性变化?
(1)修改data属性后,vue立刻监听到。Object.defineProperty

var __name = 'may';
Object.defineProperty(obj, 'name',{
	get: function() {
		return __name;
	},
	set: function(newVal) {
		__name = newVal; // 修改__name = 'april',obj.name就会变成april
	}
})

(2)data属性代理到vm上
2、模板引擎:vue的模板如何被解析,指令如何处理?
(1)模板是什么
①本质:字符串
②有逻辑,如v-if, v-for等
③与html格式很像,但有很大区别
④模板最终必须转换成Js代码(js函数-render函数),因为
有逻辑(v-if, v-for),必须用js才能实现(图灵完美语言)
转换为html渲染页面,必须用js才能实现
(2)render函数
(3)render函数与vdom
3、渲染:vue的模板如何被渲染成Html?以及渲染过程?


正则表达式

写一个function,清除字符串前后的空格。(兼容所有浏览器)?

function trim(str) {
	if (str && typeof str === 'string') {
		return str.replace(/(^\s*)|(\s*)$/g, '');
	}
}

hybrid

15、hybrid业务开发经验,对离线包机制熟悉,多各种优化方案也了解得比较清楚。

7、离线包加载和更新机制,
22、servive worker, web worker


全栈

8、图片加载的一个细节,能够从全栈角度给出一些高并发情况下的系统扩展思路
27、跨域access-control-allow-origin多域名白名单处理
cdn部署
前端框架选型
人员协调项目延期
整个部门没有用到mock平台,前后端分离
自己写了服务在服务端用webpack+multi方式融合不同的业务模块打包
Mbox的数据管理方案(mbox的数据状态流转机制)
数据库,数据索引,事务,数据库锁的问题

5、前端核心监控数据来源(performance api + 业务定义为主)

31、逻辑外链如何保持多个数据同步

项目

16、资讯类的项目,有哪些技术特点(本想了解list相关的回答)
详情里面做了哪些
详情页对性能要求高,有哪些优化?配置缓存来优化。
缓存如何配置,
哪些缓存头来控制的缓存
类似静态化的性能优化,采用ssr比较适合详情页的技术
1、哪些工作是偏技术的,需要技术来解决的

svn、git

get fetch、git pull的区别

1、git fetch是将远程主机的最新内容拉到本地,用户在检查了以后决定是否合并到工作本机分支中。
2、git pull 则是将远程主机的最新内容拉下来后直接合并,即:git pull = git fetch + git merge,这样可能会产生冲突,需要手动解决。


转载:https://blog.csdn.net/aSuncat/article/details/88674643
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场