Aiden's blog Aiden's blog
首页
  • 前端文章

    • JavaScript
    • Vue
  • 学习笔记

    • JavaScript教程
    • JavaScript高级程序设计
    • ES6 教程
    • Vue
    • Vue3.0
    • React
    • TypeScript 从零实现 axios
    • Git
    • TypeScript
    • JS设计模式总结
    • 小程序
    • 小程序云开发
    • Echarts
    • 微前端
    • H5
  • HTML
  • CSS
  • 技术文档
  • GitHub技巧
  • Nodejs
  • 博客搭建
  • 搜索引擎
  • ES系列
  • 经典面试题
  • 知识点总结
  • uni-app
  • 算法
  • Vue3实战
  • 小程序chatgpt
  • 小程序配网流程
  • 程序WIFI配网
  • 小程序WebSocket
  • H5 WebSocket
  • H5 TTS
  • Vue3实现OSS存储
  • 大文件分片上传
  • 学习
  • 面试
  • 心情杂货
  • 实用技巧
  • 友情链接
关于
收藏
  • 分类
  • 标签
  • 归档
GitHub (opens new window)

Aiden Wu

前端界的小学生
首页
  • 前端文章

    • JavaScript
    • Vue
  • 学习笔记

    • JavaScript教程
    • JavaScript高级程序设计
    • ES6 教程
    • Vue
    • Vue3.0
    • React
    • TypeScript 从零实现 axios
    • Git
    • TypeScript
    • JS设计模式总结
    • 小程序
    • 小程序云开发
    • Echarts
    • 微前端
    • H5
  • HTML
  • CSS
  • 技术文档
  • GitHub技巧
  • Nodejs
  • 博客搭建
  • 搜索引擎
  • ES系列
  • 经典面试题
  • 知识点总结
  • uni-app
  • 算法
  • Vue3实战
  • 小程序chatgpt
  • 小程序配网流程
  • 程序WIFI配网
  • 小程序WebSocket
  • H5 WebSocket
  • H5 TTS
  • Vue3实现OSS存储
  • 大文件分片上传
  • 学习
  • 面试
  • 心情杂货
  • 实用技巧
  • 友情链接
关于
收藏
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
  • 技术文档

  • GitHub技巧

  • Nodejs

  • 博客搭建

  • 搜索引擎

  • ES系列

  • 经典面试题

    • 初级面试题
      • html语义化标签
      • CSS面试题
      • 浏览器默认端口号
      • vue-router原理
      • Hash
      • History模式
      • abstract模式
      • Axios和Ajax和Fetch的区别
        • Axios
        • Promise
        • Ajax
        • Fetch
      • http2的特性
      • 事务的特性
      • rem
      • 盒子水平垂直居中
      • CSS的选择器寻找机制
      • 盒模型
      • z-index
      • 对H5的理解
      • 微信小程序和APP的区别
      • js数据类型
      • 对象
      • async/await与promise的区别
      • 堆栈
      • Number
      • 重绘与回流
      • 补充400和401、403状态码
      • Doctype作用? 严格模式与混杂模式如何区分?它们有何意义?
      • 斐波那契数列
      • CSS三角形
      • js面试题
        • 例题一
        • 例题二
        • 例题三
        • 例题四
        • 例题五
      • Vue
        • 为什么Vue被称为“渐进框架”
        • Vue中的声明式渲染是什么
        • 作用域样式(scoped css)与深度作用选择器
        • $set
        • 双向数据绑定原理
      • let、const
      • 浏览器是怎么对HTML5的离线储存资源进行管理和加载的呢
      • sessionStorage、localStorage和cookie的区别
      • html5有哪些新特性?如何处理HTML5新标签的浏览器兼容问题?如何区分 HTML 和 HTML5
      • 页面导入样式时,使用link和@import有什么区别?
      • iframe有哪些缺点
      • label的作用是什么?是怎么用的?
      • HTML5的form如何关闭自动完成功能
      • 如何实现浏览器内多个标签页之间的通信?
      • 页面可见性(Page Visibility API) 可以有哪些用途
      • 如何在页面上实现一个圆形的可点击区域
      • 视觉差网页的实现原理
      • 浏览器打开经历了什么
      • css加载会造成阻塞吗
      • 前端从哪些方面做性能优化
      • BFC
        • 如何创建BFC
        • BFC作用
      • Number.isFinite & isFinite区别
      • isNaN 和 Number.isNaN 函数的区别?
      • js 获取原型的方法?
      • 手写函数防抖和函数节流
        • 节流throttle
        • 防抖debounce
      • 柯里化
        • 作用
      • 哪些操作会造成内存泄漏?
      • 立即执行函数
      • 谈一谈你对XSS攻击理解
        • 什么是 XSS 攻击
      • 能不能说一说CSRF攻击
        • 什么是CSRF攻击呢?
        • 「防护策略」
      • 一句话概括RESTFUL
      • 常见浏览器及其内核
      • Vue组件通信
      • http缓存
      • CDN缓存
        • 服务器集群
      • defer和async的区别
      • vue-router 组件复用导致路由参数失效怎么办
      • 预渲染
      • 预加载
      • options请求
      • CORS
      • 函数式组件和普通组件的区别
        • attr 与 listener 使用
        • class 与 style 绑定
        • TitleView.vue
        • Test.vue
        • component 组件引入
        • $options 计算属性
        • 总结
      • 不能冒泡的事件
      • display:none visibility:hidden opacity:0 区别
        • display: none;
        • visibility: hidden;
        • opacity: 0;
      • css禁止用户选择文本
      • 滚动条
      • Ajax中是如何解决浏览器缓存问题的
      • this
      • requestAnimationFrame的好处(rAF)
      • 所有的置换元素
      • 哪些是HTML5 新增的表单元素
      • chrome把音频和视频的自动播放禁止了
    • 进阶面试题
    • 高阶面试题
  • 知识点总结

  • uni-app

  • 算法

  • Vue3实战

  • 小程序chatgpt

  • 小程序WIFI配网

  • 小程序配网流程

  • 小程序WebSocket

  • H5 WebSocket

  • H5 TTS

  • Vue3实现OSS存储

  • 大文件分片上传

  • 技术
  • 经典面试题
wushengxin
2021-08-03
目录

初级面试题

# 经典面试题初级版

# html语义化标签

  • h、p、header、nav、article、aside、footer
  • HTML语义化让页面的内容结构化,结构更清晰,便于对浏览器,搜索引擎解析
  • 有利于开发和维护
  • 有利于SEO
  • 提升用户体验,如title、alt

# CSS面试题

实现类名main居中显示

<div class="container">
    <div class="main"></div>
    <div class="left"></div>
    <div class="right"></div>
 </div>
1
2
3
4
5

前提:

*{
      margin: 0;
      padding: 0;
}
1
2
3
4

方法一:

.container{
      position: relative;
    }
    .main{
      position: absolute;
      width: 40%;
      height: 200px;
      background-color: skyblue;
      top: 50%;
      left: 50%;
      transform: translate(-50%,-50%);
    }
    .left{
      position: absolute;
      top: 0;
      left: 0;
      width: 30%;
      height: 200px;
      background-color: green;
    }
    .right{
      position: absolute;
      top: 0;
      right: 0;
      width: 30%;
      height: 200px;
      background-color: yellow;
    }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28

方法二:

.container{
      position: relative;
    }
    .main{
      position: absolute;
      top: 0;
      left: 0;
      right: 0;
      margin: auto;
      width: 40%;
      height: 200px;
      background-color: skyblue;
    }
    .left{
      position: absolute;
      top: 0;
      left: 0;
      width: 30%;
      height: 200px;
      background-color: green;
    }
    .right{
      position: absolute;
      top: 0;
      right: 0;
      width: 30%;
      height: 200px;
      background-color: yellow;
    }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29

方法三:

.container{
      display: flex;
    }
    .main{
      order: 2;
      width: 40%;
      height: 200px;
      background-color: skyblue;
    }
    .left{
      order: 1;
      width: 30%;
      height: 200px;
      background-color: green;
    }
    .right{
      order: 3;
      width: 30%;
      height: 200px;
      background-color: yellow;
    }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

方法四:

.container{
      overflow: hidden;
      position: relative;
    }
    .main{
      position: absolute;
      top: 0;
      left: 0;
      right: 0;
      margin: auto;
      width: 40%;
      height: 200px;
      background-color: skyblue;
    }
    .left{
      float: left;
      width: 30%;
      height: 200px;
      background-color: green;
    }
    .right{
      float: right;
      width: 30%;
      height: 200px;
      background-color: yellow;
    }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

方法五:

.container{
      overflow: hidden;
    }
    .main{
      display: inline-block;
      margin: auto;
      width: 40%;
      height: 200px;
      background-color: skyblue;
    }
    .left{
      float: left;
      width: 30%;
      height: 200px;
      background-color: green;
    }
    .right{
      float: right;
      width: 30%;
      height: 200px;
      background-color: yellow;
    }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

# 浏览器默认端口号

  • http默认80
  • https默认443
  • ftp(文件传输)默认21

# vue-router原理

用于与后台服务器交互,通过不同的路径,请求不同的资源

hash 路由模式的实现主要是基于下面几个特性:

  • URL 中 hash 值只是客户端的一种状态,也就是说当向服务器端发出请求时,hash 部分不会被发送;
  • hash 值的改变,都会在浏览器的访问历史中增加一个记录。因此我们能通过浏览器的回退、前进按钮控制hash 的切换;
  • 可以通过 a 标签,并设置 href 属性,当用户点击这个标签后,URL 的 hash 值会发生改变;或者使用 JavaScript 来对 loaction.hash 进行赋值,改变 URL 的 hash 值;
  • 我们可以使用 hashchange 事件来监听 hash 值的变化,从而对页面进行跳转(渲染)。

history 路由模式的实现主要基于存在下面几个特性:

  • pushState 和 repalceState 两个 API 来操作实现 URL 的变化 ;
  • 我们可以使用 popstate 事件来监听 url 的变化,从而对页面进行跳转(渲染);
  • history.pushState() 或 history.replaceState() 不会触发 popstate 事件,这时我们需要手动触发页面跳转(渲染)。

# Hash

hash即浏览器url中#后面的内容

  • hash是URL中的锚点,代表的是网页中的一个位置,单单改变#后的部分,浏览器只会加载相应位置的内容,不会重新加载页面
  • Hash模式通过锚点值的改变,根据不同的值,渲染指定DOM位置的不同数据

# History模式

  • HTML5 History API提供了一种功能,能让开发人员在不刷新整个页面的情况下修改站点的URL,就是利用 history.pushState API 来完成 URL 跳转而无须重新加载页面;
  • 由于hash模式会在url中自带#,如果不想要很丑的 hash,我们可以用路由的 history 模式,只需要在配置路由规则时,加入"mode: 'history'",这种模式充分利用 history.pushState API 来完成 URL 跳转而无须重新加载页面

# abstract模式

abstract模式是使用一个不依赖于浏览器的浏览历史虚拟管理后端

  • 使用 vue-router 时只要不写 mode 配置即可,默认会在浏览器环境中使用 hash 模式,在移动端原生环境中使用 abstract 模式。 (当然,你也可以明确指定在所有情况下都使用 abstract 模式)

# Axios和Ajax和Fetch的区别

# Axios

  • Axios是基于promise用于浏览器和node.js是http客户端,主要用于向后台发送请求的
  • 支持promise,能拦截请求和响应
  • 防止CSRF(跨站请求伪造):就是让你的每个请求都带一个从cookie中拿到的key, 根据浏览器同源策略,假冒的网站是拿不到你cookie中得key的,这样,后台就可以轻松辨别出这个请求是否是用户在假冒网站上的误导输入,从而采取正确的策略

# Promise

  • 是一个对象用来传递异步操作的信息,主要是解决地狱回调的问题
  • 本质:分离异步数据获取和业务

# Ajax

  • 基于原生的XHR开发,多个请求之间如果有先后关系的话,就会出现回调地狱

# Fetch

  • Fetch是基于promise设计的。Fetch的代码结构比起ajax简单多了,参数有点像jQuery ajax。但是,一定记住fetch不是ajax的进一步封装,而是原生js,没有使用XMLHttpRequest对象
  • 语法简洁,更加语义化
  • 脱离了xhr,是ES规范里新的实现方式
  • fetch只对网络请求报错,对400,500都当做成功的请求
  • fetch默认不会带cookie,需要添加配置项

axios既提供了并发的封装,也没有fetch的各种问题,而且体积也较小,当之无愧现在最应该选用的请求的方式

# http2的特性

  • 完全采用二进制格式
  • 多路复用
  • 头部压缩
  • 服务端推送
  • 请求优先级

# 事务的特性

  • 事务特性有:原子性、一致性、持久性、隔离性

  • 脏读:就是没有提交的数据,举个例子:比如某个事务在对数据库中某条记录进行修改,修改后没有提交也没有回滚,也就是让其处于一个待定的状态,这个时候如果有其他的事务来先一步对这条记录进行读取或者处理了的现象。

  • 不可重复读取:一个事务先后读取某条记录,但在两次读取之间该条记录杯其他另一个事务给修改了,就造成了两次读取的数据不同的现象。

  • 幻读:幻读就是一个事务按照查询条件查询以前检索过的数据可是发现该数据被其他事务插入了满足其查询条件的新数据的现象。

  • 不可重复读喝脏读的区别是一个是读取了前一事务提交的数据,而一个是读取了另一个事务未提交的数据

# rem

相对当位,相对于html根元素来设置

# 盒子水平垂直居中

  • 定位:三种
  • display:flex
  • JavaScript
  • display:table-cell
.father{
  display:table-cell;
  vertical-align:middle;
  text-align:center
}
1
2
3
4
5

# CSS的选择器寻找机制

不考虑其他因素,下面哪种的渲染性能比较高? .box a{…} a{…}

  • 第二种渲染更好,css的选择器寻找机制是从右向左查询

# 盒模型

  • 标准盒模型:box-sizing:content-box
  • ie(怪异)盒模型:box-sizing:border-box
  • flex盒模型
  • 多列布局

# z-index

  • 表示元素的自底向上显示顺序
  • 需要与定位结合使用,值越大元素离电脑屏幕越近
  • 适用:隐藏div弹窗

# 对H5的理解

  • 新标签可读性高,有助于开发

  • 提供了更多的媒体元素(audio、video)

  • 很好的替代了flash

# 微信小程序和APP的区别

  • 下载安装、占用空间不同
  • 开发成本不同:APP开发成本比较高,它需要开发安卓版和IOS版,两种版本所用到开发语言不同。开发成本自然会高很多。 微信小程序是基于腾讯的小程序开发框架进行开发,开发技术类似HTML。一次开发就可以自动适配所有手机, 开发成本相对低些。
  • 用户群体不同:app面向所有智能手机的用户
    • 小程序是基于微信10亿用户
  • 推广不同:小程序可以分享,推广难度会小很多

# js数据类型

  • 基本数据类型:Undefined、Null、Boolean、Number、String、Symbol、BigInt
  • 引用数据类型:Object、function

# 对象

数字属性名==字符串属性名

# async/await与promise的区别

  • async/await是基于Promise实现的,Generater的语法糖,将异步强行转换为同步处理,它返回的是一个Promise对象
  • async用于申明一个function是异步的,而await可以认为是async wait的简写,等待一个异步方法执行完成
  • async/await相对于promise来讲,写法更加优雅
  • Promise的出现解决了传统callback函数导致的“地域回调”问题,但它的语法导致了它向纵向发展行成了一个回调链,遇到复杂的业务场景,这样的语法显然也是不美观的。而async await代码看起来会简洁些,使得异步代码看起来像同步代码,await的本质是可以提供等同于”同步效果“的等待异步返回能力的语法糖
  • async await与Promise一样,是非阻塞的

# 堆栈

  • 堆:存储引用类型值的空间
  • 栈:存储基本类型值和指行代码的环境

# Number

Number数字表示方法 Number类型表示数字,JavaScript 采用“IEEE 754 标准定义的*双精度*64位格式

# 重绘与回流

  • 我们增删DOM节点,修改一个元素的宽高,页面布局发生变化,DOM树结构发生变化,那么肯定要重新构建DOM树,而DOM树与渲染树是紧密相连的,DOM树构建完,渲染树也会随之对页面进行再次渲染,这个过程就叫回流
  • 当你给一个元素更换颜色,这样的行为是不会影响页面布局的,DOM树不会变化,但颜色变了,渲染树得重新渲染页面,这就是重汇
  • *回流的代价要远大于重绘。且回流必然会造成重绘,但重绘不一定会造成回流*
  • 回流:-页面首次渲染 -浏览器窗口大小发生改变 -元素尺寸或位置发生改变 -元素内容变化(文字数量或图片大小等等) -元素字体大小变化 -添加或者删除可见的DOM元素 –激活CSS伪类(例如::hover)
  • 导致回流的属性和方法:clientWidth、clientHeight、clientTop、clientLeft offsetWidth、offsetHeight、offsetTop、offsetLeft scrollWidth、scrollHeight、scrollTop、scrollLeft scrollIntoView()、scrollIntoViewIfNeeded() getComputedStyle() getBoundingClientRect() scrollTo()
  • 重绘:当页面中元素样式的改变并不影响它在文档流中的位置时(例如:color、background-color、visibility等),浏览器会将新样式赋予给元素并重新绘制它,这个过程称为重绘
  • 减少重绘和回流的方式:
    • 使用translate代替top
    • 使用style写样式代替行内样式
    • 分离读写操作
    • 样式集中修改
    • 尽量只修改position:absolute或fixed元素,对其他元素影响不大

# 补充400和401、403状态码

(1)400状态码:请求无效

产生原因:

  • 前端提交数据的字段名称和字段类型与后台的实体没有保持一致
  • 前端提交到后台的数据应该是json字符串类型,但是前端没有将对象JSON.stringify转化成字符串。

解决方法:

  • 对照字段的名称,保持一致性
  • 将obj对象通过JSON.stringify实现序列化

(2)401状态码:当前请求需要用户验证

(3)403状态码:服务器已经得到请求,但是拒绝执行

# Doctype作用? 严格模式与混杂模式如何区分?它们有何意义?

Doctype声明于文档最前面,告诉浏览器以何种方式来渲染页面,这里有两种模式,严格模式和混杂模式

  • 严格模式的排版和 JS 运作模式是 以该浏览器支持的最高标准运行。
  • 混杂模式,向后兼容,模拟老式浏览器,防止浏览器无法兼容页面。

# 斐波那契数列

function fibonaci(n){
      if(n<=1) return 1;
      let arr = [1,1]
      let i = n+1-2
      while(i>0){
        let a = arr[arr.length-2],
            b = arr[arr.length-1]
            arr.push(a+b)
            i--
      }
      return arr[arr.length-1]
    }
    console.log(fibonaci(0))
    console.log(fibonaci(1))
    console.log(fibonaci(2))
    console.log(fibonaci(3))
    console.log(fibonaci(4))
    console.log(fibonaci(5))
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

# CSS三角形

.box{
      width: 0px;
      height: 0px;
      content: "";
      border-left: 100px solid transparent;
      border-right: 100px solid transparent;
      border-bottom: 100px solid red;
    }
1
2
3
4
5
6
7
8

# js面试题

# 例题一

const a = 1 

const b = 1 

const c = null 

const d = null 

const e = [ ] 

const f = [ ] 

const g = { } 

const h = { }

console.log(a===b)
console.log(c===d)
console.log(e===f)
console.log(g===h)
//true true false false
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

# 例题二

console.log(1)

 setTimeout(() => {

    console.log(2)

}, 0)

new Promise((resolve) => {

    console.log(3)

    resolve()

}).then(() => { 

   console.log(4)

})

console.log(5)
//13542
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

# 例题三

    if ([]) {

console.log('A') // A

}

if ({}) {

console.log('B') // B

}

if ('') {

console.log('C') // C

}

if (null) {

console.log('D') // D

}
//A B
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

# 例题四

  console.log(a) // A

console.log(b) // B 

console.log(c) // C 

function a( ) { }

var b = 1 

const c = 2
//f a(){}   undefined  报错
1
2
3
4
5
6
7
8
9
10
11
12

# 例题五

var name = 'chris'

    var staffA = {

      name: 'hunter',

      getShowName: function () {
        console.log(this.name)
        return function () {
          console.log(this.name)

        }

      }

    }
    staffA.getShowName()
    // hunter 下面的consle.log没输出
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

# Vue

# 为什么Vue被称为“渐进框架”

  • Vue本身只关注动态展现数据和与用户交互部分,它本身不做诸如路由,状态数据管理等方面,如需要可根据逐渐引入vue的插件或第三方库来扩展,如引入vue-router增加路由功能,引入vuex管理状态,引入axios发ajax请求与后台交互

# Vue中的声明式渲染是什么

  • 界面能根据初始化数据做初始化渲染显示,不需要手动操作DOM来显示
  • 要更新页面,只需要更新数据即可,不用手动操作DOM来更新界面

# 作用域样式(scoped css)与深度作用选择器

# 作用域样式是什么

  • 让组件的样式限定在当前组件作用域内有效,对其它外部或内部组件无效

# $set

vue并不支持直接通过数组索引修改数组以及修改数组的长度

  • 修改数组
    • 通过this.$set(target,index,value) ---------target:数组变量,index:要修改的索引,value:要修改的值
  • 修改数组中的对象
    • 通过this.$set(target,key,value)-------target:数组变量,key:为一个字符串,修改对象的变量名,value为修改的值

# 双向数据绑定原理

  • 通过Object.defineProperty中的get和set方法进行改变
  • 通过监听表单来改变数据,inputName.oninput

方案一:vue2.0的实现

姓名:<span id="spanName"></span>
  <br>
  <input type="text" id="inputName">

let obj = {
      name:''
    }
    let newObj = JSON.parse(JSON.stringify(obj))
    Object.defineProperty(obj,'name',{
      get(){
        return newObj.name
      },
      set(val){
        if(val === newObj.name) return;
        newObj.name = val;
        observer()
      }
    })
    function observer(){
      spanName.innerHTML = obj.name
      inputName.value = obj.name
    }

    setTimeout(()=>{
      obj.name = "珠峰培训"
    },1000)
    inputName.oninput = function(){
      obj.name = this.value
    }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29

方案二:vue3.0的实现

let obj = {}
    obj = new Proxy(obj,{
      get(target,prop){
        return target[prop]
      },
      set(target,prop,value){
        target[prop] = value
        observer()
      }
    })
    function observer(){
      spanName.innerHTML = obj.name
      inputName.value = obj.name
    }

    setTimeout(()=>{
      obj.name = "珠峰培训"
    },1000)
    inputName.oninput = function(){
      obj.name = this.value
    }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
//Object.defineProperty
let person = {
  name:'张三',
  age:18
}

let p = {}
Object.defineProperty(p,'name',{
  get(){
    return person.name
  },
  set(value){
    person.name = value
  }
})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

Proxy(代理):拦截对象中任意属性的变化,包括属性值的读写,属性的添加、属性的删除

Reflect(反射):对源对象的属性进行操作

//proxy
let person = {
  name:'张三',
  age:18
}
let p = new Proxy(person,{
    //有人读取p的某个属性时调用
    get(target,propName){
        return target[propName]
    },
    //有人修改p的某个属性或给p追加某个属性时调用
    set(target,propName,value){
        target[propName] = value
    },
    //有人删除p的某个属性时调用
    deleteProperty(target,propName){
        return delete target[propName]
    }
})
//proxy Reflect
let person = {
  name:'张三',
  age:18
}
let p = new Proxy(person,{
    //有人读取p的某个属性时调用
    get(target,propName){
        return Reflect.get(target,propName)
    },
    //有人修改p的某个属性或给p追加某个属性时调用
    set(target,propName,value){
        Reflect.set(target,propName,value)
    },
    //有人删除p的某个属性时调用
    deleteProperty(target,propName){
        return Reflect.deleteProperty(target,propName)
    }
})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38

# let、const

  • let
    • 不存在变量提升
    • 同一个作用域下不能重复定义同一个名称
    • 有着严格的作用域
  • const
    • 不存在变量提升
    • 同一个作用域下不能重复定义同一个名称
    • 有着严格的作用域
    • 赋值了必须初始化,不能重新赋值

# 浏览器是怎么对HTML5的离线储存资源进行管理和加载的呢

  1. 在线的情况下,浏览器发现html头部有manifest属性,它会请求manifest文件,如果是第一次访问app,那么浏览器就会根据manifest文件的内容下载相应的资源并且进行离线存储。如果已经访问过app并且资源已经离线存储了,那么浏览器就会使用离线的资源加载页面,然后浏览器会对比新的manifest文件与旧的manifest文件,如果文件没有发生改变,就不做任何操作,如果文件改变了,那么就会重新下载文件中的资源并进行离线存储。
  2. 离线的情况下,浏览器就直接使用离线存储的资源。

# sessionStorage、localStorage和cookie的区别

共同点:都是保存在浏览器端、且同源的

  1. 存储大小限制也不同,cookie数据不能超过4K,同时因为每次http请求都会携带cookie、所以cookie只适合保存很小的数据,如会话标识。sessionStorage和localStorage虽然也有存储大小的限制,但比cookie大得多,可以达到5M或更大
  2. 数据有效期不同,sessionStorage:仅在当前浏览器窗口关闭之前有效;localStorage:始终有效,窗口或浏览器关闭也一直保存,因此用作持久数据;cookie:只在设置的cookie过期时间之前有效,即使窗口关闭或浏览器关闭

# html5有哪些新特性?如何处理HTML5新标签的浏览器兼容问题?如何区分 HTML 和 HTML5

  1. 绘画 canvas;
  2. 用于媒介回放的 video 和 audio 元素;
  3. 本地离线存储 localStorage 长期存储数据,浏览器关闭后数据不丢失;
  4. sessionStorage 的数据在浏览器关闭后自动删除;
  5. 语意化更好的内容元素,比如 article、footer、header、nav、section;
  6. 表单控件,calendar、date、time、email、url、search;
  7. 地图和拖放
  8. 新的技术webworker, websocket, Geolocation;

处理兼容

  • IE8/IE7/IE6支持通过document.createElement方法产生的标签,
  • 可以利用这一特性让这些浏览器支持HTML5新标签,浏览器支持新标签后,还需要添加标签默认的样式。
  • 当然也可以直接使用成熟的框架、比如html5shim
<!--[if lt IE 9]>
  <script> src="http://html5shim.googlecode.com/svn/trunk/html5.js"</script>
<![endif]-->
1
2
3

如何区分html和html5:

  1. 在文档类型声明上,h5为<!DOCTYPE html>,之前版本比较长
  2. h5有语义化标签,如

# 页面导入样式时,使用link和@import有什么区别?

  1. link是XHTML标签,除了加载CSS外,还能用于定义RSS, 定义rel连接属性等作用;而@import是CSS提供的,只能用于加载CSS;
  2. link引用CSS时,在页面载入时同时加载;@import需要页面网页完全载入以后加载.
  3. link是XHTML标签,无兼容问题;@import是在CSS2.1提出的,低版本(IE5及以下)的浏览器不支持。
  4. link支持使用Javascript控制DOM去改变样式;而@import不支持。

# iframe有哪些缺点

  1. iframe会阻塞主页面的Onload事件;
  2. iframe和主页面共享链接池,而浏览器对相同城的链接有限制,所以会影响页面的并行加载;
  3. 使用iframe之前需要考虑这两个缺点,如果需要使用iframe,最好是通过JavaScript;
  4. 动态给iframe添加src属性值,这样可以可以绕开以上两个问题
  5. 不利于seo
  6. 代码复杂,无法一下被搜索引擎索引到
  7. iframe框架页面会增加服务器的http请求,对于大型网站不可取
  8. 很多的移动设备无法完全显示框架,设备兼容性差

# label的作用是什么?是怎么用的?

label标签是用来定义表单控制间的关系,当用户选择该标签时,浏览器会自动将焦点转到和标签相关的表单控件上。

1、
<label for = "Name">Number:</label>
<input type="text" name="Name" id="Name" />
2、
<label>Data:<input type="text" name="B" /><label>
1
2
3
4
5

# HTML5的form如何关闭自动完成功能

  1. 设置Form的autocomplete为"on"或者"off"来开启或者关闭自动完成功能
  2. 设置输入框的autocomplete为"on"或者"off"来开启或者关闭该输入框的自动完成功能
打开自动完成功能的Form<br>  
<form name="form1" autocomplete="on">  
    打开自动完成功能的输入框  
    <input type="text" autocomplete="on" name="txtOff1"><br>  
    关闭自动完成功能的输入框  
    <input type="text" autocomplete="off" name="txtOn1"><br>  
    <input type="submit" value="提交"><br>  
</form>  
关闭自动完成功能的Form<br>  
<form name="form1" autocomplete="off">  
    打开自动完成功能的输入框  
    <input type="text" autocomplete="on" name="txtOff1"><br>  
    关闭自动完成功能的输入框  
    <input type="text" autocomplete="off" name="txtOn1"><br>  
    <input type="submit" value="提交"><br>  
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

# 如何实现浏览器内多个标签页之间的通信?

  • 第一种——调用localStorage
    • 在一个标签页里面使用 localStorage.setItem(key,value)添加(修改、删除)内容; 在另一个标签页里面监听 storage 事件。 即可得到 localstorge 存储的值,实现不同标签页之间的通信。
  • 第二种——调用cookie+setInterval()
    • 将要传递的信息存储在cookie中,每隔一定时间读取cookie信息,即可随时获取要传递的信息

# 页面可见性(Page Visibility API) 可以有哪些用途

  1. 通过 visibilityState 的值检测页面当前是否可见
  2. document.visibilityState, 表示页面所处的状态

# 如何在页面上实现一个圆形的可点击区域

<style>  
    .disc{  
        width:100px;  
        height:100px;  
        background-color:grey;  
        border-radius: 50%;  
        cursor: pointer;  
        line-height: 100px;  
        text-align: center;  
        color: white;  
    }  
</style>
<div class="disc">点击区域</div> 
1
2
3
4
5
6
7
8
9
10
11
12
13

# 视觉差网页的实现原理

利用background-attachment: fixed;

# 浏览器打开经历了什么

  • url解析
  • dns解析 => ip地址
  • 发送请求:TCP三次握手
  • DOM渲染(渲染树)
    • dom解析
    • css结构体
  • JS引擎和UI渲染引擎显示页面
  • TCP四次挥手:断开连接

# css加载会造成阻塞吗

  • css加载不会阻塞dom的解析
  • css加载会阻塞dom渲染
  • css加载会阻塞js的执行

# 前端从哪些方面做性能优化

  • 减少http请求
  • 压缩文件的大小(资源压缩,Gzip压缩)
  • CDN库
  • SSR服务器渲染
  • 懒加载

# BFC

  • 块级格式化上下文
  • 它是指一个独立的块级渲染区域
  • 与区域外部无关

# 如何创建BFC

给父级元素设置

  • float的值不是none
  • position的值不是static或者relative
  • display的值是inline-block、flex或者inline-flex
  • overflow:hidden

# BFC作用

  • 可以取消合作margin塌陷
  • BFC可以阻止元素被浮动元素覆盖

# Number.isFinite & isFinite区别

某种程度上,都是检测有限性的值。两者区别在于,isFinite函数强制将一个非数值的参数转换成数值,如果能转换成数值,然后再去判断是否是有限的。

Number.isFinite()检测有穷性的值,这个方法不会强制将一个非数值的参数转换成数值,这就意味着,只有数值类型的值,且是有穷的(finite),才返回 true。

Number.isFinite(0)    // true
Number.isFinite('0')  // false
Number.isFinite(Infinity) false
isFinite('0')   // true
isFinite('0')  // true
isFinite(Infinity)  // false
1
2
3
4
5
6

# isNaN 和 Number.isNaN 函数的区别?

  • isNaN首先会接受一个参数,参数讲这个转换成数字,任何不能被转换成数值的都返回true,所以对于非数字的参数,也是true,会影响NaN判断
  • Number.isNaN首先判断是不是数字,是数字在去判断是不是NaN,这种方法更准确。
// isNaN('sdasd') true
// isNaN('21N') true
// isNaN(NaN)  true
// isNaN(123) false
1
2
3
4

我们来看看Number.isNaN

Number.isNaN('1232N')  // false
Number.isNaN('1232')    // false
Number.isNaN(21312)  // false
Number.isNaN('sadas')  // false
Number.isNaN(NaN)   // true
1
2
3
4
5

# js 获取原型的方法?

假设Demo是一个对象,那么有三种方式👇

  • Demo.constructor.prototype
  • Demo.__proto__
  • Object.getPrototypeOf(Demo)

# 手写函数防抖和函数节流

# 节流throttle

规定在一个单位时间内,只能触发一次函数。如果这个单位时间内触发多次函数,只有一次生效。

function throttle(fn, delay) {
    let flag = true,
        timer = null
    return function(...args) {
        let context = this
        if(!flag) return

        flag = false
        clearTimeout(timer)
        timer = setTimeout(function() {
            fn.apply(context,args)
            flag = true
        },delay)
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

# 防抖debounce

在事件被触发n秒后再执行回调,如果在这n秒内又被触发,则重新计时。

function debounce(fn, delay) {
    let timer = null
    return function(...args) {
        let context = this
        if(timer) clearTimeout(timer)
        timer = setTimeout(function(){
            fn.apply(context,args)
        },delay)
    }
}
1
2
3
4
5
6
7
8
9
10

# 柯里化

柯里化,英语:Currying(果然是满满的英译中的既视感),是把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,并且返回接受余下的参数而且返回结果的新函数的技术。

  • 高价函数
  • 每个函数只传递一个参数

# 作用

  • 参数复用
// 正常正则验证字符串 reg.test(txt)

// 函数封装后
function check(reg, txt) {
    return reg.test(txt)
}

check(/\d+/g, 'test')       //false
check(/[a-z]+/g, 'test')    //true

// Currying后
function curryingCheck(reg) {
    return function(txt) {
        return reg.test(txt)
    }
}

var hasNumber = curryingCheck(/\d+/g)
var hasLetter = curryingCheck(/[a-z]+/g)

hasNumber('test1')      // true
hasNumber('testtest')   // false
hasLetter('21212')      // false
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

# 哪些操作会造成内存泄漏?

相关知识点:

  • 1.意外的全局变量
  • 2.被遗忘的计时器或回调函数
  • 3.脱离 DOM 的引用
  • 4.闭包

# 立即执行函数

  1. 不必为函数命名,避免了污染全局变量
  2. 立即执行函数内部形成了一个单独的作用域,可以封装一些外部无法读取的私有变量
  3. 封装变量

# 谈一谈你对XSS攻击理解

# 什么是 XSS 攻击

XSS 全称是 Cross Site Scripting ,为了与CSS区分开来,故简称 XSS,翻译过来就是“跨站脚本”。

XSS是指黑客往 HTML 文件中或者 DOM 中注入恶意脚本,从而在用户浏览页面时利用注入的恶意脚本对用户实施攻击的一种手段。

最开始的时候,这种攻击是通过跨域来实现的,所以叫“跨域脚本”。发展到现在,往HTML文件中中插入恶意代码方式越来越多,所以是否跨域注入脚本已经不是唯一的注入手段了,但是 XSS 这个名字却一直保留至今。

注入恶意脚本可以完成这些事情:

  1. 窃取Cookie
  2. 监听用户行为,比如输入账号密码后之间发给黑客服务器
  3. 在网页中生成浮窗广告
  4. 修改DOM伪造登入表单

一般的情况下,XSS攻击有三种实现方式

  • 存储型 XSS 攻击
  • 反射型 XSS 攻击
  • 基于 DOM 的 XSS 攻击

# 能不能说一说CSRF攻击

# 什么是CSRF攻击呢?

CSRF 英文全称是 Cross-site request forgery,所以又称为“跨站请求伪造”,是指黑客引诱用户打开黑客的网站,在黑客的网站中,利用用户的登录状态发起的跨站请求。简单来讲,「CSRF 攻击就是黑客利用了用户的登录状态,并通过第三方的站点来做一些坏事。」

# 「防护策略」

# 用户操作限制——验证码机制

方法:添加验证码来识别是不是用户主动去发起这个请求,由于一定强度的验证码机器无法识别,因此危险网站不能伪造一个完整的请求。

# 一句话概括RESTFUL

就是URL定位资源,用HTTP描述操作

# 常见浏览器及其内核

  1. -webkit-:webkit核心浏览器,Chrome

  2. -moz-:Gecko核心浏览器,fixfox

  3. -o-:Opera核心浏览器,Opera

  4. -ms-:微软的IE浏览器

# Vue组件通信

  • props、this.$emit('方法名',参数)
  • this.$parent.方法名()
  • this.$refs.ref名.属性/方法
  • this.$children[0].属性/方法
  • EventBus => 公共的vue实例,实例.$emit , 实例.$on
  • $attrs获取父组件属性,this.$listenershi获取父组件方法
  • provide、inject =>有点像props
provide:{
  name:"a组件里的provide"
}
inject:['name']
1
2
3
4
  • Vuex

# http缓存

第二次请求资源时请求缓存

  • 强制缓存,响应头Cache-Control设置max-age缓存时间
  • 协商缓存:如果不是最新资源服务器返回
    • Last-Modified资源上一次修改的时间200状态码,是返回304状态码,直接从缓存里拿资源
      • 发送时:请求头携带资源标识If-Modified-Since
    • ETag资源对应的唯一字符串
      • 发送时:请求头携带资源标识If-None-Match

# CDN缓存

# 服务器集群

获取资源时,获取资源最近的服务器,CDN心跳,询问各个CDN的状态,

# defer和async的区别

  • defer 和 async 在网络读取(脚本下载)这块儿是一样的,都是异步的(相较于 HTML 解析)
  • 两者的差别:在于脚本下载完之后何时执行,显然 defer 是最接近我们对于应用脚本加载和执行的要求的。defer是立即下载但延迟执行,加载后续文档元素的过程将和脚本的加载并行进行(异步),但是脚本的执行要在所有元素解析完成之后,DOMContentLoaded 事件触发之前完成。async是立即下载并执行,加载和渲染后续文档元素的过程将和js脚本的加载与执行并行进行(异步)。
  • 关于 defer,我们还要记住的是它是按照加载顺序执行脚本的
  • 标记为async的脚本并不保证按照指定它们的先后顺序执行。对它来说脚本的加载和执行是紧紧挨着的,所以不管你声明的顺序如何,只要它加载完了就会立刻执行。
  • async 对于应用脚本的用处不大,因为它完全不考虑依赖(哪怕是最低级的顺序执行),不过它对于那些可以不依赖任何脚本或不被任何脚本依赖的脚本来说却是非常合适的。

# vue-router 组件复用导致路由参数失效怎么办

解决方法:

1.通过 watch 监听路由参数再发请求

watch: { //通过watch来监听路由变化

 "$route": function(){
 this.getData(this.$route.params.xxx);
 }
    "$route": handle(n){
        //n为路由
    },
     deep:true //深度监听
}
1
2
3
4
5
6
7
8
9
10

2.用 :key 来阻止“复用”

<router-view :key="$route.fullPath" />
1

# 预渲染

骨架屏

# 预加载

  • 网络字体
  • 当图片设置display为none会预加载。但不会渲染

# options请求

预检请求首先需要向另外一个域名的资源发送一个 HTTP OPTIONS 请求头,其目的就是为了判断实际发送的请求是否是安全的

1、获取服务器支持的HTTP请求方法;

2、用来检查服务器的性能。

# CORS

OPTIONS是CORS中一种透明服务器验证机制,判断实际发送的请求是否是安全的

只要同时满足以下两大条件,就属于简单请求。

配置"Access-Control-Allow-Origin":"*"允许跨域

(1) 请求方法是以下三种方法之一:

  • HEAD
  • GET
  • POST

(2)HTTP的头信息不超出以下几种字段:

  • Accept
  • Accept-Language
  • Content-Language
  • Last-Event-ID
  • Content-Type:只限于三个值application/x-www-form-urlencoded、multipart/form-data、text/plain

复杂请求:每次都会发送OPTIONS请求判断发送的请求是否安全

# 函数式组件和普通组件的区别

什么是函数式组件 没有管理任何状态,也没有监听任何传递给它的状态,也没有生命周期方法,它只是一个接受一些 prop 的函数。简单来说是 一个无状态和无实例的组件

  • functional:true

# attr 与 listener 使用

平时我们在开发组件时,传递 prop 属性以及事件等操作,都会使用v-bind="$attrs"和 v-on="$listeners"。而在函数式组件的写法有所不同,attrs属性集成在 data中。

<template functional>
  <div v-bind="data.attrs" v-on="listeners">
    <h1>{{ props.title }}</h1>
  </div>
</template>
复制代码
1
2
3
4
5
6

# class 与 style 绑定

在引入函数式组件、直接绑定外层的class类名和style样式是无效的。data.class 表示动态绑定class, data.staticClass 则表示绑定静态class, data.staticStyle 则是绑定内联样式

# TitleView.vue

<template functional>
  <div :class="[data.class, data.staticClass]" :style="data.staticStyle">
    <h1>{{ props.title }}</h1>
  </div>
</template>
复制代码
1
2
3
4
5
6

# Test.vue

<template>
  <title-view
    :class="{title-active: isActive}"
    style="{ color: red }"
    title="Hello Do"
  />
</template>
复制代码
1
2
3
4
5
6
7
8

# component 组件引入

函数式组件引入其他组件方式如下,具体参考:github.com/vuejs/vue/i… (opens new window)

<template functional>
  <div class="tv-button-cell">
    <component :is="injections.components.TvButton" type="info" />
    {{ props.title }}
    </component>
  </div>
</template>

<script>
import TvButton from '../TvButton'

export default {
  inject: {
    components: {
      default: {
        TvButton
      }
    }
  }
}
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

# $options 计算属性

有时候需要修改prop数据源, 使用 Vue 提供的 $options 属性,可以访问这个特殊的方法。

<template functional>
  <div v-bind="data.attrs" v-on="listeners">
    <h1>{{ $options.upadteName(props.title) }}</h1>
  </div>
</template>

<script>
  export default {
    updateName(val) {
      return 'hello' + val
    }
  }
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13

# 总结

虽然速度和性能方面是函数式组件的优势、但不等于就可以滥用,所以还需要根据实际情况选择和权衡。比如在一些展示组件。例如, buttons, tags, cards,或者页面是静态文本,就很适合使用函数式组件。

# 不能冒泡的事件

不能被冒泡的9个事件:妈(mouseenter)妈(mouseleave)不(blur)让(load)你(unload)浪(load)费(foucus)

① load和unload

② mouseenter和mouseleave

③ blur和focus

④ error

⑤ resize和abort从3个角度说可分为ui事件、鼠标移入移出事件、聚焦和失焦件,

# display:none visibility:hidden opacity:0 区别

# display: none;

  1. DOM 结构:浏览器不会渲染 display 属性为 none 的元素,不占据空间;
  2. 事件监听:无法进行 DOM 事件监听;
  3. 性能:动态改变此属性时会引起重排,性能较差;
  4. 继承:不会被子元素继承,毕竟子类也不会被渲染;
  5. transition:transition 不支持 display。

# visibility: hidden;

  1. DOM 结构:元素被隐藏,但是会被渲染不会消失,占据空间;
  2. 事件监听:无法进行 DOM 事件监听;
  3. 性 能:动态改变此属性时会引起重绘,性能较高;
  4. 继 承:会被子元素继承,子元素可以通过设置 visibility: visible; 来取消隐藏;
  5. transition:visibility 会立即显示,隐藏时会延时

# opacity: 0;

  1. DOM 结构:透明度为 100%,元素隐藏,占据空间;
  2. 事件监听:可以进行 DOM 事件监听;
  3. 性 能:提升为合成层,不会触发重绘,性能较高;
  4. 继 承:会被子元素继承,且,子元素并不能通过 opacity: 1 来取消隐藏;
  5. transition:opacity 可以延时显示和隐藏

二者的区别

  • visibility: hidden和display: none的区别仅仅在于display: none隐藏后的元素不占据任何空间,而visibility: hidden隐藏后的元素空间依旧保留。
  • visibility具有继承性,给父元素设置visibility:hidden;子元素也会继承这个属性,但是如果重新给子元素设置visibility: visible,则子元素又会显示出来。这个和display: none是不一样的。
  • CSS3的transition支持visibility属性,但是并不支持display,由于transition可以延迟执行,因此可以配合visibility使用纯css实现hover延时显示效果。
  • visibility: hidden不会影响计数器的计数,visibility: hidden虽然让一个元素不见了,但是其计数器仍在运行,而display:none则不是。

# css禁止用户选择文本

user-select:none;

# 滚动条

防止低版本浏览器不兼容,即横向有滚动条

.box{
  overflow-x: hidden; 
  overflow-y: auto;
}
.box::-webkit-scrollbar{
	display:none
}
1
2
3
4
5
6
7

# Ajax中是如何解决浏览器缓存问题的

我们都知道ajax能提高页面载入的速度主要的原因是通过ajax减少了重复数据的载入, 也就是说在载入数据的同时将数据缓存到内存中,一旦数据被加载其中,只要我们没有刷新页面, 这些数据就会一直被缓存在内存中,当我们提交 的URL与历史的URL一致时,就不需要提交给服务器, 也就是不需要从服务器上面去获取数据,虽然这样降低了服务器的负载提高了用户的体验, 但是我们不能获取最新的数据。为了保证我们读取的信息都是最新的,我们就需要禁止他的缓存功能。 解决方案有如下几种: 1、在ajax发送请求前加上 anyAjaxObj.setRequestHeader("If-Modified-Since","0")。 2、在ajax发送请求前加上 anyAjaxObj.setRequestHeader("Cache-Control","no-cache")。

# this

this 永远指向最后调用它的那个对象”,我们看最后调用 a 的地方 a();,前面没有调用的对象那么就是全局对象 window,这就相当于是 window.a();注意,这里我们没有使用严格模式,如果使用严格模式的话,全局对象就是 undefined,那么就会报错 Uncaught TypeError: Cannot read property 'name' of undefined。

在这个例子中,函数 fn 是对象 a 调用的,所以打印的值就是 a 中的 name 的值。是不是有一点清晰了呢~

我们做一个小小的改动: 例 3:

var name = "windowsName";
    var a = {
        name: "Cherry",
        fn : function () {
            console.log(this.name);      // Cherry
        }
    }
    window.a.fn();
1
2
3
4
5
6
7
8

这里打印 Cherry 的原因也是因为刚刚那句话“this 永远指向最后调用它的那个对象”,最后调用它的对象仍然是对象 a。

箭头函数的 this 始终指向函数定义时的 this,而非执行时

# requestAnimationFrame的好处(rAF)

相比于setTimeout的在固定时间后执行对应的动画函数,requestAnimationFrame用于指示浏览器在下一次重新绘制屏幕图像时, 执行其提供的回调函数。

  • **「使浏览器画面的重绘和回流与显示器的刷新频率同步」**它能够保证我们的动画函数的每一次调用都对应着一次屏幕重绘,从而避免setTimeout通过时间定义动画频率,与屏幕刷新频率不一致导致的丢帧。
  • **「节省系统资源,提高性能和视觉效果」**在页面被置于后台或隐藏时,会自动的停止,不进行函数的执行,当页面激活时,会重新从上次停止的状态开始执行,因此在性能开销上也会相比setTimeout小很多。
  • 取消请求动画帧:cancelAnimationFrame(raf)

# 所有的置换元素

img input textarea select object iframe canvas

# 哪些是HTML5 新增的表单元素

datalist , keygen, output

# chrome把音频和视频的自动播放禁止了

加入muted:"muted"属性即可

编辑 (opens new window)
#经典面试题
上次更新: 2021/12/06, 21:28:32
ES12
进阶面试题

← ES12 进阶面试题→

最近更新
01
大文件分片上传
08-05
02
Vue3实现OSS存储
08-05
03
H5 TTS
08-05
更多文章>
Theme by Vdoing | Copyright © 2019-2025 Aiden Wu | MIT License
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式
×