首页
更多应用
Search
1
修改iview的标签为i-的形式而不是驼峰的形式
2,791 阅读
2
PHP微信和企业微信签名
2,522 阅读
3
在VUE中怎么全局引入sass文件
2,223 阅读
4
vscode硬件占用较高解决方案
2,017 阅读
5
解决Macos下storm系列IDE卡顿的问题
1,975 阅读
默认分类
JS
VUE
CSS
mac使用技巧
React
fastmock
登录
/
注册
Search
标签搜索
react
js
vue
vscode
nodejs
项目
代码
webpack
工具
nginx
小程序
css
fastmock
eslint
npm
http
vue-cli3
git
浏览器
const
fastmock技术社区
累计撰写
102
篇文章
累计收到
26
条评论
首页
栏目
默认分类
JS
VUE
CSS
mac使用技巧
React
fastmock
页面
更多应用
搜索到
28
篇与
的结果
2024-09-14
处理TS类型声明文件,保留指定key的类型声明
我的原始需求是这样的,写了一个nodejs命令行工具,工具的功能是,拉取后端接口导出的 postman.json 接口内容,通过接口中的入参出参数据,生成入参出参的TS类型声明文件,达到在ts业务代码中可以校验接口入参和出参类型的目的,postman.json的大致格式如下{ "item": [ { "item": [ { "item": [], "name": "WechatMiniAppNatureController", "description": "WechatMiniAppNatureController" } ], "name": "wpe-miniwe-recycle-srv-api", "description": "exported at 2024-09-09 15:17:40" }, { "item": [ { "item": [ { "request": { "method": "POST", "description": "", "header": [ { "key": "Content-Type", "value": "application/json", "type": "text", "description": "" } ], "body": { "mode": "raw", "options": { "raw": { "language": "json" } }, "raw": "{\n \"Id\": 0\n}" }, "url": { "path": [ "wechat", "rec", "v1", "nature", "apply", "taxRebateInfo" ], "query": [], "host": "{{wpe-miniwe-recycle-srv-web}}", "raw": "{{wpe-miniwe-recycle-srv-web}}/wechat/rec/v1/nature/apply/taxRebateInfo" } }, "response": [ { "name": "退税申请详情接口-Example", "originalRequest": { "method": "POST", "description": "", "header": [ { "key": "Content-Type", "value": "application/json", "type": "text", "description": "" } ], "body": { "mode": "raw", "options": { "raw": { "language": "json" } }, "raw": "{\n \"Id\": 0\n}" }, "url": { "path": [ "wechat", "rec", "v1", "nature", "apply", "taxRebateInfo" ], "query": [], "host": "{{wpe-miniwe-recycle-srv-web}}", "raw": "{{wpe-miniwe-recycle-srv-web}}/wechat/rec/v1/nature/apply/taxRebateInfo" } }, "code": 200, "_postman_previewlanguage": "json", "header": [ { "name": "date", "key": "date", "value": "周一, 09 9月 202415:17:40 GMT", "description": "The date and time that the message was sent" } ], "body": "{\n \"Response\": {\n \"RequestId\": \"\",\n \"Error\": {\n \"Code\": \"\",\n \"Message\": \"\"\n },\n \"Data\": {\n \"id\": 0,\n \"taxRebateNumber\": \"\", //退税申请序号\n \"natureRecordId\": \"\", //自然人档案号\n \"registryNumber\": \"\", //登记序号\n \"collectionItemCode\": \"\", //征收项目代码\n \"collectionItemName\": \"\", //征收项目名称\n \"collectionCode\": \"\", //征收品目代码\n \"taxBureauCode\": \"\", //主管税务所科分局代码\n \"taxAuthorityCode\": \"\", //主管税务机关代码\n \"taxAmountAuthorityCode\": \"\", //税款所属税务机关代码\n \"taxAmountAuthorityName\": \"\", //税款所属税务机关名称\n \"streetTownCode\": \"\", //街道乡镇代码\n \"taxAmount\": 0.0, //应退税额\n \"taxRate\": 0.0, //税率\n \"taxUuid\": \"\", //税票UUID\n \"eleTaxNumber\": \"\", //电子税票号码\n \"taxStartTime\": \"\", //税款所属期起\n \"taxEndTime\": \"\", //税款所属期止\n \"applyStatus\": 0,\n \"rebateStatus\": \"\",\n \"rebateStatusCn\": \"\",\n \"taxStatus\": 0,\n \"rejectReason\": \"\",\n \"bankCardNo\": \"\",\n \"createTime\": \"\"\n }\n }\n}" } ], "name": "退税申请详情接口" } ], "name": "WechatMiniAppTaxController", "description": "WechatMiniAppTaxController" }, { "item": [ { "request": { "method": "POST", "header": [ { "key": "Content-Type", "value": "application/json", "type": "text", "description": "" } ], "body": { "mode": "raw", "options": { "raw": { "language": "json" } }, "raw": "{\n \"QrId\": \"\"\n}" }, "url": { "path": [ "wechat", "rec", "v1", "operator", "inviteConfirm" ], "query": [], "host": "{{wpe-miniwe-recycle-srv-web}}", "raw": "{{wpe-miniwe-recycle-srv-web}}/wechat/rec/v1/operator/inviteConfirm" } }, "response": [ { "name": "operatorInviteConfirm-Example", "originalRequest": { "method": "POST", "header": [ { "key": "Content-Type", "value": "application/json", "type": "text", "description": "" } ], "body": { "mode": "raw", "options": { "raw": { "language": "json" } }, "raw": "{\n \"QrId\": \"\"\n}" }, "url": { "path": [ "wechat", "rec", "v1", "operator", "inviteConfirm" ], "query": [], "host": "{{wpe-miniwe-recycle-srv-web}}", "raw": "{{wpe-miniwe-recycle-srv-web}}/wechat/rec/v1/operator/inviteConfirm" } }, "code": 200, "_postman_previewlanguage": "json", "header": [ { "name": "date", "key": "date", "value": "周一, 09 9月 202415:17:40 GMT", "description": "The date and time that the message was sent" } ], "body": "{\n \"Response\": {\n \"RequestId\": \"\",\n \"Error\": {\n \"Code\": \"\",\n \"Message\": \"\"\n },\n \"Data\": false\n }\n}" } ], "name": "operatorInviteConfirm" } ], "name": "WechatMiniAppOperatorController", "description": "WechatMiniAppOperatorController" } ], "name": "wpe-miniwe-recycle-srv-web", "description": "exported at 2024-09-09 15:17:40" } ], "info": { "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json", "name": "wpe-miniwe-recycle-srv-20240909151740", "description": "exported at 2024-09-09 15:17:40" } }上面的接口文档中 接口地址为 /wechat/rec/v1/nature/apply/taxRebateInfo 的接口返回体,经过数据反解析后输出的Ts类型声明代码为export type TWechatRecV1NatureApplyTaxRebateInfoRess = { Code: number; Error: { Code: number; Message: string; }, RequestId: string; Data: { id: number; taxRebateNumber: string; natureRecordId: string; // ... 其他属性 } };上面的代码中,除了Data内的数据,其他的都是所有接口相同的属性内容,所以我需要处理生成的ts文件,只保留 Data 的类型描述。也尝试过好几种方案,主要有从源代码处理,在postman文件的response -> body 代码中处理完内容再去做反解析在生成的文件中通过字符串匹配去查找上面的方法中,主要都存在一个问题,就是postman源代码中,body包含了很多杂七杂八的内容,比如换行符,注释,还有转译字符,加上body内容的层级是不固定,这为我们做正则匹配带来了很多麻烦,所以兜兜转转想到了最终的解决方案,那就是使用AST的方法来处理生成的TS代码,这样在操作AST的过程中,babel 会帮我们处理好注释和其他不相关的内容。先show一下最终的代码// 要先安装下面的依赖 const parser = require('@babel/parser'); const traverse = require('@babel/traverse').default; const generate = require('@babel/generator').default; /** * 取出声明代码中指定key的interface代码 * 使用babel的抽象语法树转换,处理,生成代码 * @param typeCode ts代码 * @param rootName 根类型名 * @param keyName 属性名 * @returns 取出的代码 */ export const subInterfaceByKey = (typeCode: string, rootName: string, keyName: string): string => { // 从ts类型声明代码中取出指定key的interface代码,现将代码转换成ast const ast = parser.parse(typeCode, { sourceType: 'module', plugins: ['typescript'] }); let titleType = 'any'; // 从ast中找到指定key的接口,生成代码返回。 traverse(ast, { TSInterfaceDeclaration(path) { if (path.node.id.name === rootName) { const properties = path.node.body.body; const titleProperty = properties.find(prop => prop.key.name === keyName); // console.log(titleProperty.typeAnnotation); if (titleProperty) { titleType = generate(titleProperty.typeAnnotation).code; } } }, }); if (titleType !== 'any') { // 去掉类型前面的冒号和空格 return titleType.replace(/:\s/, ''); } return titleType; };上面的代码中,通过babel parser将要处理的代码转换成ast,然后通过 traverse 的 TSInterfaceDeclaration 勾子来处理ts interface 类型的代码,最后将处理后的代码生成好赋值给变量返回,处理后的声明文件内容就成了下面这个样子了export type TWechatRecV1NatureApplyTaxRebateInfoRess = { id: number; taxRebateNumber: string; natureRecordId: string; // 。。。其他属性 };至于为什么要用type而不是interface,原因是,Data 数据有可能不是一个对象,而是基础数据类型或数组,比如export type TWechatRecV1JodCancelCmbcBillRess = boolean;经过这次经验,我想以后再遇到这种代码处理的需求,我不会第一时间想到通过正则来处理,而是通过AST来处理了,即安全又逻辑清晰,
2024年09月14日
4 阅读
0 评论
0 点赞
2024-07-04
那些平时很少用的npm配置
一、在package.json 中可以指定包为本地归档文件,让项目可离线安装依赖和编译 "devDependencies": { "@commitlint/cli": "^9.1.2", "@commitlint/config-conventional": "^9.1.2", "@commitlint/prompt-cli": "^9.1.2", "@tencent/babel-plugin-tea-component": "file:./lib/babel-plugin-tea-component-1.0.2.tgz", "@tencent/eslint-config-prettier": "file:./lib/eslint-config-prettier-2.0.0.tgz", "@tencent/eslint-config-prettier-typescript-react": "file:./lib/eslint-config-prettier-typescript-react-2.1.0.tgz", "@tencent/eslint-config-react": "file:./lib/eslint-config-react-2.1.0.tgz", |如上面的代码,在./lib 目录下存放npm包的tgz文件,然后通过 file: 前缀指定包的路径即可注意:如果包有其他依赖包,且也有离线需求,也需要放到依赖项里然后指定离线文件的位置二、可以为私有npm仓库单独指定registry 镜像源# ~/.npmrc @tencent:registry=https://mirrors.cloud.tencent.com/npm/如上面的配置,将 @tencent 下的npm包指向到腾讯镜像源,这样,即使没有修改全局的镜像源地址(即registry=https://xxx.xxxxxx.com/npm/)我们在安装依赖时,当安装到dependencies依赖项是 @tencent/xxx 开头的包时,也会从腾讯镜像源拉取依赖包npmrc的配置存在优先级,当我们在多个配置文件中定义相同的键时,npm将按照以下顺序查找和应用配置:1、项目根目录下的.npmrc文件2、用户主目录下的.npmrc文件(即上面的 ~/.npmrc)3、npm内置的默认配置三、在npmrc 中可以配置不同的镜像源的访问信息(如果镜像源设置了鉴权访问)@fm:registry=https://xxx.xxxxxxx.net/npm/ always-auth=true //xxx.xxxxxxx.net/npm/:username=在npm镜像源管理页面生成的用户名 //xxx.xxxxxxx.net/npm/:_password="在npm镜像源管理页面生成的密码" //xxx.xxxxxxx.net/npm/:email=zhangsan123@qq.com在npmrc中配置后,就不需要再拉取依赖的时候进行身份验证了
2024年07月04日
36 阅读
0 评论
0 点赞
前端性能优化之webpack打包优化
前端工程化彻底盛行的今天,我们已经习惯使用打包工具来帮助我们打包代码到最终能在浏览器运行的js或者css代码,这样我们就可以在编写代码时放心地使用所有的高级语法,其中最让前端coder感到爽快的就是 import export,我们不再需要像以前一样在html里面放很多很多script。或者使用amd。cmd,requirejs工具来写模块引用的代码,这些方便,也让我们很容易忽略一个问题,就是打包的产物的大小,当一个项目足够大时,我们的js甚至可以达到几MB到几十MB,所以,今天就来总结下关于减小构建产物体积,来达到减少首屏加载时间的内容webpack 官方自带的优化策略 https://www.webpackjs.com/configuration/optimization/这里以react项目为例,列举需要优化的构建项一、使用代码拆分,让我们的页面代码构建到单独的js,首次访问页面的时候才加载这块jsmodule.exports = { optimization: { { usedExports: true, concatenateModules: false, chunkIds: 'deterministic', runtimeChunk: true, // 将运行时依赖单独打包-运行时依赖如我们使用的async await语法所需的降级兼容代码 设置为 'single' 则所有的runtime依赖打包到一个文件 // 使用代码拆分 参考文档 https://www.51cto.com/article/689344.html splitChunks: { chunks: 'async', // webpack 打包chunk分为 entry chunk 和async chunk两种,配置文件中的entry配置的主包是默认拆分的,多个入口,多个 main chunk。async chunk就是使用import('./xxx.js') 一步模块加载方法加载的模块。那么 chunks选项就是指定这两种chunk哪些需要分包的,`initial` 只分包主包, async 只分包异步加载的包。all 分包上面两种包,这里要注意的就是all有时候会理解成“所有”就会以为所有使用了import './xxx.js'引入的包都会被分包 minSize: 20, // 超过了这个大小的包才会被拆分 minRemainingSize: 0, minChunks: 1, // 被引用次数大于这个数的包才会被拆分,这里要注意的是,被引用是只命中entry chunk 和 async chunk 的引用者才算 maxAsyncRequests: 30, maxInitialRequests: 30, enforceSizeThreshold: 100, // 超过这个大小的包,不管有没有命中上面的配置,都分包 // 对指定规则的文件使用特定的分包策略 cacheGroups: { vendors: { test: /[\\/]node_modules[\\/]/, // 匹配文件路径 type:/\.json$/, // 匹配文件类型 idHint:'vendors',// 用于设置 Chunk ID,它还会被追加到最终产物文件名中,例如 idHint = 'vendors' 时,输出产物文件名形如 vendors-xxx-xxx.js minChunks: 1, minSize: 0, priority: 2 // 设置优先级,如果文件命中多个groups策略,优先使用这个配置数字较大的规则组 } } } } } }接下来,在react路由里,将组件引入代码 import Xxxx from '@src/routes/Xxxx' 修改为如下引用方式//该组件是动态加载的 千万注意,因为组件是动态加载的,那么。就有可能出现加载失败或者加载错误的情况,所以需要使用 Suspense 组件来包裹,组件还未加载,显示fallback中的内容,组件加载完成,显示组件,加载失败会throw一个error,防止页面崩溃 const Home = React.lazy(() => import('./Home')); function Layout() { return ( // 显示 <Spinner> 组件直至 Home 加载完成 <React.Suspense fallback={<Spinner />}> <div> <Home /> </div> </React.Suspense> ); }上面的分包策略的理解注释中的内容提到了分包的条件和规则,那么,为了尽可能减小我们的主包的大小,我们就要尽可能减少在我们的 entry 选项中指定的入口文件中对其他模块的引用,或者使用异步模块引用的方式,常见的几个优化项目为优化使用到的工具的引用,将必要的工具引用单独提到一个文件中,避免打包其他没用到的代码到主包有些应用初始化相关但是跟主应用无关的代码,使用异步模块加载,如下// app.ts (async () => { const {default: AppInit} = await import('./app-init'); aegis = AppInit.tam(); AppInit.dataInsight(); AppInit.chunkError(); })();如果在入口文件中有react或者vue路由使用的组件,使用react或vue提供的异步路由方法引入使用二、将三方库通过CDN引入而不打包到我们的代码包默认情况下,我们一般都会将我们所需要的依赖,例如react,moment,axios等三方包通过npm或yarn安装到本地,然后直接import进来使用,这种方式势必就会将这些第三方包打包到我们自己的js中,且因为这些库本身体积就较大,所以会导致我们打包出来的js非常大,而且,当我们使用了chunk切分后,各个chunk都会单独打包进去这些依赖内容。针对这种情况,webpack提供了 externals 选项来让我们可以从外部获取这些扩展依赖,首先,我们需要通过script标签的形式来引入我们需要使用的三方库,有两种方式,一种是手动在 html-webpack-plugin 的html模板文件或者content内容中加入script标签,第二种是使用html-webpack-tags-plugin插件,通过配置的方式往html内容中动态插入script标签,这里推荐后者,原因是方便写判断逻辑,而不是在html中通过ejs模板语法来写判断逻辑然后,配置externals选项告诉webpack当我们使用import语句导入模块时,实际使用的是是什么内容(一般三方库都会导出一个包含了所有他包含内容的全局变量)const assetsPath = 'https://static.xxx.com/js'; module.exports = { externals: isDev ? {} : { // 排除不打包 'react': 'React', 'react-dom': 'ReactDOM', 'react-router': 'ReactRouter', 'react-router-dom': 'ReactRouterDOM', 'axios': 'axios', 'moment': 'moment', 'moment-timezone': 'moment', 'lodash': '_', }, plugins: [ ...config.plugins, new webpack.ContextReplacementPlugin(/moment[/\\]locale$/, /zh-cn|ja|ko/), new webpack.DefinePlugin(envKeys), // 开发环境不使用这种方式,因为会影响本地开发的热更新 new HtmlWebpackTagsPlugin({ tags: isDev ? [] : [ { type: 'js', path: '/react-16.11.0.production.min.js', attributes: { defer: 'defer' }, // defer: load完成后不立即执行,等带页面DOMLoaded事件执行前执行,等价于把script放到所有dom之后 publicPath: assetsPath, append: false, }, { type: 'js', path: '/react-dom-16.11.0.production.min.js', attributes: { defer: 'defer' }, publicPath: assetsPath, append: false, }, { type: 'js', path: '/react-router-5.2.1.min.js ', attributes: { defer: 'defer' }, publicPath: assetsPath, append: false, }, { type: 'js', path: '/react-router-dom-5.2.1.min.js', attributes: { defer: 'defer' }, publicPath: assetsPath, append: false, }, { type: 'js', path: '/axios-0.26.0.min.js', attributes: { defer: 'defer' }, publicPath: assetsPath, append: false, }, { type: 'js', path: '/moment.min.js', attributes: { defer: 'defer' }, publicPath: assetsPath, append: false, }, { type: 'js', path: '/lodash-4.17.21.min.js ', attributes: { defer: 'defer' }, publicPath: assetsPath, append: false, }, { type: 'js', path: '/moment-timezone-with-data-10-year-range.min.js', attributes: { defer: 'defer' }, publicPath: assetsPath, append: true, }, ], }), new CopyWebpackPlugin({ patterns: [ { from: 'public', globOptions: { ignore: ['**/index.html'], }, to: 'dist', }, ], }), ].concat(!isDev ? [new BundleAnalyzerPlugin({analyzerPort: 8889, analyzerMode: 'static'})] : []), }
2023年12月14日
137 阅读
0 评论
0 点赞
2023-12-11
记录在TS项目中使用eslint规范代码时遇到的问题
一、代码无法识别 as 表达式报错内容:as语句无法识别,导致(window as any).hello这种语句报错问题原因:eslint 在检测代码时,会先将代码转换为 AST 对象 而这个转换过程需要指定的解析器才能完成,eslint 默认使用的是babel解析器,而babel解析器里没有包含ts语法内容的解析器,所以,我们需要使用ts为eslint开发的解析器解决方法:确保安装了eslint以及ts eslint解析器 npm install --save-dev eslint @typescript-eslint/parser @typescript-eslint/eslint-plugin修改eslint配置文件 .eslintrc.js 中的解析器的配置项,配置内容如下module.exports = { root: true, env: { browser: true, mocha: true, node: true, es6: true, commonjs: true }, plugins: [ '@typescript-eslint/eslint-plugin', // 加载插件,使其对代码进行处理 'react', 'import' ], parser: '@typescript-eslint/parser', // 指定AST解析器为ts的eslint解析器 // ... 其他配置 }二、在interface或者type类型声明中,函数生命中的参数类型表达式报 'xxx' is defined but never used.eslintno-unused-vars报错内容:在interface或者type类型声明中,函数生命中的参数类型表达式报 'xxx' is defined but never used.eslintno-unused-vars报错原因:eslint在执行 no-unused-vars 规则检测时,使用的是默认的检测规则,也就是 js 的变量检测规则解决方法:禁用默认的no-unused-vars改为 @typescript-eslint/no-unused-vars 这个规则会排除interface或者type类型声明中的无函数体函数的检测,更改后的rules内容rules: { 'react/jsx-filename-extension': [ 'error', { extensions: ['.js', '.jsx', '.ts', '.tsx'] } ], // ... 其他配置 'eol-last': 2, // 文件以单一的换行符结束 // 'no-unused-vars': [1, { vars: 'all', args: 'after-used' }], // 不能有声明后未被使用的变量或参数 'no-unused-vars': 'off', '@typescript-eslint/no-unused-vars': ['error'], // ... 其他配置 }
2023年12月11日
62 阅读
0 评论
1 点赞
2023-01-12
使用ua-parser库处理userAgent判断微信授权登录支持的浏览器
平时我们在js中判断浏览器名称和版本都是通过解析userAgent字符串来判断,但是自己挨着用字符串判断始终不能保证处理的准确性,这种时候就可以考虑找找社区有没有比较成熟的解析库了,成熟的库优势就是经过比较漫长的迭代沉淀,且根据用户反馈做了更多的优化调整。对于ua解析库,比较成熟的就是 ua-parser 了,ua-parser 有很多语言版本,支持 python php golang 等,前端直接使用 ua-parser-js 就可以了import UAParser from 'ua-parser-js'; const WECHAT_SUPPORT_DEVICE = [ { // 微信内 webview browser: 'wechat', }, { // uc浏览器 browser: 'ucbrowser', }, { // qq 浏览器 browser: 'qqbrowser', }, { // ios safari 浏览器 browser: 'mobile safari', os: 'ios', }, ]; function isWechatSupportDevice(): boolean { const parser = new UAParser(navigator.userAgent); // you need to pass the user-agent for nodejs const parserResults = parser.getBrowser(); const browserName = parserResults.name; console.log(browserName); const isValid = WECHAT_SUPPORT_DEVICE.some((item) => item.browser === browserName.toLowerCase()); return isValid; },
2023年01月12日
315 阅读
0 评论
0 点赞
2022-11-30
前端常用框架或库收集整理
前端常用框架或库收集整理React 常用组件react-use 常用的自定义 hooks 合集react-hook-form 最常用 react 表单处理hooks,用来做表单验证处理,提交等react-cool-img react图片懒加载react-cool-inview react元素块内容进入页面可视区域监听组件,类似于react-dnd 拖放效果组件react-sortable-tree 可以排序的树形组件@uiw/react-md-editor md 编辑器,可以自定义控件,如上传等shepherdjs 网站新手引导框架 也有react 组件 https://shepherdjs.dev/docs/react-files-uploading react 文件上传组件 https://www.npmjs.com/package/react-files-uploadingreact-images-uploading react 图片上传组件 https://www.npmjs.com/package/react-images-uploadingreact-intersection-observer react 图片和dom懒加载 https://github.com/thebuilder/react-intersection-observerreact-share 网站分享快速生成按钮和图表的组件NodeJscheerio 用jquery语法来解读提取html文本内容的爬虫内容分析库ora 命令行loading工具consola 命令行人机交互输入工具,可以异步执行多个输入,单选,多选,确认 操作commander 命令行工具,注册命令,指定命令的说明,可选参数,以及要执行的代码,一般配合上面的 consola 来实现命令行工具sharp 图片合成和处理工具,可以修改图片大小,滤镜,网图片上加文字,图片等UI 组件库ElementUI vue 框架使用最多的组件库Framework7 支持所有主流前端框架,三端都有组件库JS 绘图jsplumb 拓扑图绘制框架fabricjs canvas库,支持画图,绑定操作,事件等,让canvas变简单ECharts 不用多说,无人不知,无人不晓Cytoscape.js 主要用来画连线图,如关系图谱JS 动画Tween.js 一个简单的 JavaScript 补间(比如css3的ease-in)动画库Snap.svg 绘制svg的类库,超级简单方便的apiAnime.js 类似jquery和jquery-ui的动画库,直接操作domwaypoint.js jquery监听dom进入浏览器可是窗口区域插件parallax.js 视距差效果JS工具函数html-to-text 将html内容转换成纯文本去除富文本内容字符串格式处理工具,支持多层级处理驼峰,下划线,大驼峰等的转换 https://www.npmjs.com/package/humps音视频相关webm-muxer/mp4-muxer 音视频录制并生成视频工具库 https://www.npmjs.com/package/webm-muxerjs-audio-recorder https://www.npmjs.com/package/js-audio-recorder 音频录制,支持录制时的声波显示等,非常强大代码编辑器Ace editor Ace是一个用JavaScript编写的嵌入式代码编辑器。它与Sublime,Vim和TextMate等原生编辑器的功能和性能相匹配。它可以很容易地嵌入到任何网页和JavaScript应用程序中。作为与codemirror同类的现代编辑器,ACE同样拥有mode进行语法解析,实现编辑器的智能感知型功能。CodeMirror 是一个用JavaScript为浏览器实现的多功能文本编辑器。它专门用于编辑代码,并附带一些实现更高级编辑功能的语言模式和插件。其核心仅提供编辑器功能,其他功能通过丰富的API和插件实现。CodeMirror的使用基于特定的程序语言模式(mode),它对特定的语言进行语法解析(parse),使编辑器能够在解析结果基础上进行语法高亮,实现具有上下文感知(context-aware)的代码补全、缩进等功能。monaco editor monaco是VS Code的代码编辑器,同时也是一个开源代码编辑器,可以嵌入到Web应用程序中社区整理常用库10个按钮特效 http://www.adobeedu.com/%E8%BF%9910%E4%B8%AA%E6%8C%89%E9%92%AE%EF%BC%8C%E6%8A%8A-css-hover-%E7%9A%84%E5%88%9B%E6%84%8F%E5%8F%91%E6%8C%A5%E5%88%B0%E6%9E%81%E8%87%B4%E4%BA%86/HTML5+CSS3 最酷的 loading 效果收集 https://www.runoob.com/w3cnote/free-html5-css3-loaders-preloaders.html
2022年11月30日
384 阅读
0 评论
0 点赞
2022-11-16
[webpack踩坑路之]css提取插件mini-css-extract-plugin和speed-measure-webpack-plugin冲突
当我们使用webpack5.x打包项目时,在现网环境需要使用mini-css-extract-plugin将我们的样式打包到独立的样式文件中,使用官方推荐配置能正常运行const MiniCssExtractPlugin = require("mini-css-extract-plugin"); module.exports = { plugins: [ new MiniCssExtractPlugin({ // Options similar to the same options in webpackOptions.output // all options are optional filename: "[name].css", chunkFilename: "[id].css", ignoreOrder: false, // Enable to remove warnings about conflicting order }), ], module: { rules: [ { test: /\.css$/, use: [ { loader: MiniCssExtractPlugin.loader, options: { // you can specify a publicPath here // by default it uses publicPath in webpackOptions.output publicPath: "../", }, }, "css-loader", ], }, ], }, };但是当我们同时使用了 speed-measure-webpack-plugin 插件来打印各个module的打包时间时,就会出现无法正常打包的情况,报错信息如下:Webpack 5 fails as soon as I smp.wrap() my config, with the following error: ERROR in ..../Error.scss Module build failed (from ../../node_modules/mini-css-extract-plugin/dist/loader.js): Error: You forgot to add 'mini-css-extract-plugin' plugin (i.e. `{ plugins: [new MiniCssExtractPlugin()] }`), please read https://github.com/webpack-contrib/mini-css-extract-plugin#getting-started at Object.pitch (.../node_modules/mini-css-extract-plugin/dist/loader.js:50:14)这时候我们需要去判断下,再不需要输出打包时间的情况下,不使用 smp 插件,如,我的方式const wrapConfig = isDev ? smp.wrap : (config) => config; module.exports = wrapConfig({ })
2022年11月16日
453 阅读
0 评论
0 点赞
2022-11-12
fabricjs马赛克笔刷
最近在做一个浏览器插件,其功能是截取当前网页的部分内容,然后像聊天工具截图那样编辑图片,其中的一个工具的给图片打马赛克。实际效果如下通过方案对比最终采用了自定义画笔的方式来实现而不是矩形区域框选的方案。代码如下:PS: 以下代码基于fabricjs 5.2.1 版本生成马赛克笔刷的工具函数 fabric-brush.tsimport { IMosaicPatternBrush } from '@/types/fabric-shim'; import { fabric } from 'fabric'; const mosaicify = (imageData: ImageData) => { const { data } = imageData; const iLen = imageData.height; const jLen = imageData.width; let index; let i; let j; let r; let g; let b; let a; let _i; let _j; let _iLen; let _jLen; // const { blockSize } = this; const blockSize = 20; for (i = 0; i < iLen; i += blockSize) { for (j = 0; j < jLen; j += blockSize) { index = (i * 4 * jLen) + (j * 4); r = data[index]; g = data[index + 1]; b = data[index + 2]; a = data[index + 3]; _iLen = Math.min(i + blockSize, iLen); _jLen = Math.min(j + blockSize, jLen); for (_i = i; _i < _iLen; _i++) { for (_j = j; _j < _jLen; _j++) { index = (_i * 4 * jLen) + (_j * 4); data[index] = r; data[index + 1] = g; data[index + 2] = b; data[index + 3] = a; /* data[index] = 0; data[index + 1] = 0; data[index + 2] = 0; */ } } } } }; export const mosaicBrush = (fabricCanvas: fabric.Canvas): IMosaicPatternBrush => { const squareBrush: IMosaicPatternBrush = new fabric.PatternBrush(fabricCanvas); // getPatternSrc 取得要重复绘製的图形 Canvas squareBrush.getPatternSrc = function() { // 创立一个暂存 canvas 来绘製要画的图案 const cropping = { left: 0, top: 0, width: fabricCanvas.width, height: fabricCanvas.height, }; const imageCanvas = fabricCanvas.toCanvasElement(1, cropping); const imageCtx: any = imageCanvas.getContext('2d'); const imageData = imageCtx.getImageData(0, 0, imageCanvas.width, imageCanvas.height); mosaicify(imageData); imageCtx.putImageData(imageData, 0, 0); const patternCanvas = (fabric as any).document.createElement('canvas'); // 这里的ceateElement一定要使用fabric内置的方法 const patternCtx: any = patternCanvas.getContext('2d'); patternCanvas.width = fabricCanvas.width || 0; patternCanvas.height = fabricCanvas.height || 0; patternCtx.drawImage( imageCanvas, 0, 0, imageCanvas.width, imageCanvas.height, cropping.left, cropping.top, cropping.width, cropping.height ); return patternCanvas; }; return squareBrush; }; 使用// 生成马赛克画笔实例 const brush: IMosaicPatternBrush = mosaicBrush(fabIns); // 这里不能少,否则画出来的内容不会生效,会被其他内容覆盖 brush.source = brush.getPatternSrc.call(brush); // 设置画笔 fabIns.freeDrawingBrush = brush;
2022年11月12日
423 阅读
0 评论
0 点赞
2022-06-26
使用webpack打包对外lib时import取到的是空对象或undefined
首先,webpack默认认为你现在正在开发的是一个应用而不是一个对外使用的库,所以默认打包结构是一个闭包,然后模块是作为闭包的参数列表,是个数组,每一项也是个匿名函数也就是说,你在代码中 export 暴露出的对象,都在闭包中,所以也就不会对外暴露对象。解决方案:修改webpack配置文件,在 output 配置中加入如下配置library: 'libName', // libName 为对外暴露的库名称 libraryTarget: 'umd' // 定义模块运行的方式,将它的值设为umd参考官方文档:Output | webpack我的博客即将同步至腾讯云开发者社区,邀请大家一同入驻:https://cloud.tencent.com/developer/support-plan?invite_code=24299ll4gdokg
2022年06月26日
406 阅读
0 评论
0 点赞
2022-02-27
express框架下获取用户真实ip地址
1、配置nginx在http,或者 server 或者 location 中加入如下配置proxy_set_header Host $proxy_host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $remote_addr;2、nodejs 获取方法var ip = req.headers['x-real-ip'] || req.connection.remoteAddress;
2022年02月27日
371 阅读
0 评论
0 点赞
1
2
3