指针原来是套娃的博客
type: channel
link: https://blog.imtwa.top/
description: 指针原来是套娃的博客
items: 手写系列一：实现防抖节流
items: webpack学习笔记
items: vscode插件
items: 关于虚拟dom复用导致的组件渲染不一致问题
items: mysql开发规范
items: vue项目commit自动格式化并提交
items: js工具函数大全
items: webRTC与webSocket接入智谱视频通话API避坑指南
items: 详谈JavaScript发展史
items: 软件更新

手写系列一：实现防抖节流
type: item
date: 2025-03-26T21:38:00+08:00
description: 防抖和节流的区别 防抖是在指定时间内只执行一次，如果 再次触发则重新计时 ，即只处理 最后一次响应 。 节流是在指定时间内只执行一次，如果再次触发则不执行，也就是 只执行第一次，后面的触发不管，等到时间过去才再响应一次触发。 防抖常用在输入框搜索、滚动加载、表单提交等高频触发只用处理最后一次响应的地方。 节流常用在滚动监听、窗口变化等，在高频的变化中一段时间内只响应第一次变化，并给出多个中间态，以实现 平滑 的变化。手写实现防抖/** * 防抖在是指定时间内只执行一次，如果再次触发则重新计时 * 一段时间内只处理最后一次事件响应 * 定时器实现 */ function debounce(fn, delay) { let timer = null; return function (...args) { console.log(args); if (timer) { clearTimeout(timer); } timer = setTimeout(() => { fn.apply(this, args); }, delay); }; } const log = debounce((...args) => { console.log("防抖，只执行",args); }, 100); log(1, 2, 3); log(4, 5, 6); setTimeout(() => { log(7, 8, 9); }, 1000); 效果：手写实现节流/** * 节流是指定时间内只执行一次，如果再次触发则不执行 * 一段时间内只处理第一次事件响应 * 定时器实现 */ function throttle(fn, delay) { let timer = null; return function (...args) { console.log(args); // 当第一次获得定时器后，除非定时器到时清除，都会阻止后面的触发 if (!timer) { timer = setTimeout(() => { fn.apply(this, args); timer = null; }, delay); } }; } /** * 时间戳实现 */ function throttle(fn, delay) { let last = 0; // 设置为0 确保第一次触发 return function (...args) { console.log(args); const now = Date.now(); // 下一次超过间隔时间才执行 if (now - last >= delay) { fn.apply(this, args); last = now; } }; } const log = throttle((...args) => { console.log("节流，只执行", args); }, 100); log(1, 2, 3); log(4, 5, 6); setTimeout(() => { log(7, 8, 9); }, 1000);效果：

webpack学习笔记
type: item
date: 2025-03-21T15:13:00+08:00
description: 一、webpack安装与配置官网：https://www.webpackjs.com/npm i webpack webpack-cli // 运行 npx webpack基本配置默认情况下，webpack会读取webpack.config.js文件作为配置文件，也可以通过CLI参数--config来指定某个配置文件 // webpack的基本配置 module.exports = { // 编译模式 "development" | "production" mode: "development", // 配置源码地图 具体配置：https://www.webpackjs.com/configuration/devtool/ devtool: "source-map", // 入口 webpack从入口开始依赖解析 entry:{ // 属性名：chunk的名称， 属性值：入口模块（启动模块） main: "./src/index.js" }, // 出口配置 output: { // 公用的公共路径 / publicPath: "/", // 输出目录为 dist 默认为dist path: path.resolve(__dirname, "dist"), // js 输出到 dist/js/xxx filename: "js/[name].[chunkhash:5].js" }, // loader配置 运行时从从右到左，从下到上 module: { // 模块的匹配规则 rules: [ // 规则1 { // 正则表达式，匹配模块的路径 test: /index\.js$/, // 匹配到了之后，使用哪些加载器 use: ["./loaders/loader1", "./loaders/loader2"] }, // 规则2 { // 正则表达式，匹配模块的路径 test: /\.js$/, // 匹配到了之后，使用哪些加载器 use: ["./loaders/loader3", "./loaders/loader4"] } ] }, // 插件配置 运行顺序看内部生命周期钩子触发顺序，监听相同生命周期时从上到下（从左到右） plugins: [ new MyPlugin({ // 插件内部配置 }) ], // 开发处理器配置 需要安装webpack-dev-server 只在开发环境有效 devServer: { port: 8080, // 自动打开网页 open: true, // 开启热替换HMR 需要在代码里写入 module.hot.accept(); 接受热更新 hot:true, // 代理规则 proxy: { "/api": { target: "http://blog.imtwa.com", //更改请求头中的host和origin changeOrigin: true } } }, // 优化配置 optimization: { splitChunks: { // 分包配置 chunks: "all", // 缓存组配置 cacheGroups:{ } }, }, resolve: { alias: { // 别名 @ = src目录 "@": path.resolve(__dirname, "src"), // 别名 _ = 工程根目录 _: __dirname, }, }, stats: { // 打包时使用不同的颜色区分信息 colors: true, // 打包时不显示具体模块信息 modules: false, // 打包时不显示入口模块信息 entrypoints: false, // 打包时不显示子模块信息 children: false, } };二、webpack打包流程webpacke是实现模块化的重要构建工具，它是将开发时态的代码转成运行时态代码，所以webpack不会影响代码的开发和运行，只会在打包时影响打包过程。所以webpack是运行在node环境下，与浏览器环境无关。初始化此阶段，webpack会将CLI参数、配置文件、默认配置进行融合，形成一个最终的配置对象。编译1、创建chunkchunk是webpack在内部构建过程中的一个概念，译为块，它表示通过某个入口找到的所有依赖的统称。根据入口模块（默认为./src/index.js）创建一个chunk每个chunk都有至少两个属性：name：默认为mainid：唯一编号，开发环境和name相同，生产环境是一个数字，从0开始2、构建所有依赖模块webpack只能分析js代码，将js代码读取后进行AST抽象语法树分析，找到每个代码的依赖，并转换代码。loader在做AST前生效，处理源代码。AST在线测试工具：http…

vscode插件
type: item
date: 2025-03-21T13:02:00+08:00
description: 因为换了几台电脑，每次都要重新安装vscode和插件，这里记录一下用到的插件和对应的配置。Chinese (Simplified) (简体中文) Languagevscode简体中文配置Live Server建立本地服务器，实时显示服务器端页面Remote Repositories查看远程仓库Code Runner执行node代码indent-rainbow缩进颜色显示Draw.io Integration绘图插件any-rule多种正则Regex Previewer检查正则ESLint检查js格式化Prettier - Code formatter格式化检查与修复GitLens — Git supercharged显示git提交CodeGeeX: AI Coding Assistant智谱ai编程助手Markdown Preview Enhancedmarkdown文件预览显示首选项 开启Enable Script Execution（js脚本执行） 启用目录F1 搜索 markdown preview enhanced: customize css 配置css样式/* Please visit the URL below for more information: */ /* https://shd101wyy.github.io/markdown-preview-enhanced/#/customize-css */ .markdown-preview.markdown-preview { // modify your style here // eg: background-color: blue; font-family: "consolas", "Noto Sans S Chinese"; font-size: 1em; } .markdown-img-description{ text-align: center; margin-top: -1em; color: #666;; margin-bottom: 2em; } html body img{ border:2px solid #ccc; } .markdown-p-center{ text-align: center; }F1 搜索 markdown preview enhanced: extend parser 配置jsconst scripts = ` `; var fs = require("fs"); module.exports = { onWillParseMarkdown: function(markdown) { return new Promise((resolve, reject) => { const reg = /\!\[(.*)\]\((\S+)\)/gm; markdown = markdown.replace(reg, function(match, g1, g2) { var width = "100%"; if (g1) { var w = g1.split("|"); if (w.length > 1) { width = w[1] + "px"; g1 = w[0]; } } return ` ${g1} `; }); resolve(markdown); }); }, onDidParseMarkdown: function(html) { return new Promise((resolve, reject) => { return resolve(scripts + html); }); } };

关于虚拟dom复用导致的组件渲染不一致问题
type: item
date: 2024-12-06T16:10:00+08:00
description: 今天开发时，有一个页面需要使用自定义的列表组件，共有两个列表，用按钮切换列表展示，但是第二个列表不需要头部的选择框。本来配置selection选项即可，但是切换过来第二个列表无论怎么配置还是带着选择框的样式，无法去掉，相同配置放到其他页面却没有选择框。代码和样式如下：<-- 部分配置已忽略 --> <el-table-wrap v-if="invoiceStatus === 'bill'" :data="dataList" > <-- 配置选择框 --> <el-table-column type="selection" width="40"> </el-table-column> </el-table-wrap> <el-table-wrap v-else :data="customDataList" > <-- 没有配置 --> </el-table-wrap>但是第二个实现出来却是这样的：但是奇怪的是，同样的配置在其它界面就没有选择框，最后经过调试发现把v-if改成v-show显示没有问题了。<-- 部分配置已忽略 --> <el-table-wrap v-show="invoiceStatus === 'bill'" :data="dataList" > <el-table-column type="selection" width="40"> </el-table-column> </el-table-wrap> <el-table-wrap v-show="invoiceStatus === 'custom'" :data="customDataList" > </el-table-wrap>原来是v-if和v-show的区别，v-if会把元素销毁，再创建元素的时候，vue在虚拟dom阶段会复用之前的节点，导致第二个列表携带着第一个列表的配置。v-show只是隐藏显示，两个列表会同时创建，vue会自动标识加上key值。当然给列表组件加上key也可以解决这个问题，给一个加上即可。<-- 部分配置已忽略 --> <el-table-wrap v-if="invoiceStatus === 'bill'" key="bill" :data="dataList" > <el-table-column type="selection" width="40"> </el-table-column> </el-table-wrap> <el-table-wrap v-else :data="customDataList" > </el-table-wrap>有不一致配置时避免使用v-if改为v-show，或者加上key值。复现demo： <el-button type="primary" @click="selection = !selection">切换</el-button> <el-table v-if="selection" :data="tableData"> <el-table-column type="selection" width="55"/> <el-table-column prop="name" label="姓名" width="120"/> <el-table-column prop="address" label="地址" show-overflow-tooltip/> </el-table> <el-table v-else :data="tableData"> <el-table-column prop="name" label="姓名" width="120"/> <el-table-column prop="address" label="地址" show-overflow-tooltip/> </el-table>

mysql开发规范
type: item
date: 2024-12-04T10:18:00+08:00
description: 1. 规范背景与目的MySQL数据库与 Oracle、 SQL Server 等数据库相比，有其内核上的优势与劣势。我们在使用MySQL数据库的时候需要遵循一定规范，扬长避短。本规范旨在帮助或指导RD、QA、OP等技术人员做出适合线上业务的数据库设计。在数据库变更和处理流程、数据库表设计、SQL编写等方面予以规范，从而为公司业务系统稳定、健康地运行提供保障。2. 设计规范2.1 数据库设计以下所有规范会按照【高危】、【强制】、【建议】三个级别进行标注，遵守优先级从高到低。对于不满足【高危】和【强制】两个级别的设计，审核人员应强制打回要求修改。2.1.1 库名【强制】库的名称必须控制在32个字符以内，相关模块的表名与表名之间尽量体现join的关系，如user表和user_login表。【强制】库的名称格式：业务系统名称_子系统名，同一模块使用的表名尽量使用统一前缀。【强制】一般分库名称命名格式是库通配名_编号，编号从0开始递增，比如wenda_001以时间进行分库的名称格式是“库通配名_时间”【强制】创建数据库时必须显式指定字符集，并且字符集只能是utf8mb4。创建数据库SQL举例：create database db1 default character set utf8mb4;。2.1.2 表结构【强制】表和列的名称必须控制在32个字符以内，表名只能使用字母、数字和下划线，一律小写。【强制】表名要求模块名强相关，如师资系统采用”sz”作为前缀，渠道系统采用”qd”作为前缀等。【强制】创建表时必须显式指定字符集为utf8mb4。【强制】创建表时必须显式指定表存储引擎类型，必须为InnoDB。因为Innodb表支持事务、行锁、宕机恢复、MVCC等关系型数据库重要特性，为业界使用最多的MySQL存储引擎。而这是其他大多数存储引擎不具备的。【强制】建表必须有comment【数仓要求】【强制】建表必须有行数据的创建时间字段create_time和最后更新时间字段update_time，同时该字段应使用入库时间，不要使用程序生成时间，避免数据库与服务器时间差异引起的数据问题【数仓要求】【建议】建表时关于主键：(1)强制要求主键为id，类型为int或bigint，且为auto_increment(2)标识表里每一行主体的字段不要设为主键，建议设为其他字段如user_id，order_id等，并建立unique key索引。因为如果设为主键且主键值为随机插入，则会导致innodb内部page分裂和大量随机I/O，性能下降。【建议】表中所有字段必须都是NOT NULL属性，业务可以根据需要定义DEFAULT值。因为使用NULL值会存在每一行都会占用额外存储空间、数据迁移容易出错、聚合函数计算结果偏差等问题。【建议】建议对表里的blob、text等大字段，垂直拆分到其他表里，仅在需要读这些对象的时候才去select。【建议】反范式设计：把经常需要join查询的字段，在其他表里冗余一份。如user_name属性在user_account，user_login_log等表里冗余一份，减少join查询。【强制】中间表用于保留中间结果集，名称必须以tmp_开头。备份表用于备份或抓取源表快照，名称必须以bak_开头。中间表和备份表定期清理。【强制】对于超过100W行的大表进行alter table，必须经过运维同学审核，并在业务低峰期执行。因为alter table会产生表锁，期间阻塞对于该表的所有写入，对于业务可能会产生极大影响。2.1.3 列数据类型优化【建议】表中的自增列（auto_increment属性），推荐使用bigint类型。因为无符号int存储范围为-2147483648~2147483647（大约21亿左右），溢出后会导致报错。【建议】业务中选择性很少的状态status、类型type等字段推荐使用tinytint或者smallint类型节省存储空间。【建议】业务中IP地址字段推荐使用int类型，不推荐用char(15)。因为int只占4字节，可以用如下函数相互转换，而char(15)占用至少15字节。一旦表数据行数到了1亿，那么要多用1.1G存储空间。 SQL：select inet_aton('192.168.2.12'); select inet_ntoa(3232236044); PHP: ip2long(‘192.168.2.12’); long2ip(3530427185);【建议】不推荐使用enum，set。 因为它们浪费空间，且枚举值写死了，变更不方便。推荐使用tinyint或smallint。【建议】不推荐使用blob，text等类型。它们都比较浪费硬盘和内存空间。在加载表数据时，会读取大字段到内存里从而浪费内存空间，…

vue项目commit自动格式化并提交
type: item
date: 2024-10-09T17:08:00+08:00
description: 在 Vue 项目中，全局格式化（通常指的是代码格式化、样式格式化、数据格式化等）是一个重要的实践，它有助于维护代码的一致性和可读性，促进团队协作，减少因格式不一致导致的合并冲突，以及提高代码质量。先看效果：如果出现错误的commit做到commit的时候自动格式化，需要一下几个步骤：一 配置prettier安装Prettier： npm install --save-dev prettier 或者使用yarn yarn add --dev prettier配置Prettier:项目根目录新建配置文件,配置包括.prettierrc, .prettierrc.json, 或者在package.json内的prettier字段。例如创建一个.prettierrc文件，并设置一些基本规则：基本规则:{ "eslintIntegration": true, //设置为true时，Prettier会尝试避免与ESLint中的格式化规则冲突。这意呀着，如果ESLint和Prettier在格式化代码时有不同的规则，Prettier会尽量遵循ESLint的规则（前提是你已经安装了ESLint并配置了相应的规则）。 "stylelintIntegration": true, //类似于eslintIntegration，但它是针对CSS的。设置为true时，Prettier会尝试避免与Stylelint中的格式化规则冲突。这对于Vue项目中的 部分特别有用，但请注意，Prettier对CSS的支持可能不如Stylelint全面。 "tabWidth": 2, //设置缩进时使用的空格数。在你的配置中，它被设置为2，意味着每次缩进将使用两个空格。 "printWidth": 120, //指定代码行的最大长度。Prettier会尝试将代码格式化为不超过这个宽度的行。在你的配置中，它被设置为120个字符。 "singleQuote": true, //设置为true时，Prettier将使用单引号（'）而不是双引号（"）来包裹字符串。 "semi": false, //设置为true时，Prettier会在语句末尾添加分号。这是JavaScript中常见的做法，尽管ESLint等工具可能允许在某些情况下省略分号。 "arrowParens": "avoid", //控制箭头函数参数周围的括号。在你的配置中，它被设置为"avoid"，这意味着Prettier会尽可能避免在箭头函数参数周围添加括号，除非这是必要的（例如，当参数是一个对象或数组时）。 "trailingComma": "none", //控制多行数组、对象字面量等末尾是否添加逗号。在你的配置中，它被设置为"none"，意味着Prettier不会在末尾添加逗号。 "bracketSpacing": true //设置为true时，Prettier会在对象字面量、数组字面量等的大括号{}或方括号[]内部添加空格。这有助于提高代码的可读性。 }详细版本:{ "printWidth": 200, // 指定行的最大长度 "tabWidth": 4, // 指定缩进的空格数 "useTabs": true, // 是否使用制表符进行缩进，默认为 false "singleQuote": true, // 是否使用单引号，默认为 false "quoteProps": "as-needed", // 对象属性是否使用引号，默认为 "as-needed" "trailingComma": "none", // 是否使用尾随逗号（末尾的逗号），可以是 "none"、"es5"、"all" 三个选项 "bracketSpacing": true, // 对象字面量中的括号是否有空格，默认为 true "jsxBracketSameLine": false, // JSX 标签的右括号是否与前一行的末尾对齐，默认为 false "arrowParens": "always", // 箭头函数参数是否使用圆括号，默认为 "always" "rangeStart": 0, // 指定格式化的范围的起始位置 "requirePragma": false, // 是否需要在文件顶部添加特殊的注释才能进行格式化，默认为 false "insertPragma": false, // 是否在格式化后的文件顶部插入特殊的注释，默认为 false "proseWrap": "preserve", // 是否保留 markdown 文件中的换行符，默认为 "preserve" "htmlWhitespaceSensitivity": "ignore", // 指定 HTML 文件中空格敏感度的配置选项，可以是 "css"、"…

js工具函数大全
type: item
date: 2024-10-09T15:30:00+08:00
description: 效验相关 /** * 手机号码 * @param val 当前值字符串 * @returns 返回 true: 手机号码正确 */ export function verifyPhone(val) { // false: 手机号码不正确 // if ( // !/^((12[0-9])|(13[0-9])|(14[5|7])|(15([0-3]|[5-9]))|(16([0-3]|[5-9]))|(17([0-3]|[5-9]))|(18[0,5-9]))\d{8}$/.test( // val // ) // ) { if (!/^1[3-9]\d{9}$/.test(val)) { return false } else { return true } } /** * 国内电话号码 * @param val 当前值字符串 * @returns 返回 true: 国内电话号码正确 */ export function verifyTelPhone(val) { // false: 国内电话号码不正确 if (!/\d{3}-\d{8}|\d{4}-\d{7}/.test(val)) return false // true: 国内电话号码正确 else return true } /** * 密码 (以字母开头，长度在6~16之间，只能包含字母、数字和下划线) * @param val 当前值字符串 * @returns 返回 true: 密码正确 */ export function verifyPassword(val) { // false: 密码不正确 if (!/^[a-zA-Z]\w{5,15}$/.test(val)) return false // true: 密码正确 else return true } /** * 强密码 (字母+数字+特殊字符，长度在6-16之间) * @param val 当前值字符串 * @returns 返回 true: 强密码正确 */ export function verifyPasswordPowerful(val) { // false: 强密码不正确 if ( !/^(?![a-zA-z]+$)(?!\d+$)(?![!@#$%^&\.*]+$)(?![a-zA-z\d]+$)(?![a-zA-z!@#$%^&\.*]+$)(?![\d!@#$%^&\.*]+$)[a-zA-Z\d!@#$%^&\.*]{6,16}$/.test( val ) ) { return false } else { return true } } /** * 密码强度 * @param val 当前值字符串 * @description 弱：纯数字，纯字母，纯特殊字符 * @description 中：字母+数字，字母+特殊字符，数字+特殊字符 * @description 强：字母+数字+特殊字符 * @returns 返回处理后的字符串：弱、中、强 */ export function verifyPasswordStrength(val) { let v = '' // 弱：纯数字，纯字母，纯特殊字符 if (/^(?:\d+|[a-zA-Z]+|[!@#$%^&\.*]+){6,16}$/.test(val)) v = '弱' // 中：字母+数字，字母+特殊字符，数字+特殊字符 if (/^(?![a-zA-z]+$)(?!\d+$)(?![!@#$%^&\.*]+$)[a-zA-Z\d!@#$%^&\.*]{6,16}$/.test(val)) v = '中' // 强：字母+数字+特殊字符 if ( /^(?![a-zA-z]+$)(?!\d+$)(?![!@#$%^&\.*]+$)(?![a-zA-z\d]+$)(?![a-zA-z!@#$%^&\.*]+$)(?![\d!@#$%^&\.*]+$)[a-zA-Z\d!@#$%^&\.*]{6,16}$/.test( val ) ) { v = '强' } // 返回结果 return v } /** * IP地址 * @param val 当前值字符串 * @returns 返回 true: IP地址正确 */ export function verifyIPAddress(val) { // false: IP地址不正确 if ( !/^(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])$/.test( v…

webRTC与webSocket接入智谱视频通话API避坑指南
type: item
date: 2024-10-08T11:02:00+08:00
description: 先看效果：智谱新上线的音视频通话大模型拥有理解音频和画面的能力，接入该api，需要使用webSocket协议不断传输音频和视频的base64编码。WebRTC（Web Real-Time Communication）是一个支持网页浏览器进行实时语音对话或视频对话的技术，webRTC最强大的功能是无需服务器，可以实现浏览器端对端的音视频通话，这里只使用了webRTC实现视频画面显示。这里就详细说一下从开发到跑起这个demo踩的一些不得不说的血泪坑。一技术栈使用vue2，webRTC自然就选用了vue-webRTC，npm地址：https://www.npmjs.com/package/vue-webrtc/v/2.0.0?activeTab=readme通过看它的readme文档发现，最新版是3.0.1，从3.0.0开始支持vue3，vue2使用的是2.0.0版本。跑vue-webRTC这个示例没有出现问题，但是上线的时候却发现一直报错：Permissions policy violation: camera is not allowed in this document.网上有关这些的文档都是说没有授权导致，在这里查资料卡了很久。线上使用的也是https协议，也授权了权限，调试很多次一直报错，终于在一篇文档里发现了问题： 【Web安全】Permissions Policy（权限策略）详解 不知道是谁给线上环境的响应头里设置了不允许使用麦克风和摄像头，也是吐血了。这里需要从Nginx修改配置，于是换了一个线上环境，成功解决。二智谱接入模型需要使用webSocket协议，这很简单，使用原生js new WebSocket(url)即可，提供了.send()方法发送数据，.onopen方法监听建立连接成功 .onmessage方法监听服务器返回。部分代码如下： this.ws = new WebSocket(this.socketURL + `?Authorization=${APIKey}`) this.ws.onopen = () => { console.log('WebSocket 连接已打开') } this.ws.onmessage = event => { let data = JSON.parse(event.data) console.log('收到服务器消息:', data) } // 发送消息 this.ws.send(JSON.stringify(message))但是接入的时候需要传入apiKey进行鉴权，api文档里写的是将key放在Header头里面，这完全就没有考虑浏览器调用情况！浏览器端对写入header头很严格，而且这也不是简单的get post请求，可以用axios工具设置请求头。所以当时有两种方法，1、找一个可以支持websocket协议写入请求头的库 2、使用@fortaine/fetch-event-source发送fetch请求，fetch是websocket的替代方案，可以解决传复杂参数问题。因为有一个已经封装好了的可以用fetch的库，所以当时选择通过fetch协议调用。通过一番操作以后，发post请求报405 发get请求报400，调试到这里真是吐血了！！用文档给的java代码调用就没有问题，这个文档根本就没有考虑浏览器方案。服务器端只支持websocket协议，而websocket或eventsource是get请求，带参只能跟在url地址后面。所以发post会报405请求方法不对，后端又只从请求头里拿鉴权信息，发get带过去的它都不认。经过一番协商，后端改了鉴权方法，从url地址里拿key信息，这下直接用原生webSocket协议都行了。调试半天，后端改一下协议十分钟搞定。三搞定传输以后，剩下的就比较简单了，从音视频流里获取视频和音频数据，再转成base64编码，直接发送即可。特别感谢：https://github.com/2fps/recorder作者整理的关于音频的资料很详细。请求获取音视频流： // 获得音视频数据流 getUserMedia() { if (navigator.mediaDevices && navigator.mediaDevices.getUserMedia) { navigator.mediaDevices .getUserMedia({ audio: true, // 设置为 true 以请求音频流 video: true }) .then(stream => { // 拿到音视频数据流 this.activeStream = stream // 包含视频&&音频 this.videoStream = new MediaStream(stream…

详谈JavaScript发展史
type: item
date: 2024-09-26T14:09:00+08:00
description: JavaScript发展史 1995年Navigator公司为了可以控制浏览器行为，将某些不宜在服务端完成的操作放到客户端完成，开发了可以嵌入网页的脚本语言JavaScript，并在1996年将JavaScript正式内置在了他们的产品Navigator 2.0 浏览器中。同年，它的竞争对手微软公司，copy了JavaScript，改名叫做JScript，并搭载在IE3.0浏览器中。 Navigator为了抵制微软，规范JavaScript语言，决定将JavaScript提交给国际标准化组织ECMA（European Computer Manufacturers Association），希望为JavaScript定制一套国际标准。至此，我们熟悉的ES标准(ECMAScript)出现。 ES只是一套标准，理论上js可以运行在各种环境里，浏览器只是它的一种环境，但是具体运行还要靠各大厂商实现。ES1.0 ES1.0在1997年发布，基于JavaScript和Jscript制定了一些规范。主要规定了ECMAScript的以下组成部分： 语法， 类型， 语句， 关键字， 保留字， 操作符， 对象；ES2 ES2在1998年发布，对ES1进行了一些小的修订和澄清，但未引入重大新功能。ES3 1999年12月，ECMAScript 3.0版发布，成为JavaScript的通行标准，得到了广泛支持。可以说这一版才是对该标准第一次真正的修改，新增了对正则表达式、新控制语句、try-catch异常处理的支持，并围绕标准的国际化做出了一些小的修改，修改内容包括字符串处理、错误定义和数值输出；第3版也标志着ECMAScript成为了一门真正的编程语言，所有的现代浏览器完全支持 ECMAScript 3。 主要更新和新增功能如下：正则表达式：ES3引入了正则表达式支持，这是处理字符串的一个非常强大的工具。 新的控制语句：switch 和 try...catch 语句，提供了更复杂的控制流选项。 错误处理：引入了try...catch和throw语句，用于异常处理。 新的字符串方法：例如charAt(), charCodeAt(), concat(), indexOf(), lastIndexOf(), slice(), substring(), toLowerCase(), toUpperCase(), 和split()。 新的数组方法：例如concat(), join(), pop(), push(), reverse(), shift(), slice(), sort(), splice(), 和unshift()。 国际化支持：增加了对Unicode的基本支持，以及一些国际化相关的函数。 更严格的错误检查：ES3对某些类型错误进行了更严格的检查，例如在赋值时类型不匹配。 行为一致性：对一些语言特性进行了规范，以确保不同实现之间的行为一致性。 保留字：ES3规范定义了更多的保留字，以避免在未来版本的JavaScript中出现命名冲突。ES4阶段 在ES3发布后的十年里，web开发逐渐兴起，各种更新讨论踊跃而出，ECMA TC39重新召集相关人员共同谋划，结果，出台后的标准几乎是在第3版的基础上完全定义了一门新语言；第4版不仅包含了强类型变量、新语句和新的数据结构、真正的类和经典继承，还定义了与数据交互的新方式。 技术专家委员会成员包括 Microsoft、Mozilla、Google 等大公司；各方对于是否通过这个标准，发生了严重分歧；以 Yahoo、Microsoft、Google 为首的大公司，反对 JavaScript 的大幅升级，主张小幅改动；以 JavaScript 创造者 Brendan Eich 为首的 Mozilla 公司，则坚持当前的草案； 由于各方意见不统一，ES4未能成为正式标准，在ES3发布后的10年里，ES标准并未做大更新。ES5 2009年12月3日，ECMAScript 5.0版正式发布；第5版力求澄清第3版中已知的歧义并添加了新的功能，包括原生JSON对象、继承的方法和高级属性定义，以及严格模式；随着时间的推移，所有的现代浏览器已经完全支持 ES5； 除了ECMAScript的版本，很长一段时间中，Netscape公司（以及继承它的Mozilla基金会）在内部依然使用自己的版本号，这导致了JavaScript有自己不同于ECMAScript的版本号；1996年3月，Navigator 2.0内置了JavaScript 1.0；JavaScript 1.1版对应ECMAScript 1.0，但是直到JavaScript 1.4版才完全兼容ECMAScript 1.0； JavaScript 1.5版完全兼容ECMA…

软件更新
type: item
date: 2024-09-14T10:59:00+08:00
description: 2.1.52.1.5测试版 导出txt文件支持在其它软件观看，新增导入本地书籍功能，优化更新提示，在应用内即可更新，优化少量BUGhttps://pan.imtwa.top/p/MwD3268GCq/xxRead2.1.5.apk2024-9-182.1.4阅读界面增加多个字体选择，加入背景颜色调色盘，优化少量BUGhttps://pan.imtwa.top/p/XWOomDFhQk/xxRead2.1.4.apk2024-9-112.1.2搜索页面精确展示搜索结果，加入搜索超时取消逻辑，优化少量BUGhttps://pan.imtwa.top/p/NPEai7dHQm/xxRead2.1.2.apk2024-8-252.1.0新增作品分类，新增作品标签，优化书城界面，优化少量BUGhttps://pan.imtwa.top/p/NPEai7dHQm/xxRead2.1.2.apk2024-4-52.0.8使用触底刷新，优化搜索页内容过多卡顿问题，优化少量BUGhttps://pan.imtwa.top/p/NPEai7dHQm/xxRead2.1.2.apk2024-4-42.0.6支持音量长按翻页，使用虚拟列表，优化主页目录加载速度，优化少量BUGhttps://pan.imtwa.top/p/NPEai7dHQm/xxRead2.1.2.apk2024-3-42.0.4新增书源管理，使用并发处理，优化数据加载速度和系统性能，优化少量BUGhttps://pan.imtwa.top/p/NPEai7dHQm/xxRead2.1.2.apk2023-11-112.0.2引入Levenshtein算法，优化搜索结果展示，增加多个书源，搜索结果改为多书源结果，优化少量BUGhttps://pan.imtwa.top/p/NPEai7dHQm/xxRead2.1.2.apk2023-11-082.0.0重构项目代码，新增下拉刷新，新增图片查看保存，新增书架宫格展示，优化书源，优化少量BUGhttps://pan.imtwa.top/p/NPEai7dHQm/xxRead2.1.2.apk2023-11-031.1.2新增导出TXT功能，优化少量BUGhttps://pan.imtwa.top/p/NPEai7dHQm/xxRead2.1.2.apk2023-09-251.1.0新增头像昵称简介自定义设置https://pan.imtwa.top/p/NPEai7dHQm/xxRead2.1.2.apk2023-09-221.0.8书架页面新增左滑删除，新增更新提示，优化界面设计https://pan.imtwa.top/p/NPEai7dHQm/xxRead2.1.2.apk2023-09-211.0.6优化榜单界面，解决遇到连续英文翻页阅读页面显示不完全的BUGhttps://pan.imtwa.top/p/NPEai7dHQm/xxRead2.1.2.apk2023-09-181.0.4加入音量翻页功能，优化少量BUGhttps://pan.imtwa.top/p/NPEai7dHQm/xxRead2.1.2.apk2023-09-041.0.2对书源进行替换https://pan.imtwa.top/p/NPEai7dHQm/xxRead2.1.2.apk2023-08-251.0.0初步完成界面设计，实现搜索、阅读、浏览记录、缓存下载等功能https://pan.imtwa.top/p/NPEai7dHQm/xxRead2.1.2.apk2023-08-25