首页
统计
友链
关于
Search
1
webRTC与webSocket接入智谱视频通话API避坑指南
402 阅读
2
关于虚拟dom复用导致的组件渲染不一致问题
94 阅读
3
mysql开发规范
91 阅读
4
git操作
77 阅读
5
详谈JavaScript发展史
76 阅读
前端
面试
算法
学习
踩坑日记
登录
Search
标签搜索
git
算法
sql
指针原来是套娃的
累计撰写
24
篇文章
累计收到
0
条评论
首页
栏目
前端
面试
算法
学习
踩坑日记
页面
统计
友链
关于
搜索到
24
篇与
的结果
2026-06-01
一种曲折的uniapp接入第三方sdk方式
uniapp当前痛点采用uniapp框架开发时,很多情况下会收到第三方原生生态的制约,一些第三方的服务可能只有安卓、ios、web的sdk,并不会单独对uniapp开发适配的sdk。如果想要用uts的方式进行接入,需要每个端都写一套适配的代码(安卓、ios或鸿蒙),这样带来的开发成本会很高。而且引入过多的sdk会提高app的内存大小,在云打包时安卓如果超过150MB,每打包一次都要收费。我们的项目就遇到了这样的问题,使用到的第三方服务没有提供uniapp版本的插件,需要手动的接入原生的sdk,非常复杂,而且sdk还有很多类型声明和官方文档上的不一致,成了开发的卡点。通过翻阅uniapp文档,我们发现了一种叫做renderjs的方式,可以在视图层运行的JS。renderjs介绍与使用官方文档:https://uniapp.dcloud.net.cn/tutorial/renderjs.html#renderjsuniapp打包的app,其实是一种桥接技术,将原生能力和webview桥接起来,所以在官方文档的划分中,有逻辑层和视图层两个概念。我们编写的代码都会运行在逻辑层中,通过一种特定的通信来控制视图层,所以这样会有不少的性能损耗,也是代码里不能频繁的更新视图的原因。在逻辑层中,也没有dom相关的元素给我们使用,而视图层不一样。视图层由webview渲染,拥有dom和window,renderjs天然的处于webview环境中,可以直接操作视图dom,毫无通讯损耗。最关键的是它相当于在浏览器环境运行的代码,可以接入第三方的web端sdk,正常的获取dom和window元素,不会像逻辑层的代码一样,抛出各种不兼容。使用renderjs,需要先在template中挂载view标签,并单独写一个script。代码如下:<template> <!-- renderjs数据绑定 --> <view :prop="rtmConfig" :change:prop="agora.handleConfig" style="display: none"></view> </template> <script lang="ts" setup> // 通知renderjs使用RTM加入频道 rtmConfig.value = { userId: 'xxxxxxxx' }; /** * 处理renderjs消息(通过事件总线) */ const handleRenderjsMessage = (message: any) => { console.log('收到renderjs消息:', message); }; onBeforeMount(async () => { // 监听renderjs消息事件(使用事件总线) uni.$on('renderjs-message', handleRenderjsMessage); }); </script> <!-- Vue 2 桥梁:用于 renderjs 调用,可以使用 uni.$emit --> <script lang="ts"> export default { methods: { // renderjs 调用此方法发送消息给 Vue 3 handleRenderjsBridge(data: any) { try { console.log('Vue2桥梁收到消息:', JSON.stringify(data)); // 使用 uni.$emit 发送事件给 Vue 3 uni.$emit('renderjs-message', data); } catch (error) { console.error('Vue2桥梁发送消息失败:', error); } } } }; </script> <script module="agora" lang="renderjs"> export default { data() { return { // #ifdef APP sdkUrl: 'static/js/xxx.js', // #endif // #ifdef H5 sdkUrl: '/static/js/xxx.js', // #endif ownerInstance: null } }, mounted() { console.log('Agora RenderJS mounted - 等待配置'); }, methods: { // 初始化Agora async initAgora() { try { console.log('正在初始化...'); // 动态加载Agora RTM SDK await this.loadAgoraSDK(); console.log('初始化完成'); } catch (error) { console.error('初始化失败:', error); } }, // 动态加载Agora SDK loadAgoraSDK() { return new Promise((resolve, reject) => { console.log('准备加载SDK,路径:', this.sdkUrl); const script = document.createElement('script'); script.src = this.sdkUrl; script.onload = () => { console.log('ASDK加载成功'); resolve(); }; script.onerror = (error) => { console.error('SDK加载失败,错误:', error); console.error('尝试加载的URL:', this.sdkUrl); }; document.head.appendChild(script); }); }, // 处理配置 - 使用uni-app renderjs规范 handleConfig(newValue, oldValue, ownerInstance, instance) { console.log('收到配置信息:', JSON.stringify(newValue)); // 保存ownerInstance供后续使用 this.ownerInstance = ownerInstance; // 配置接收后初始化sdk this.initAgora(); }, // 发送消息给逻辑层 sendMessage(data) { try { console.log('正在发送消息给逻辑层:', JSON.stringify(data)); // 通过 ownerInstance.callMethod 调用 Vue 2 的方法 // Vue 2 方法中可以使用 uni.$emit if (this.ownerInstance && this.ownerInstance.callMethod) { this.ownerInstance.callMethod('handleRenderjsBridge', data); } else { console.warn('ownerInstance.callMethod 不可用'); } } catch (error) { console.error('发送消息失败:', error); } } } } </script>agora可以自定义命名,rtmConfig是正常的逻辑层代码的变量,当rtmConfig绑定的数据发生改变后,会立即通知到agora的handleConfig中,这样我们就实现了逻辑层传递内容到renderjs中,函数有四个参数:newValue: 变化后的新值 oldValue: 变化前的旧值 ownerInstance: 组件实例对象,可以获取逻辑层的函数,ownerInstance.callMethod('handleRenderjsBridge', data); instance: 当前 renderjs 模块所在视图层的实例对象,通过 `instance.$el` 可以直接获取当前绑定的 DOM 元素通过document.createElement('script')挂载js,即可实现加载第三方sdk,当sdk处于本地时,h5与app上路径有些区别,app中路径为'static/js/xxx.js',h5中使用'/static/js/xxx.js'。逻辑层通知renderjs,修改绑定的变量即可,但是renderjs通知给逻辑层就有一些曲折。因为renderjs当前只能支持vue2的代码,不支持调用setup形式中的函数,我们的处理方案是写一层vue2的script作为桥接,vue2与setup的业务逻辑中通过uni.$emit全局通讯的方式传递。这里有一个踩坑点需要注意:renderJs需要写在页面级别文件中,不能放在组件里嵌套,绑定的dom元素也需要在页面级别,不能嵌套,不然会报错Mt.setAttribute is not a function。当时排查了很久,发现从组件改到页面级文件就可以了。使用效果我们使用这套方案接入了声网RTM的sdk和国外的Stripe支付sdk,减少了很多的开发工作。在后续处理一个视频需求时,发现插件市场也有同样思路处理的视频组件,使用体验非常好,避免了很多原生video的问题:https://ext.dcloud.net.cn/plugin?id=19654以上。
2026年06月01日
2 阅读
0 评论
0 点赞
2026-05-29
微信支付sdk回调问题
正常的app内购流程如下:请求后端获取订单号 ➞ 调用微信sdk发起支付 ➞ 得到微信支付成功回调 ➞ 上报后端进行校验 ➞ 一次支付完成但是在微信支付的sdk中有一个非常奇怪的行为,如果用户完成支付后不点击微信页面的“返回商家”按钮,sdk不会回调通知给客户端,导致客户端获取的状态不正确。经百度查阅资料,这种行为在2017年社区中就有人提出了,但是微信方面始终没有修复。如果客户端想要正常的处理支付成功后的逻辑,需要和后端保持沟通,从服务端获取正确的支付状态。
2026年05月29日
1 阅读
0 评论
0 点赞
2025-03-26
手写系列一:实现防抖节流
防抖和节流的区别 防抖是在指定时间内只执行一次,如果 再次触发则重新计时 ,即只处理 最后一次响应 。 节流是在指定时间内只执行一次,如果再次触发则不执行,也就是 只执行第一次,后面的触发不管,等到时间过去才再响应一次触发。 防抖常用在输入框搜索、滚动加载、表单提交等高频触发只用处理最后一次响应的地方。 节流常用在滚动监听、窗口变化等,在高频的变化中一段时间内只响应第一次变化,并给出多个中间态,以实现 平滑 的变化。手写实现防抖/** * 防抖在是指定时间内只执行一次,如果再次触发则重新计时 * 一段时间内只处理最后一次事件响应 * 定时器实现 */ 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);效果:
2025年03月26日
18 阅读
0 评论
2 点赞
2025-03-21
webpack学习笔记
一、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在线测试工具:https://astexplorer.net/3、产生chunk assets在第二步完成后,chunk中会产生一个模块列表,列表中包含了模块id和模块转换后的代码接下来,webpack会根据配置为chunk生成一个资源列表,即chunk assets,资源列表可以理解为是生成到最终文件的文件名和文件内容4、合并chunk assets将多个chunk的assets合并到一起,并产生一个总的hash输出webpack将利用node中的fs模块,根据编译产生的总的assets,生成相应的文件。涉及术语module:模块,分割的代码单元,webpack中的模块可以是任何内容的文件,不仅限于JSchunk:webpack内部构建模块的块,一个chunk中包含多个模块,这些模块是从入口模块通过依赖分析得来的bundle:chunk构建好模块后会生成chunk的资源清单,清单中的每一项就是一个bundle,可以认为bundle就是最终生成的文件hash:最终的资源清单所有内容联合生成的hash值chunkhash:chunk生成的资源清单内容联合生成的hash值chunkname:chunk的名称,如果没有配置则使用mainid:通常指chunk的唯一编号,如果在开发环境下构建,和chunkname相同;如果是生产环境下构建,则使用一个从0开始的数字进行编号三、loaderloader处理在读取到文件内容之后,发生在AST抽象语法树之前。loader的功能定位是转换代码,因为webpack只能对js代码进行抽象语法树分析,所以需要在loader阶段引入对图片、css等处理成js代码。也可以对源代码进行修改,如babel-loader等。loader执行顺序是从下到上、从右到左,上一个loader处理后再交给下一个loader。常用的loader// 使用 postcss 处理 css https://postcss.org/ postcss-loader // 解析 CSS 文件中的 import 和 url() css-loader // 将 CSS 插入到 DOM 中 style-loader // css 样式打包成一个文件 // 该 loader 负责记录要生成的 css 文件的内容 // 同时导出开启 css-module 后的样式对象 mini-css-extract-plugin.loader // 各种图片、字体文件,均交给 url-loader 处理 url-loader // 转换js代码,用于适配各版本浏览器 https://www.babeljs.cn/ babel-loader四、pluginplugin的本质是一个带有apply方法的对象,嵌入到webpack的编译流程中的节点进行处理。执行顺序看节点,同节点的按配置中从上到下、从左到右。apply函数会在初始化阶段,创建好Compiler对象后运行。compiler对象是在初始化阶段构建的,整个webpack打包期间只有一个compiler对象,后续完成打包工作的是compiler对象内部创建的compilation。apply方法会在创建好compiler对象后调用,并向方法传入一个compiler对象compiler对象提供了大量的钩子函数(hooks,可以理解为事件),plugin的开发者可以注册这些钩子函数,参与webpack编译和生成。class MyPlugin{ apply(compiler){ compiler.hooks.事件名称.事件类型(name, function(compilation){ //事件处理函数 }) } }事件名称即要监听的事件名,即钩子名,所有的钩子:https://www.webpackjs.com/api/compiler-hooks事件类型这一部分使用的是 Tapable API,这个小型的库是一个专门用于钩子函数监听的库。它提供了一些事件类型:tap:注册一个同步的钩子函数,函数运行完毕则表示事件处理结束tapAsync:注册一个基于回调的异步的钩子函数,函数通过调用一个回调表示事件处理结束tapPromise:注册一个基于Promise的异步的钩子函数,函数通过返回的Promise进入已决状态表示事件处理结束处理函数处理函数有一个事件参数compilation。常用的plugin// 清除输出目录文件 clean-webpack-plugin // 自动生成html文件 并引入打包后的js html-webpack-plugin // 复制静态资源到输出目录 copy-webpack-plugin // 将css文件打包成一个文件 // 和mini-css-extract-plugin.loader合用 mini-css-extract-pluginwebpack内置插件// 全局常量定义插件,使用该插件通常定义一些常量值 DefinePlugin // 可以为每个chunk生成的文件头部添加一行注释 // 一般用于添加作者、公司、版权等信息 BannerPlugin // 自动加载模块,不用手动import 或 require // 写法 /* new webpack.ProvidePlugin({ $: 'jquery', _: 'lodash' }) */ ProvidePlugin五、性能优化性能优化可以从三个方向入手构建性能传输性能运行性能构建性能这里所说的构建性能,是指在开发阶段的构建性能,降低从打包开始,到代码效果呈现所经过的时间。1、减少模块解析配置module.noParse,对第三方或打包好的模块不进行解析。2、优化loader性能有一些库不用经过特定的loader解析,如配置exclude: /lodash/,在使用babel-loader时不解析lodash库。module.exports = { module: { rules: [ { test: /\.js$/, exclude: /lodash/, use: "babel-loader" } ] } }3、开启热替换默认情况下,webpack-dev-server不管是否开启了热更新,当重新打包后,都会调用location.reload刷新页面。但如果运行了module.hot.accept(),将改变这一行为。module.hot.accept()的作用是让webpack-dev-server通过socket管道,把服务器更新的内容发送到浏览器。浏览器将不在刷新重新请求整个模块,而是只请求发送变化的模块。devServer:{ hot:true // 开启HMR } // 并在js中加入下面代码 if(module.hot){ // 是否开启了热更新 module.hot.accept() // 接受热更新 }传输性能传输性能是指,打包后的JS代码传输到浏览器经过的时间。在优化传输性能时要考虑到:总传输量:所有需要传输的JS文件的内容加起来,就是总传输量,重复代码越少,总传输量越少。文件数量:当访问页面时,需要传输的JS文件数量,文件数量越多,http请求越多,响应速度越慢。浏览器缓存:JS文件会被浏览器缓存,被缓存的文件不会再进行传输。1、手动分包将不依赖其他模块的文件打包成公共模块,公共模块会被打包成为动态链接库(dll Dynamic Link Library),并生成资源清单。后续打包时webpack分析到引用的模块在资源清单中,就不会打包该模块。打包公共模块是一个独立的打包过程,在打包时利用DllPlugin生成资源清单。module.exports = { mode: "production", entry: { jquery: ["jquery"], lodash: ["lodash"] }, output: { filename: "dll/[name].js", library: "[name]" // 每个bundle暴露的全局变量名 }, plugins: [ new webpack.DllPlugin({ // 这里不参与打包后的代码运行,不用放到输出目录中 path: path.resolve(__dirname, "dll", "[name].manifest.json"), name: "[name]" }) ] };打包完成后,需要在页面手动引入公共模块的js文件。并在主代码打包时引入打包好的资源清单new webpack.DllReferencePlugin({ manifest: require("./dll/jquery.manifest.json") }), new webpack.DllReferencePlugin({ manifest: require("./dll/lodash.manifest.json") })手动打包的过程: 1. 开启`output.library`暴露公共模块 2. 用`DllPlugin`创建资源清单 3. 用`DllReferencePlugin`使用资源清单 手动打包的注意事项: 1. 资源清单不参与运行,可以不放到打包目录中 2. 记得手动引入公共JS,以及避免被删除 3. 不要对小型的公共JS库使用 优点: 1. 极大提升自身模块的打包速度 2. 极大的缩小了自身文件体积 3. 有利于浏览器缓存第三方库的公共代码 缺点: 1. 使用非常繁琐 2. 如果第三方库中包含重复代码,则效果不太理想2、自动分包配置webpack分包策略,webpack可以根据分包策略自动进行分包。webpack提供了optimization配置项,用于配置一些优化信息,其中splitChunks是分包策略的配置。module.exports = { optimization: { splitChunks: { // 分包策略 chunks: "all" } } }chunks:从chunk中分离chunk,实现分包。all: 对于所有的chunk都要应用分包策略async:【默认】仅针对异步chunk应用分包策略initial:仅针对普通chunk应用分包策略maxSize:控制包的最大字节数,超过后尽可能分包(因为分包是按模块划分,单一模块超过字节后无法再分)minChunks:一个模块被多少个chunk使用时,才会进行分包,默认值1缓存组配置之前配置的分包策略是全局的,而实际上,分包策略是基于缓存组的。每个缓存组提供一套独有的策略,webpack按照缓存组的优先级依次处理每个缓存组,被缓存组处理过的分包不需要再次分包。默认情况下,webpack提供了两个缓存组:module.exports = { optimization:{ splitChunks: { //全局配置 cacheGroups: { // 属性名是缓存组名称,会影响到分包的chunk名 // 属性值是缓存组的配置,缓存组继承所有的全局配置,也有自己特殊的配置 vendors: { // 当匹配到相应模块时,将这些模块进行单独打包 test: /[\\/]node_modules[\\/]/, // 缓存组优先级,优先级越高,该策略越先进行处理,默认值为0 priority: -10 }, default: { // 覆盖全局配置,将最小chunk引用数改为2 minChunks: 2, // 优先级 priority: -20, // 重用已经被分离出去的chunk reuseExistingChunk: true } } } } }修改缓存组以实现css公共样式抽离module.exports = { optimization: { splitChunks: { chunks: "all", cacheGroups: { styles: { test: /\.css$/, // 匹配样式模块 minSize: 0, // 覆盖默认的最小尺寸,这里仅仅是作为测试 minChunks: 2 // 覆盖默认的最小chunk引用数 } } } }, module: { rules: [{ test: /\.css$/, use: [MiniCssExtractPlugin.loader, "css-loader"] }] }, plugins: [ new CleanWebpackPlugin(), new HtmlWebpackPlugin({ template: "./public/index.html", chunks: ["index"] }), new MiniCssExtractPlugin({ filename: "[name].[hash:5].css", // chunkFilename是配置来自于分割chunk的文件名 chunkFilename: "common.[hash:5].css" }) ] }这两种分包方法所能分的最小包还是一个模块的大小,下面使用代码压缩和tree shaking将会减少模块的体积。3、代码压缩webpack自动集成了Terser https://terser.org/,可以减少代码体积;破坏代码的可读性,提升破解成本。用法:const TerserPlugin = require('terser-webpack-plugin'); const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin'); module.exports = { optimization: { // 是否要启用压缩,默认情况下,生产环境会自动开启 minimize: true, minimizer: [ // 压缩时使用的插件,可以有多个 new TerserPlugin(), new OptimizeCSSAssetsPlugin() ], }, };4、tree shakingtree shaking可以通过分析模块间的依赖关系,自动去除没有用到的模块内容,从而大大减少了打包体积。但是tree shaking的模块分析依赖es6的模块分析,es的import绑定的变量是不可变的,更加稳定,所以在使用第三方库时,需要选择es6版本,如lodash-es。同时,在书写导入语句时,尽量分块导出、按需导入。使用export xxx导出,而不使用export default {xxx}导出使用import {xxx} from "xxx"导入,而不使用import xxx from "xxx"导入webpack2开始内置了tree shaking,在打包生产环境中会自动开启。5、懒加载使用import()动态引入一个模块,webpack会将模块打包成异步包,等到运行该语句时动态加载js。/* webpackChunkName:"lodash" */是修改包的名字。btn.onclick = async function() { //动态加载 //import 是ES6的草案 //浏览器会使用JSOP的方式远程去读取一个js模块 //import()会返回一个promise (* as obj) // const { chunk } = await import(/* webpackChunkName:"lodash" */"lodash-es"); const result = chunk([3, 5, 6, 7, 87], 2); console.log(result); }; 其它优化1、ESlint使用ESLint可以检查代码格式与质量,在开发阶段编写优雅的代码。2、bundle analyzerbundle-analyzer可以分析打包结果,生成图形化的界面。
2025年03月21日
22 阅读
0 评论
5 点赞
2025-03-21
vscode插件
因为换了几台电脑,每次都要重新安装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 = ` <script> function setCurrent(){ const links = document.querySelectorAll(".md-sidebar-toc a") for(const link of links){ link.style.color=""; } const hash = location.hash; const a = document.querySelector('a[href="'+hash+'"]'); if(a){ a.style.color = "#f40"; } } setCurrent(); window.onhashchange = setCurrent; </script> `; 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 ` <p class="markdown-p-center"> <img src="${g2}" alt="${g1}" style="max-width:${width}"/> </p> <p class="markdown-img-description"> ${g1} </p> `; }); resolve(markdown); }); }, onDidParseMarkdown: function(html) { return new Promise((resolve, reject) => { return resolve(scripts + html); }); } };
2025年03月21日
45 阅读
0 评论
1 点赞
1
2
...
5