伪类和伪元素

什么是伪类和伪元素? 伪类:以冒号(:)开头,用于选择处于特定状态的元素。 伪元素:以双冒号(::)开头,用于在文档中插入虚构的元素。 这么说有点抽象,我们来看具体案例。例如下面的伪类语法表达的意思是:文档里的那些已经被用户访问过的 a 标签,当鼠标悬浮在它上面的时候,颜色为红色。 a:visited:hover { color: red; } 效果如下: 可以看到,无论是 visited还是 hover,都表示了 a 标签的某种状态,选择器始终选择的是伪类前面的元素,只不过当出现伪类描述的状态时,样式才生效而已。 注意,上面使用的是无痕浏览器打开的页面,是不可能出现 visited 状态的,因为无痕不记录访问历史,我们可以点击控制台的 :hov 图标手动勾选 :visited 和 :hover 来模拟 a 标签「已访问」和「悬浮」两种状态。 我们再来看一下伪元素的案例,下面的语法表达的意思是: div 标签里面首字的颜色为红色。 div::first-letter { color: red; } 效果如下: 与伪类不同的是,首字并不是 div 元素的某种状态,而是浏览器创建出来的一个虚拟的元素,我们可以在上图的右下角看到 Pseudo ::first-letter element提示,相当于浏览器自动选中了「彻」字。 注意:::first-letter 伪元素只作用于块状元素上面,如果把 div 换成 span,就无法选中首字了,除非手动设置 span 的 display 属性为 block 或 inline-block 等块状值。 从上面的案例当中,我们可以得出两个结论: 伪类用于向某些已经存在的选择器添加特殊效果(当状态改变时) 伪元素用于将特殊效果添加到不存在的虚拟元素中(浏览器自动创建) 也就是说伪类的本质还是类(class),作用于标签本身,只不过限定了状态条件;而伪元素的本质是元素(element),作用于该虚拟元素的内容本身。 伪类有哪些? 按照功能,可划分为以下几类: 动态伪类::visited、:focus、:hover等 状态伪类::disabled、:empty、:required 等 结构伪类::first-child、:nth-of-type等 其他伪类::target、:lang、:not()等 下面的表格详细记录了各种伪类及其描述: 伪类 描述 兼容性 :active 元素处于活动状态时 ✅ :focus 元素已获取焦点时 ✅ :hover 元素处于悬浮状态时 ✅ :link 链接未访问时 ✅ :visited 链接已访问时 ✅ :first-child 元素是首个子元素时 ✅ :last-child 元素是最后一个子元素时 ✅ :nth-child() 元素是第 n 个子元素时 ✅ :nth-last-child() 元素是倒数第 n 个子元素时 ✅ :only-child 元素是唯一子元素时 ✅ :first-of-type 元素是首个特定类型的子元素时 ✅ :last-of-type 元素是最后一个特定类型的子元素时 ✅ :nth-of-type() 元素是第 n 个特定类型的子元素时 ✅ :nth-last-of-type() 元素是倒数第 n 个特定类型的子元素时 ✅ :only-of-type 元素是唯一的特定类型的子元素时 ✅ :not 不满足指定条件时 ✅ :target 元素 id 匹配到哈希值时 ✅ :root 元素是文档树的根元素时 ✅ :lang() 匹配到指定语言时 ✅ :empty 元素处于没有子元素状态时 ✅ :invalid 和 :valid 表单项是否有效 ✅ :required 和 :optional 表单项是否必填 ✅ :in-range和 :out-of-range 表单项是否超出范围 ✅ :read-only和 :read-write 表单项是否只读 ✅ :enabled和 :disabled 表单项是否禁用 ✅ :fullscreen 当前处于全屏显示模式时 ⚠️ :blank 输入框处于输入为空状态时 ❌ :dir() 匹配到特定文字书写方向时 ❌ 上表中的兼容性表示: ...

October 8, 2024

Webpack与Vite

前言 vite比webpack快? vite比webpack简单? 今天我们就来分析一下,到底有什么不一样的地方! 定位 对比之前,我们先要搞懂,vite与webpack的定位以及关系才可以。 那前端社区中常谈到的这些工具webpack、rollup、parcel、esbuild、vite、vue-cli、create-react-app、umi他们之间的关系是怎样的。 webpack、rollup、parcel、esbuild都是打包工具,代码写好之后,我们需要对代码进行压缩、合并、转换、分割、打包等操作,这些工作需要打包工具去完成。 vue-cli、create-react-app、umi 是基于webpack的上层封装,通过简单的配置就可以快速创建出一个项目,把更多的时间放在业务开发上。 vite开发环境依赖esbuild进行预构建,生产环境则依赖rollup进行打包,并且充分利用了现代浏览器的特性,比如http2、ES module,vite是站在众多巨人肩膀上的一个产物, 类似webpack + webpack-dev-server的结合体,是一个非常棒的前端项目的构建工具。 运行原理 首先,我们从运行原理上分析一下,vite为什么比webpack快。 webpack运行原理 当我们使用webpack启动项目时,webpack会根据我们配置文件(webpack.config.js) 中的入口文件(entry),分析出项目项目所有依赖关系,然后打包成一个文件(bundle.js),交给浏览器去加载渲染。 这样就会带来一个问题,项目越大,需要打包的东西越多,启动时间越长。 关于ES module 在讲vite运行原理之前,我们先说一下ES module 目前,绝大多数现代浏览器都已经支持ES module了, 我们只需要在<script>标签中添加type="module",就可以使用ES module了。 下面这段代码是可以直接在浏览器中运行的。 // test.js export default function hello() { console.log('hello world'); } // index.html <script type="module"> import hello from './test.js'; hello(); // hello world </scirpt> vite运行原理 在<script type="module">中,浏览器遇到内部的import引用时,会自动发起http请求,去加载对应的模块。 vite也正是利用了ES module这个特性,使用vite运行项目时,首先会用esbuild进行预构建,将所有模块转换为es module,不需要对我们整个项目进行编译打包,而是在浏览器需要加载某个模块时,拦截浏览器发出的请求,根据请求进行按需编译,然后返回给浏览器。 这样一来,首次启动项目(冷启动)时,自然也就比webpack快很多了,并且项目大小对vite启动速度的影响也很小。 构建方式 我们再来看一下,vite与webpack在项目构建上有哪些区别。 webpack webpack是基于nodejs运行的,但js只能单线程运行,无法利用多核CPU的优势,当项目越来越大时,构建速度也就越来越慢了。 vite vite预构建与按需编译的过程,都是使用esbuild完成的。 esbuild是用go语言编写的,可以充分利用多核CPU的优势,所以vite开发环境下的预构建与按需编译速度,都是非常快的。 http2 vite充分利用了http2可以并发请求的优势,这也是速度快的一个主要原因。 接下来,我们了解一下http2的来龙去脉。 在之前http1的时候,浏览器对同一个域名的请求,是有并发限制的,一般为6个,如果并发请求6个以上,就会造成阻塞问题,所以在http1的时代,我们要减少打包产物的文件数量,减少并发请求,来提高项目的加载速度。 2015年以后,http2出现了,他可以并发发送多个请求,不会出现http1的并发限制。这时候,将打包产物分成多个小模块,并行去加载,反而会更快。 vite也充分利用了这一优势,对项目资源进行了合理的拆分,访问项目时,同时加载多个模块,来提升项目访问速度。 热更新 vite速度快的另一个原因是与webpack不同的热更新机制。 ...

October 5, 2024

数据绑定

1. 定义 1.1 双向绑定 & 单向绑定 vue的双向绑定,即数据与视图的响应式设计。具体表现为:View的改变能实时让Model发生变化,而Model的变化也能实时更新View。 什么情况下用户可以更新View呢?如:填写表单。当用户填写表单时,View的状态就被更新了,如果此时MVVM框架可以自动更新Model的状态,那就相当于把Model和View做了双向绑定。 注意区别:单向数据绑定,所有数据只有一份,一旦数据变化,就去更新页面(只有data–>DOM,没有DOM–>data)。 用户在页面作出更新,需要用户手动收集(双向绑定是自动收集),在合并到原有的数据中。 Vue.js中的v-model主要用在表单的input输入框,完成视图和数据的双向绑定: <!DOCTYPE html> <html> <head></head> <body> <div id="app"> <input type="text" v-model="message"> <p>{{message}}</p> </div> <script> var app = new Vue({ el: '#app', data: { message: '' } }); </script> </body> </html> 1.2 v-model来添加双向绑定 <input v-model="xxx"> <!-- 上面的代码等价于 --> <input :value="xxx" @input="xxx = $event.target.value"> <!-- 双向绑定 = 单向绑定 + UI事件监听 --> 1.3 双向绑定、单向绑定的优缺点 单向绑定:数据流也是单向的,对于复杂应用来说是实施统一状态管理(如redux)的前提。 双向绑定:在一些需要实时反应用户输入的场合会非常方便(如多级联动菜单)。但常认为复杂应用中这种便利比不上引入状态管理带来的优势。因为不知道状态什么时候发生改变,是谁造成的改变,数据变更也不会通知。 响应式的思路:mvvm Model,View,View-Model 2. 原理概述 Vue 数据双向绑定原理是通过 数据劫持 + 发布者-订阅者模式 的方式来实现的,首先是通过 ES5 提供的 Object.defineProperty() 方法来劫持(监听)各属性的 getter、setter,并在当监听的属性发生变动时通知订阅者,是否需要更新,若更新就会执行对应的更新函数。详见 vue源码。 ...

October 4, 2024

CSRF攻击

CSRF是什么 CSRF(Cross-site request forgery)跨站请求伪造:攻击者诱导受害者进入第三方网站,在第三方网站中,向被攻击网站发送跨站请求,利用受害者在被攻击网站已经获取的注册凭证,绕过后台的用户验证,达到冒充用户对被攻击的网站执行某项操作的目的。 一个典型的CSRF攻击有着如下的流程: 受害者登录a.com,并保留了登录凭证(Cookie)。 攻击者引诱受害者访问了b.com。 b.com 向 a.com 发送请求。 a.com接收到请求后,对请求进行验证,并确认是受害者的凭证,误以为是受害者自己发送的请求。 a.com以受害者的名义执行了这个请求。 攻击完成,攻击者在受害者不知情的情况下,冒充受害者,让a.com执行了自己定义的操作。 CSRF的特点 攻击一般发起在第三方网站,而不是被攻击的网站。被攻击的网站无法防止攻击发生 攻击利用受害者在被攻击网站的登录凭证,冒充受害者提交操作;而不是直接窃取数据 整个过程攻击者并不能获取到受害者的登录凭证,仅仅是“冒用” 跨站请求可以用各种方式:图片URL、超链接、CORS、Form提交等等。 如何进行预防 CSRF通常从第三方网站发起,被攻击的网站无法防止攻击发生,只能通过增强自己网站针对CSRF的防护能力来提升安全性。 防止csrf常用方案如下: 阻止不明外域的访问 同源检测 Samesite Cookie 提交时要求附加本域才能获取的信息 CSRF Token 双重Cookie验证 同源检测 Cookie的同源和浏览器的同源策略有所区别: 浏览器同源策略:协议、域名和端口都相同即同源; Cookie同源策略:域名相同即同源; 在HTTP协议中,每个异步请求都会携带两个header,用来标记来源域名: Origin Header Referer Header 这两个Header在浏览器发起请求时,大多数情况会自动带上,并且不能由前端修改,服务器接收到后可以根据这两个Header确定来源的域名; 综上所述: 同源验证是一个相对简单的防范方法,能够防范绝大多数的CSRF攻击。但这并不是万无一失的,对于安全性要求较高,或者有较多用户输入内容的网站,我们就要对关键的接口做额外的防护措施。 Samesite Cookie属性 在Chrome 51版本后,浏览器的 Cookie 新增加了一个SameSite属性,用来防止 CSRF 攻击。 Cookie的Samesite属性用来限制第三方Cookie, 从而减少安全风险,它有三个值: Set-Cookie: SameSite = Strict; Set-Cookie: SameSite = Lax; Set-Cookie: SameSite = None; Strict: 最为严格,完全禁止第三方Cookie, 跨站点时,任何情况都不发送Cookie; Lax: 限制稍微宽松,大多数情况下时不发送第三方Cookie的,除了a链接、预加载请求和GET表单; None: 关闭SameSite属性,但必须同时设置Secure属性, ...

October 2, 2024

模版字符串

未见过的函数用法: function fun(strings,params1){ console.log(strings); console.log(params1) } fun`params1 = ${333}` // 输出分别为 // ['params1 = ', ''] // 333 不知道各位在学习或开发中有没有遇到过这样的函数调用方式呢?秉承着我没遇到的东西就要发文章来分享分享的原则,经过我查阅资料并加以学习,就让本文来带大家了解一下JS中的标签函数吧。 模板字符串 标签函数的主要作用就是处理模板字符串,所以在了解标签函数之前先了解一下模板字符串(模板字面量)吧。 基本用法 模板字符串是ES6新增的使用模板字面量定义字符串的能力,用反引号```````` 进行分隔。与使用''或""的定义的字符串字面量不同是模板字面量保留换行字符,可以跨行定义字符串。 例如: let str1 = 'xxhh\n2233' let str2 = `xxhh 2233` console.log(str1 === str2) // 结果为true 要注意的是模板字符串中的所有字符都会包含在字符串中,特别在使用缩进的时候,缩进的空格都会包含在字符串中。 let str = ` <div> <h1>xxhh</h1> </div> ` console.log(str.length) // 结果为44,包含了缩进所产出的所有空格 字符串插值 在没有模板字符串时,我们通常会使用+加法运算符来进行字符串的拼接,但有了模板字符串后我们并可通过插值占位符${}来将各字面量、变量或表达式结果来进行拼接,这样可以更容易地创建复杂和动态的字符串,同时保持代码的可读性和简洁性。这是模板字符串最常用的一个特性。 let name = 'xxhh'; let str1 = "name:"+name; let str2 = `name:${name}`; console.log(str1,str2) // name:xxhh name:xxhh console.log(str1 === str2) // true 要注意的是使用字符串插值的所有插入的值都会使用toString()强制转型为字符串,而且任何JavaScript 表达式都可以用于插值。 ...

October 2, 2024

DOCTYPE

DOCTYPE 是一个声明,位于 HTML 文档的最顶部,指示浏览器使用哪种 HTML 或 XHTML 版本来渲染页面。它的主要作用是确保浏览器以标准模式解析文档,从而避免不同浏览器间的渲染差异。正确使用 DOCTYPE 可以提升页面的兼容性和可访问性。 <!DOCTYPE>声明应该位于HTML文档的第一行,紧接着是<html>标签。 例如,对于 HTML5 文档,你只需写: <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Document Title</title> </head> <body> <!-- 页面内容 --> </body> </html> 这个声明告诉浏览器该文档是一个HTML5文档。HTML5是最新的HTML标准,它包括了许多现代化的功能,如语义元素、表单控件、音频和视频等。 DOCTYPE 的作用有以下几个方面: 指定 HTML 版本:浏览器根据 DOCTYPE 的声明来确定使用哪个 HTML 版本来渲染页面,从而保证页面在不同的浏览器上显示一致性。 触发标准模式:在 HTML 中,如果省略了 DOCTYPE 声明,浏览器会进入混杂模式(Quirks mode),这种模式下浏览器的渲染方式与早期的浏览器相同,可能导致页面的显示出现不可预测的错误。而指定了 DOCTYPE 声明,则会触发标准模式(Standards mode),使得浏览器按照 HTML 规范的要求进行页面渲染,从而保证页面的稳定性和可靠性。 供浏览器和开发人员参考:DOCTYPE 声明还包含了有关 HTML 文档的元信息,例如所使用的 DTD(文档类型定义),以及其他的元数据信息,这些信息可以供浏览器和开发人员参考,帮助开发人员更好地了解和掌握 HTML 语言的特点和规范。 提高网页加载速度:指定 DOCTYPE 声明可以帮助浏览器更快地加载网页,因为浏览器知道要使用哪种渲染模式,从而更快地解析 HTML 文档。 避免代码错误:指定 DOCTYPE 声明可以帮助开发人员在编写 HTML 代码时遵循标准,避免一些常见的代码错误,例如忘记关闭标签或者使用非法的属性和元素等等。 除了HTML5的<!DOCTYPE>声明之外,还有一些其他版本的HTML和XHTML文档类型声明。这里是一些例子: 1. HTML 4.01 Strict: ...

September 24, 2024

3D球场项目 (三)

在3D球场项目 (二)中,我们梳理了视频弹幕引擎的整体架构、引擎初始化流程。现在,3D 球场部分基本已经探索完毕,我们接下来就是要解决这个项目的数据驱动部分了。 我们现在研究一下下发数据的来源:Opta,它是全球顶级的体育数据公司,1996 年创立于英国伦敦,现隶属于 Stats Perform,是行业公认的足球数据金标准。 覆盖:20+ 运动、3900+ 赛事、每年 6 万 + 场比赛 规模:7.2PB 历史数据、年采集超 10 亿数据点 精度:单场足球2 万 + 事件点,事件识别准确率 99.8% 腾讯体育采买了 Opta WTA 网球比赛的数据,我们可以通过 Opta 的 API 来获取数据。 根据他们官网的介绍,一个 MA3 网球赛事数据中 typeId 对应的意义如下: 点击展开 / 折叠 Event TypeId 完整对照表 Event TypeId Event Name Description 20 STOP_GAME Indicates that the game has finished. 41 START_SET_1 Start 1st Set 42 START_SET_2 Start 2nd Set 43 START_SET_3 Start 3rd Set 44 START_SET_4 Start 4th Set 45 START_SET_5 Start 5th Set 46 STOP_SET Stop Set 47 T_WO1 w.o. Player 1 48 T_WO2 w.o. Player 2 128 SAFE Safe (No longer used) 129 DANGER Danger (Technical/connection issue at venue) 132 INJ_BREAK Game suspended - Player injured 133 PLAYERS_COMING_OUT Players coming out 141 GAME_ABOUT_TO_START Game about to start 149 GAME_SUSPENDED Game suspended 160 PLAYERS_WARMING_UP Players warming up 162 SHAKE_HANDS_WITH_REFEREE Players shake hands with referee 163 COIN_FLIPPING_FOR_FIRST_SERVER Coin flip to choose first server 164 PLAYERS_TALKING_TO_REFEREE Player(s) talking to the referee 165 REFEREE_CHECKING_POINTMARK Referee checking pointmark 166 BOTH_PLAYERS_SEATED Both players seated 167 PLAYER1_RECEIVING_TREATMENT Player 1 receiving treatment 168 PLAYER2_RECEIVING_TREATMENT Player 2 receiving treatment 169 PLAYERS_GOING_TO_COURT Players going back to court 170 NEXT_GAME_ABOUT_TO_START Next game is about to start 180 T_MORE_THAN_5 Rally, over five shots 181 T_MORE_THAN_10 Rally over ten shots 182 T_MORE_THAN_15 Rally over fifteen shots 187 T_POINT_UNDER_INVESTIGATION Point under investigation 188 T_START_TIE_BREAK Start tie break 191 T_POINT_STOPPED_BY_REF Point stopped by referee 197 UPDATE_SCORE_START Start score update 198 UPDATE_SCORE_FINISHED Score update finished 200 SIDE_CHANGE Side change 206 SHOT_CNT Shot count 216 STATISTIC_VERIFICATION Statistics confirmation 240 NEW_BALLS New balls 241 UMPIRE_ON_COURT UMPIRE ON COURT 242 WARMING_UP_VOLLEY Warming up - volley 243 WARMING_UP_SERVICE Warming up - service 244 ONE_MINUTE One minute 245 TIME Time 246 SHOT_DETAILS Shot details 256 CLS Cancel last sent event 257 CLR Clear events 258 GCC Game conditions changed. 261 SCORER Event details for %RELATED_EVENT% in the %MIN%. minute changed 262 BP Ball position event 264 ODD Odds event (deprecated) 266 TIME_CORRECTION_EVENT Correct timestamp for a missed event 276 START_GAME_CLOCK The (stopped) game clock is (re)started the game is running 277 STOP_GAME_CLOCK The game clock is stopped. Time will not change until Start Game Clock is sent again 278 ADJUST_GAME_CLOCK Game clock value is adjusted manually 279 CSTAT A statistical value is cleared and an additional event with the correct action is sent (e.g. an invalid Ace Home event is replaced by a Service Winner Home) 280 CONF_PERIOD_SCORE Period score confirmed 282 TIME_ADAPTION Time for event %RELATED_EVENT% was adapted by %SEC% seconds 285 PLAYER_DATA_CONFIRMED Player data for %RELATED_EVENT% in the %MIN% confirmed 513 SYS_MSG System Message 514 SCOUT_IN_STADION Scout in Stadium 515 CONNECTION_PROBLEMSSCOUT_OFFLINE Connection problems Scout offline 516 CONNECTION_PROBLEMS Connection problems 517 TRANSMISSION_ONLINE Transmission online 520 LINEUP_CHANGED Line-up changed 524 JERSEY_CHANGED Jersey colors updated 782 GAME CANCELLED Automatic “Game cancelled” event after first “cancellation” System message is sent 1152 T_SERVE1 Service Player 1 1153 T_1ST_SERVICE1 1st service Player 1 1154 T_2ND_SERVICE1 2nd service Player 1 1155 T_NA1 Net approach player 1 1156 T_W_FH1 Winner (forehand) Player 1 1157 T_W_BH1 Winner (backhand) Player 1 1158 T_FE_FH1 Forced error (forehand) Player 1 1159 T_FE_BH1 Forced error (backhand) Player 1 1160 T_UE_FH1 Unforced error (forehand) Player 1 1161 T_UE_BH1 Unforced error (backhand) Player 1 1162 T_HE1 Hawkeye Player 1 1163 T_WBR1 Warning by referee Player 1 1164 T_CBR1 Cautioned by referee Player 1 1165 T_SRV_NET1 Net Player 1 1166 T_SRV_OUT1 Out Player 1 1167 T_SRV_FF1 Foot fault Player 1 1168 T_SRV_DF1 Double fault Player 1 1169 T_SRV_A1 Ace Player 1 1170 T_SRV_SW1 Service winner Player 1 1171 T_SRV_RW_FH1 Return winner (forehand) Player 1 1172 T_SRV_IN1 Serve in Player 1 1173 T_POINT1 Point Player 1 1174 T_CONF1 Confirm Point Player 1 1175 T_GAME1 Game Player 1 1176 T_SET1 Set Player 1 1177 T_BL1 Baseline Player 1 1178 T_SRV_NR1 Net/Retake Player 1 1179 T_W1 Winner Player 1 1180 T_FE1 Forced error Player 1 1181 T_UE1 Unforced error Player 1 1182 T_SRV_RW_BH1 Return winner (backhand) Player 1 1183 T_V_FH1 Volley (forehand) Player 1 1184 T_V_BH1 Volley (backhand) Player 1 1185 T_BB1 Break ball Player 1 1186 T_B1 Break Player 1 1187 T_HES1 Hawk eye successful Player 1 1188 T_ITO1 Injury Timeout Player 1 1189 T_START_SRV1 Start Service Player 1 1190 T_WARNING1 1st offence - warning Player 1 1191 T_PENALTY_POINT1 2nd offence - penalty point Player 1 1192 T_PENALTY_GAME1 3rd offence - penalty game Player 1 1193 T_DISQUALIFICATION1 Disqualification Player 1 1194 T_UE_NET1 Unforced error net Player 1 1195 T_FE_NET1 Forced error net Player 1 1196 T_SUCCESSFUL_NET_APPROACH1 Successful net approach Player 1 1197 T_TIME_VIOLATION1 Time violation Player 1 1198 T_PENALTY_POINT1 T_UNSUCCESSFUL_NET_APPROACH1 Unsuccessful net approach Player 1 1199 T_AT_NET1 At net Player 1 1200 T_AT_BASELINE1 At baseline Player 1 1201 T_SET_BALL1 Set ball Player 1 1202 T_MATCH_BALL1 Match ball Player 1 2176 T_SERVE2 Service Player 2 2177 T_1ST_SERVICE2 1st service Player 2 2178 T_2ND_SERVICE2 2nd service Player 2 2179 T_NA2 Net approach player 2 2180 T_W_FH2 Winner (forehand) Player 2 2181 T_W_BH2 Winner (backhand) Player 2 2182 T_FE_FH2 Forced error (forehand) Player 2 2183 T_FE_BH2 Forced error (backhand) Player 2 2184 T_UE_FH2 Unforced error (forehand) Player 2 2185 T_UE_BH2 Unforced error (backhand) Player 2 2186 T_HE2 Hawkeye Player 2 2187 T_WBR2 Warning by referee Player 2 2188 T_CBR2 Cautioned by referee Player 2 2189 T_SRV_NET2 Net Player 2 2190 T_SRV_OUT2 Out Player 2 2191 T_SRV_FF2 Foot fault Player 2 2192 T_SRV_DF2 Double fault Player 2 2193 T_SRV_A2 Ace Player 2 2194 T_SRV_SW2 Service winner Player 2 2195 T_SRV_RW_FH2 Return winner (forehand) Player 2 2196 T_SRV_IN2 Serve in Player 2 2197 T_POINT2 Point Player 2 2198 T_CONF2 Confirm Point Player 2 2199 T_GAME2 Game Player 2 2200 T_SET2 Set Player 2 2201 T_BL2 Baseline Player 2 2202 T_SRV_NR2 Net/Retake Player 2 2203 T_W2 Winner Player 2 2204 T_FE2 Forced error Player 2 2205 T_UE2 Unforced error Player 2 2206 T_SRV_RW_BH2 Return winner (backhand) Player 2 2207 T_V_FH2 Volley (forehand) Player 2 2208 T_V_BH2 Volley (backhand) Player 2 2209 T_BB2 Break ball Player 2 2210 T_B2 Break Player 2 2211 T_HES2 Hawk eye successful Player 2 2212 T_ITO Injury Timeout Player 2 2213 T_START_SRV2 Start Service Player 2 2214 T_WARNING2 1st offence - warning Player 2 2215 T_PENALTY_POINT2 2nd offence - penalty point Player 2 2216 T_PENALTY_GAME2 3rd offence - penalty game Player 2 2217 T_DISQUALIFICATION2 Disqualification Player 2 2218 T_UE_NET2 Unforced error net Player 2 2219 T_FE_NET2 Forced error net Player 2 2220 T_SUCCESSFUL_NET_APPROACH2 Successful net approach Player 2 2221 T_TIME_VIOLATION2 Time violation Player 2 2222 T_AT_NET2 Unsuccessful net approach Player 2 2223 At net Player 2 2224 T_AT_BASELINE2 At baseline Player 2 2225 T_SET_BALL2 Set ball Player 2 2226 T_MATCH_BALL2 Match ball Player 2 PBP = Play-by-Play(逐回合 / 逐事件数据),就是把一场比赛里每一次事件都按时间线秒级记录下来的最细粒度原始数据流。口语里也叫 “逐帧数据 / 流水账数据”。网球赛事的数据,都是以这个形式下发的,一段数据可能下发的数据是这样的: ...

May 30, 2026

小红书-社招-3年 · 第 3 轮 · 技术面试

← 第 2 轮 · 返回本次面经 · 已是最后一轮 → 本轮概述: 这一轮主要考察了小程序的低代码设计架构、Web Worker的使用、中台系统的微前端拆分策略等方面的知识。 本轮共 4 道题。答案默认折叠,便于先自行作答。 1. 讲一下你关于小程序的低代码设计架构 题目要点 小程序低代码架构本质是配置驱动的运行时体系,核心包括 DSL 协议设计、组件注册机制、运行时解析与数据驱动更新;必须围绕 setData 性能约束进行差量更新与渲染优化;工程重点不在编辑器,而在运行时引擎的性能治理与扩展能力设计。 参考答案 小程序的低代码架构,本质是在受限运行环境下实现“可配置驱动 UI 与逻辑”。核心不是拖拽能力,而是如何让页面结构、交互逻辑、数据流都由配置驱动,同时保证性能与可维护性。 一、整体架构分层 小程序低代码一般分为四层: 编辑层 → DSL 层 → 运行时引擎 → 渲染层 编辑层负责产出结构化配置;DSL 层定义组件树与属性协议;运行时负责解析与调度;渲染层落在小程序原生组件体系之上(如 WXML + setData 机制,在 微信小程序 中即运行于其渲染框架内)。 关键问题在于:小程序不是虚拟 DOM 模型,而是逻辑层与视图层分离,通过 JSON 数据桥接,因此架构必须围绕数据驱动。 二、DSL 设计 DSL 通常采用 JSON Schema 形式,核心包含: 组件类型 属性 props 样式 事件绑定 数据源 条件显示规则 低代码的关键在于“协议稳定性”,一旦 DSL 设计混乱,后续扩展成本会极高。因此会设计: 组件注册机制 属性校验规则 默认值策略 版本兼容策略 三、运行时引擎 运行时是核心。 ...

February 1, 2026

state 与 props

state 基本定义 state是组件内部的状态(数据),不能够直接修改,必须要通过setState来改变值的状态,从而达到更新组件内部数据的作用。 props 基本定义 props是指组件间传递的一种方式,props自然也可以传递state。由于React的数据流是自上而下的,所以是从父组件向子组件进行传递;另外组件内部的this.props属性是只读的不可修改。 代码示例 // 父组件 import stateJj from './stateJj.js'; // 引入子组件 class stateJjFather extends React.Component { constructor(props) { super(props); // 设置state的默认值 且只能在constructor中设置 this.state = { mes: '给子组件的信息', obj: { }, arr: [] } } fun(e) { } render() { const {mes, obj, arr} = this.state; return ( <div> // 不写箭头函数 this指向会发生错误 也可以使用bind的方式绑定this <stateJj name={'给子组件的信息'} name1={mes} fun={(e) => this.fun(e)} obj={obj} arr={arr} /> </div> ); } } // 子组件 class stateJj extends React.Component { constructor(props) { super(props); this.props; // 这里面就有父组件传的值 // 设置 默认state this.state = { text: props.initialValue || 'placeholder' }; // ES6 类中函数必须手动绑定 this.handleChange = this.handleChange.bind(this); } handleChange(event) { this.setState({ text: event.target.value }); } render() { return ( <div> {mes} </div> ); } } // 设置props值的类型 stateJj.propTypes = { optionalArray: PropTypes.array, optionalBool: PropTypes.bool, optionalFunc: PropTypes.func, optionalNumber: PropTypes.number, optionalObject: PropTypes.object, optionalString: PropTypes.string, optionalSymbol: PropTypes.symbol, // 目前可以声明的所有变量类型 }; // 设置默认的props值 stateJj.defaultProps = { }; props的特性 只读性 props经常被用作渲染组件和初始化状态,当一个组件被实例化之后,它的props是只读的,不可改变的。如果props在渲染过程中可以被改变,会导致这个组件显示的形态变得不可预测。只有通过父组件重新渲染的方式才可以把新的props传入组件中。 ...

December 17, 2024

浏览器的垃圾回收机制

浏览器的垃圾回收(Garbage Collection, GC)机制是前端性能优化和内存管理的重要基础。 一、垃圾回收的基本概念 目的:自动回收不再使用的内存,避免内存泄漏,保证浏览器性能稳定。 GC 触发:当浏览器检测到内存不足或特定条件时,启动垃圾回收过程。 二、主要垃圾回收算法 1. 标记清除(Mark-and-Sweep) 浏览器从**根对象(Global、执行上下文中的变量)**开始,标记所有可达对象。 没被标记的对象被认为不可达,即不再被使用,进行回收。 是现代 JS 引擎普遍采用的算法。 2. 引用计数(Reference Counting) 每个对象维护引用计数,引用增加时计数+1,引用消失时计数-1。 计数为 0 的对象立即回收。 缺陷:无法处理循环引用,现代引擎一般不单独使用。 三、垃圾回收的触发时机 内存分配达到一定阈值时自动触发。 主动调用相关接口(如 Chrome DevTools 手动触发)。 页面卸载时进行清理。 四、内存泄漏常见原因 全局变量未释放 全局变量一直被引用,无法回收。 闭包导致的变量无法释放 闭包作用域内变量被外部引用。 定时器未清除 setInterval、setTimeout 未正确清除,导致引用保留。 DOM 节点引用未释放 JS 中持有对已删除 DOM 的引用。 事件监听未移除 绑定事件后,未及时解绑,导致内存无法回收。 五、性能优化建议 避免不必要的全局变量。 使用完定时器及时清除。 解绑不再使用的事件监听。 谨慎使用闭包,避免无用变量持久存在。 小心操作 DOM,及时释放引用。 常见考点 面试中考察点主要包括 GC 的原理、算法、触发时机、内存泄漏原因及避免方法: 浏览器垃圾回收的原理和常见算法? 标记清除与引用计数的区别与优缺点? 什么是内存泄漏?常见的内存泄漏类型? 如何避免内存泄漏? JS 引擎如何判断对象是否可回收? 浏览器中 GC 触发的时机? 如何用 Chrome DevTools 监测内存泄漏? 事件监听和闭包如何导致内存泄漏?

December 17, 2024