├── .gitignore ├── .vscode └── settings.json ├── README.html ├── README.md ├── bugfix脚本 ├── config.js ├── index.js ├── package.json └── yarn.lock ├── filterApiResultToFile ├── README.md ├── code.js ├── data.json ├── index.js ├── package-lock.json ├── package.json └── src │ ├── api.js │ └── utils.js ├── h5网页唤醒app ├── demo.html └── openApp.js ├── more-article.png ├── node搭建消息推送 └── send-wx-message │ ├── .gitignore │ ├── README.md │ ├── app.js │ ├── bin │ └── www │ ├── cloudbaserc.json │ ├── models │ └── wxApi.js │ ├── package.json │ ├── public │ ├── js │ │ └── index.js │ └── stylesheets │ │ └── style.css │ ├── routes │ ├── index.js │ └── users.js │ ├── utils │ └── wxConfig.js │ ├── views │ ├── error.jade │ ├── index.jade │ └── layout.jade │ └── yarn.lock ├── node服务解决跨域 ├── dist │ ├── css │ │ ├── app.e20425ad.css │ │ └── chunk-vendors.0c51a37b.css │ ├── favicon.ico │ ├── img │ │ └── logo.82b9c7a5.png │ ├── index.html │ └── js │ │ ├── app.d7538b2e.js │ │ └── chunk-vendors.769a78f6.js ├── index.js ├── package.json └── yarn.lock ├── object和map的性能比较 └── index.html ├── package.json ├── puppeteer截图 ├── README.md ├── package-lock.json ├── package.json ├── src │ ├── index.js │ ├── puppeteer.js │ ├── puppeteerByPool.js │ └── route.js ├── test.html └── yarn.lock ├── qr.png ├── yuwuwu-cli ├── README.md ├── bin │ └── index.js ├── lib │ ├── create.js │ ├── createNodeTemplate.js │ ├── nodeTemplate │ │ ├── index.ejs │ │ └── package.ejs │ └── questions.js ├── package-lock.json ├── package.json └── yarn.lock ├── 串行异步操作 └── index.js ├── 查询佳能是否补货脚本 ├── README.md ├── index_tb.js ├── index_wx.js ├── package-lock.json ├── package.json └── src │ ├── filterResult │ ├── getGoodsInfoBySku.js │ ├── index.js │ └── 处理后的数据.json │ ├── getGoodsByTb.js │ ├── getGoodsByWx.js │ ├── request.js │ ├── sendEmail.js │ └── utils.js ├── 离线缓存Server Worker ├── demo.html ├── favicon.ico ├── img │ └── t.jpeg ├── js │ └── jqurey.js └── sw.js ├── 红包雨 ├── images │ ├── bg.png │ ├── red.png │ └── s-bg.png ├── index.html └── js │ ├── RedPacketGame.js │ ├── rem.js │ ├── requestAnimationFrame.js │ ├── setRaf.js │ └── utils.js ├── 自动签到脚本 ├── index.js ├── package-lock.json ├── package.json └── yarn.lock ├── 运动轨迹 ├── canvas-game.html └── test.html ├── 骨架屏1-简单的骨架屏方案 ├── img.jpg ├── index-css.html ├── index-img.html └── index.css └── 骨架屏2-自动生成页面骨架 ├── getDom.js ├── img.jpg ├── index.css └── index.html /.gitignore: -------------------------------------------------------------------------------- 1 | # Build and Release Folders 2 | bin-debug/ 3 | bin-release/ 4 | [Oo]bj/ 5 | 6 | # Other files and folders 7 | .settings/ 8 | 9 | # Executables 10 | *.swf 11 | *.air 12 | *.ipa 13 | *.apk 14 | node_modules 15 | test 16 | project.config.js 17 | mail.config.js 18 | # Project files, i.e. `.project`, `.actionScriptProperties` and `.flexProperties` 19 | # should NOT be excluded as they contain compiler settings and other important 20 | # information for Eclipse / Flash Builder. 21 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "files.exclude": { 3 | "**/node_modules/": true 4 | }, 5 | "editor.tabSize": 2, // Tab 的大小 2个空格 6 | "editor.formatOnSave": true, // 保存是格式化 7 | "eslint.codeActionsOnSave.mode": "all", 8 | "prettier.singleQuote": true, // 单引号 9 | "editor.defaultFormatter": "esbenp.prettier-vscode", 10 | "[vue,typescript,javascript]": { 11 | "editor.defaultFormatter": "esbenp.prettier-vscode" 12 | }, 13 | "[json]": { 14 | "editor.defaultFormatter": "vscode.json-language-features" 15 | }, 16 | "editor.codeActionsOnSave": { 17 | "source.fixAll.eslint": "explicit" 18 | }, 19 | "eslint.enable": true, 20 | "eslint.trace.server": "verbose", 21 | "eslint.format.enable": true, 22 | "eslint.lintTask.enable": true, 23 | "eslint.validate": [ 24 | "javascript", 25 | "javascriptreact", 26 | "vue", 27 | "typescriptreact" 28 | ], 29 | "[vue]": { 30 | "editor.defaultFormatter": "esbenp.prettier-vscode" 31 | }, 32 | "vue3snippets.enable-compile-vue-file-on-did-save-code": false, 33 | "files.watcherExclude": { 34 | "**/.git/objects/**": true, 35 | "**/.git/subtree-cache/**": true, 36 | "**/node_modules/**": true, 37 | "**/tmp/**": true, 38 | "**/bower_components/**": true, 39 | "**/dist/**": true 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /README.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 文章目录 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 128 | 129 | 130 | 131 | 207 | 208 | 209 | 228 | 229 | 230 | 237 | 238 |

研究研究js

239 | 245 |

小程序开发

246 | 250 |

node相关

251 | 262 |

项目优化、总结

263 | 298 |

其他

299 | 303 | 304 |
305 | 作者:于五五
306 | 我的主页:https://juejin.cn/user/1433418892058333
307 | GitHub:https://github.com/yuwuwu
308 | wx:yyx895 309 |
310 | 311 | 312 | 313 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 8 | # Blog-code(去写作,让自己学习更多知识) 9 | > 代码支持文章,为写过的文章提供代码支持。 10 | 11 | ## 研究研究js 12 | 13 | - 文章[《 ES6 》](https://juejin.cn/post/6920896651724849166) 14 | - 文章[《 JS面向对象 》](https://juejin.cn/post/6942412781299695623) 15 | - 文章[《 串行异步操作 》](https://juejin.cn/post/7043340637961191455)| [查看代码](https://github.com/yuwuwu/markdown-code/tree/master/%E4%B8%B2%E8%A1%8C%E5%BC%82%E6%AD%A5%E6%93%8D%E4%BD%9C) 16 | - 文章[《 object和map性能比较 》](https://juejin.cn/post/6992874755070099492)| [查看代码](https://github.com/yuwuwu/markdown-code/tree/master/object%E5%92%8Cmap%E7%9A%84%E6%80%A7%E8%83%BD%E6%AF%94%E8%BE%83) 17 | 18 | 19 | ## 小程序开发 20 | - 文章[《 微信小程序使用canvas生成海报 》](https://juejin.cn/post/6996977491873103909) 21 | - 文章[《 微信小程序canvas实现电子签名 》](https://juejin.cn/post/7000633542153601055) 22 | ## node相关 23 | 24 | - 文章[《 node解决开发环境下跨域问题 》](https://juejin.cn/post/7001894700596592653)| [查看代码](https://github.com/yuwuwu/markdown-code/tree/master/node%E6%9C%8D%E5%8A%A1%E8%A7%A3%E5%86%B3%E8%B7%A8%E5%9F%9F) 25 | 26 | - 文章[《 解放cv键 实现一个cli工具 》](https://juejin.cn/post/7078337031167803406)| [查看代码](https://github.com/yuwuwu/markdown-code/tree/master/yuwuwu-cli) 27 | 28 | - 文章[《 云开发+测试公众号搭建微信消息推送平台 》](https://juejin.cn/post/7089314780804022280)| [查看代码](https://github.com/yuwuwu/blog-code/tree/master/node%E6%90%AD%E5%BB%BA%E6%B6%88%E6%81%AF%E6%8E%A8%E9%80%81/send-wx-message) 29 | 30 | ## 项目优化、总结 31 | 32 | - 文章[《 骨架屏方案--(一)简单的骨架屏方案 》](https://juejin.cn/post/7028590020176904199)| [查看代码](https://github.com/yuwuwu/markdown-code/tree/master/%E9%AA%A8%E6%9E%B6%E5%B1%8F1-%E7%AE%80%E5%8D%95%E7%9A%84%E9%AA%A8%E6%9E%B6%E5%B1%8F%E6%96%B9%E6%A1%88) 33 | - 文章[《 骨架屏方案--(二)自动生成骨架屏代码 》](https://juejin.cn/post/7031330990500872199)| [查看代码](https://github.com/yuwuwu/markdown-code/tree/master/%E9%AA%A8%E6%9E%B6%E5%B1%8F2-%E8%87%AA%E5%8A%A8%E7%94%9F%E6%88%90%E9%A1%B5%E9%9D%A2%E9%AA%A8%E6%9E%B6) 34 | 35 | - 文章[《 关于我使用了html2canvas差点提桶跑路这件事 》](https://juejin.cn/post/7044178791878361118) 36 | 37 | - 文章[《 node+puppeteer生成海报 》](https://juejin.cn/post/7053990336820936712) | [查看代码](https://github.com/yuwuwu/markdown-code/tree/master/puppeteer%E6%88%AA%E5%9B%BE) 38 | - 文章[《 uniapp多环境配置 》](https://juejin.cn/post/6992116181343666213) 39 | - 文章[《 vue2性能优化之Object.freeze()测试 》](https://juejin.cn/post/6995500451407855623) 40 | - 文章[《 离线缓存Server Worker 》](https://juejin.cn/post/7002573409565540383) | [查看代码](https://github.com/yuwuwu/markdown-code/tree/master/%E7%A6%BB%E7%BA%BF%E7%BC%93%E5%AD%98Server%20Worker) 41 | 42 | - 文章[《 6年前端开发整理出的日常开发中碰到的兼容适配问题 》](https://juejin.cn/post/7089822034502352904) 43 | - 文章[《 6年前端经验整理出的日常开发中js工具方法 》](https://juejin.cn/post/7091309001471852580) 44 | - 文章[《 h5网页唤醒app的方案 》](https://juejin.cn/post/7091673168921755656) | [查看代码](https://github.com/yuwuwu/blog-code/tree/master/h5%E7%BD%91%E9%A1%B5%E5%94%A4%E9%86%92app) 45 | 46 | 47 | ## 其他 48 | - 文章[《 白嫖云函数 【腾讯云函数+掘金签到脚本】 》](https://juejin.cn/post/7070521315236511781) | [查看代码](https://github.com/yuwuwu/markdown-code/tree/master/%E8%87%AA%E5%8A%A8%E7%AD%BE%E5%88%B0%E8%84%9A%E6%9C%AC) 49 | - 文章[《 白嫖云函数 【收集bugfix】 》](https://juejin.cn/post/7086848550277120014) | [查看代码](https://github.com/yuwuwu/markdown-code/tree/master/bugfix%E8%84%9A%E6%9C%AC) 50 | ## 最后 51 | 都看到这里了,可以帮忙点个star吗?( ̄▽ ̄)~* -------------------------------------------------------------------------------- /bugfix脚本/config.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: yuyongxing 3 | * @Date: 2022-02-25 16:15:28 4 | * @LastEditors: yuyongxing 5 | * @LastEditTime: 2022-04-15 22:49:51 6 | * @Description: 邮箱动态项 7 | */ 8 | module.exports = { 9 | SendKey:'you sendkey', 10 | users: [ 11 | { 12 | aid: "you aid", 13 | uuid:"you uuid", 14 | cookie: `you cookie`,//使用字符串模板,防止cookie里有引号导致标签闭合问题 15 | } 16 | ] 17 | 18 | } -------------------------------------------------------------------------------- /bugfix脚本/index.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: yuyongxing 3 | * @Date: 2022-04-02 11:11:27 4 | * @LastEditors: yuyongxing 5 | * @LastEditTime: 2022-04-15 22:55:54 6 | * @Description: 7 | */ 8 | 9 | const axios = require('axios'); 10 | const { SendKey, users } = require('./config.js') 11 | 12 | 13 | 14 | /** 15 | * @Author: yuyongxing 16 | * @param {*} aid 17 | * @param {*} uuid 18 | * @param {*} cookie 19 | * @return {*} data 20 | * @Date: 2022-04-15 22:52:34 21 | * @LastEditors: yuyongxing 22 | * @LastEditTime: Do not edit 23 | * @Description: 查询用户可收集bug数 24 | */ 25 | const getBugList = async (aid, uuid, cookie) => { 26 | let { data } = await axios({ 27 | url: `https://api.juejin.cn/user_api/v1/bugfix/not_collect?aid=${aid}&uuid=${uuid}`, 28 | method: 'post', 29 | headers: { Cookie: cookie } 30 | }) 31 | return data 32 | } 33 | 34 | /** 35 | * @Author: yuyongxing 36 | * @param {*} aid 37 | * @param {*} uuid 38 | * @param {*} cookie 39 | * @param {*} params 40 | * @return {*}data 41 | * @Date: 2022-04-15 22:53:01 42 | * @LastEditors: yuyongxing 43 | * @LastEditTime: Do not edit 44 | * @Description: 收集bug 45 | */ 46 | const collectBug = async (aid, uuid, cookie, params) => { 47 | let { data } = await axios({ 48 | url: `https://api.juejin.cn/user_api/v1/bugfix/collect?aid=${aid}&uuid=${uuid}`, 49 | method: 'post', 50 | data: params, 51 | headers: { Cookie: cookie } 52 | }) 53 | return data 54 | } 55 | 56 | /** 57 | * @Author: yuyongxing 58 | * @param {*} aid 59 | * @param {*} uuid 60 | * @param {*} cookie 61 | * @return {*} data 62 | * @Date: 2022-04-15 22:53:16 63 | * @LastEditors: yuyongxing 64 | * @LastEditTime: Do not edit 65 | * @Description: 获取活动详情 66 | */ 67 | const getBugFixGameInfo = async (aid, uuid, cookie) => { 68 | let { data } = await axios({ 69 | url: `https://api.juejin.cn/user_api/v1/bugfix/competition?aid=${aid}&uuid=${uuid}`, 70 | method: 'post', 71 | headers: { Cookie: cookie } 72 | }) 73 | return data 74 | } 75 | 76 | /** 77 | * @Author: yuyongxing 78 | * @param {*} aid 79 | * @param {*} uuid 80 | * @param {*} cookie 81 | * @param {*} params 82 | * @return {*} data 83 | * @Date: 2022-04-15 22:53:32 84 | * @LastEditors: yuyongxing 85 | * @LastEditTime: Do not edit 86 | * @Description: 获取活动用户详情:可用Bug数量 87 | */ 88 | const getBugFixGameUserInfo = async (aid, uuid, cookie, params) => { 89 | let { data } = await axios({ 90 | url: `https://api.juejin.cn/user_api/v1/bugfix/user?aid=${aid}&uuid=${uuid}`, 91 | method: 'post', 92 | data: params, 93 | headers: { Cookie: cookie } 94 | }) 95 | return data 96 | } 97 | 98 | /** 99 | * @Author: yuyongxing 100 | * @param {*} aid 101 | * @param {*} uuid 102 | * @param {*} cookie 103 | * @param {*} params 104 | * @return {*} data 105 | * @Date: 2022-04-15 22:53:49 106 | * @LastEditors: yuyongxing 107 | * @LastEditTime: Do not edit 108 | * @Description: 参与活动 109 | */ 110 | const bugFix = async (aid, uuid, cookie, params) => { 111 | let { data } = await axios({ 112 | url: `https://api.juejin.cn/user_api/v1/bugfix/fix?aid=${aid}&uuid=${uuid}`, 113 | method: 'post', 114 | data: params, 115 | headers: { Cookie: cookie } 116 | }) 117 | return data 118 | } 119 | 120 | /** 121 | * @Author: yuyongxing 122 | * @param {*} title 123 | * @param {*} desp 124 | * @return {*} data 125 | * @Date: 2022-04-15 22:54:07 126 | * @LastEditors: yuyongxing 127 | * @LastEditTime: Do not edit 128 | * @Description: 微信推送 129 | */ 130 | const sendWxMessage = async (title, desp) => { 131 | title = encodeURIComponent(title) 132 | desp = encodeURIComponent(desp) 133 | let { data } = await axios({ 134 | url: `https://sctapi.ftqq.com/${SendKey}.send?title=${title}&desp=${desp}`, 135 | method: 'post' 136 | }) 137 | return data 138 | } 139 | 140 | /** 141 | * @Author: yuyongxing 142 | * @param {*} aid 143 | * @param {*} uuid 144 | * @param {*} cookie 145 | * @param {*} bugList 146 | * @return {*} {err_no: err_no,err_msg: err_msg} 147 | * @Date: 2022-04-15 22:51:23 148 | * @LastEditors: yuyongxing 149 | * @LastEditTime: Do not edit 150 | * @Description: 根据列表收取Bug 151 | */ 152 | const collectBugByList = async (aid, uuid, cookie, bugList) => { 153 | let err_msg = "" 154 | let err_no = 0 155 | for (let j = 0; j < bugList.length; j++) { 156 | const params = { 157 | bug_time: bugList[j].bug_time, 158 | bug_type: bugList[j].bug_type 159 | } 160 | let res_collectBug = await collectBug(aid, uuid, cookie, params) 161 | if (res_collectBug.err_no != 0) { 162 | err_no = 1001 163 | err_msg += `${res_collectBug.err_msg}; ` 164 | } 165 | } 166 | return { 167 | err_no: err_no, 168 | err_msg: err_msg 169 | } 170 | } 171 | 172 | /** 173 | * @Author: yuyongxing 174 | * @param {*} aid 175 | * @param {*} uuid 176 | * @param {*} cookie 177 | * @return {*} 178 | * @Date: 2022-04-15 22:54:24 179 | * @LastEditors: yuyongxing 180 | * @LastEditTime: Do not edit 181 | * @Description: 参与游戏 182 | */ 183 | const joinBugFix = async (aid, uuid, cookie) => { 184 | let msg = "" 185 | const res_bugFixGameInfo = await getBugFixGameInfo(aid, uuid, cookie) 186 | msg = res_bugFixGameInfo.err_msg 187 | if (res_bugFixGameInfo.err_no == 0 && res_bugFixGameInfo.data.award_status == 1) { 188 | // 活动进行中 189 | const res_bugFixGameUserInfo = await getBugFixGameUserInfo(aid, uuid, cookie, { competition_id: res_bugFixGameInfo.data.competition_id }) 190 | // 用户已参与的bug数:bug_fix_num 191 | // 用户剩余的bug数:user_own_bug 192 | const bug_fix_num = res_bugFixGameUserInfo.data.bug_fix_num 193 | const user_own_bug = res_bugFixGameUserInfo.data.user_own_bug 194 | if (bug_fix_num < 10 && user_own_bug >= 10) { 195 | const res_bugFix = await bugFix(aid, uuid, cookie, { competition_id: res_bugFixGameInfo.data.competition_id }) 196 | if (res_bugFix.err_no == 0) { 197 | return { 198 | err_no: 0, 199 | err_msg: res_bugFixGameInfo.data.competition_name 200 | } 201 | } 202 | msg = res_bugFix.err_msg 203 | } 204 | 205 | } else if (res_bugFixGameInfo.err_no == 0 && res_bugFixGameInfo.data.award_status == 0) { 206 | msg = "活动已结束" 207 | } 208 | return { 209 | err_no: 1001, 210 | err_msg: msg 211 | } 212 | } 213 | 214 | 215 | /** 216 | * @Author: yuyongxing 217 | * @param {*} 218 | * @return {*} 219 | * @Date: 2022-04-15 22:54:39 220 | * @LastEditors: yuyongxing 221 | * @LastEditTime: Do not edit 222 | * @Description: 主函数 223 | */ 224 | const bugFix_start = async () => { 225 | for (let i = 0, len = users.length; i < len; i++) { 226 | let title = 'bugfix成功' 227 | let desp = '' 228 | const user = users[i] 229 | // 查询bug数量 230 | const res_bugList = await getBugList(user.aid, user.uuid, user.cookie) 231 | if (res_bugList.err_no == 0) { 232 | // 收集bug 233 | const res_collectBugByList = await collectBugByList(user.aid, user.uuid, user.cookie, res_bugList.data) 234 | if (res_collectBugByList.err_no == 0) { 235 | desp = `收集${res_bugList.data.length}个bug成功;` 236 | } else { 237 | title = 'bugfix失败' 238 | desp = res_collectBugByList.err_msg 239 | } 240 | } 241 | // 参与活动 242 | const res_joinBugFix = await joinBugFix(user.aid, user.uuid, user.cookie) 243 | if (res_joinBugFix.err_no == 0) { 244 | desp += res_joinBugFix.err_msg + "参与成功" 245 | } else { 246 | desp += "参与失败:" + res_joinBugFix.err_msg 247 | } 248 | await sendWxMessage(title, desp) 249 | } 250 | } 251 | exports.bugFix_start = bugFix_start -------------------------------------------------------------------------------- /bugfix脚本/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "bug_fix", 3 | "version": "1.0.0", 4 | "description": "bug_fix脚本", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "author": "", 10 | "license": "ISC", 11 | "dependencies": { 12 | "axios": "^0.21.4" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /bugfix脚本/yarn.lock: -------------------------------------------------------------------------------- 1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 | # yarn lockfile v1 3 | 4 | 5 | axios@^0.21.4: 6 | version "0.21.4" 7 | resolved "https://registry.yarnpkg.com/axios/-/axios-0.21.4.tgz#c67b90dc0568e5c1cf2b0b858c43ba28e2eda575" 8 | integrity sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg== 9 | dependencies: 10 | follow-redirects "^1.14.0" 11 | 12 | follow-redirects@^1.14.0: 13 | version "1.14.9" 14 | resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.14.9.tgz#dd4ea157de7bfaf9ea9b3fbd85aa16951f78d8d7" 15 | integrity sha512-MQDfihBQYMcyy5dhRDJUHcw7lb2Pv/TuE6xP1vyraLukNDHKbDxDNaOE3NbCAdKQApno+GPRyo1YAp89yCjK4w== 16 | -------------------------------------------------------------------------------- /filterApiResultToFile/README.md: -------------------------------------------------------------------------------- 1 | 9 | 10 | # getApiInfoToFile 11 | 12 | ## 介绍 13 | 14 | 获取一些 api 的接口返回信息,并将其保存到文件中,方便其他人也能查看。 15 | E41835V14R r50 6yue18 -------------------------------------------------------------------------------- /filterApiResultToFile/code.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: yuwuwu 3 | * @Date: 2024-07-31 20:01:53 4 | * @LastEditors: yuwuwu 5 | * @LastEditTime: 2024-07-31 22:41:42 6 | * @FilePath: /markdown-code/getApiInfoToFile/code.js 7 | * @Description: 8 | */ 9 | const { checkCode } = require('./src/api'); 10 | const { generateRandomString } = require('./src/utils'); 11 | 12 | const run = async () => { 13 | const code = generateRandomString(); 14 | const res = await checkCode(code); 15 | if (res.code != 1003) { 16 | console.log(res, code); 17 | } 18 | // console.log(res, code); 19 | return res; 20 | }; 21 | let count = 0; 22 | const timer = setInterval(() => { 23 | count++; 24 | try { 25 | run(); 26 | if (count >= 10000) { 27 | console.log('done'); 28 | clearInterval(timer); 29 | } 30 | } catch (error) { 31 | console.log('error', error); 32 | clearInterval(timer); 33 | } 34 | }, 100); 35 | -------------------------------------------------------------------------------- /filterApiResultToFile/index.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: yuwuwu 3 | * @Date: 2024-06-28 13:36:37 4 | * @LastEditors: yuwuwu 5 | * @LastEditTime: 2024-07-31 18:39:06 6 | * @FilePath: /markdown-code/getApiInfoToFile/index.js 7 | * @Description: 8 | */ 9 | const { getGoodsBySku } = require('./src/api'); 10 | const { writeToFile, waitTime } = require('./src/utils'); 11 | 12 | const start = async () => { 13 | for (let i = 3000; i <= 4000; i++) { 14 | try { 15 | if (i % 50 == 0) { 16 | await waitTime(30000); 17 | } else { 18 | await waitTime(2000); 19 | } 20 | const result = await getGoodsBySku(i); 21 | console.log(result?.data?.title, i, result?.data?.quantity); 22 | if (result.code == 1000 && result?.data?.title?.includes('R10')) { 23 | writeToFile(result); 24 | } 25 | } catch (error) { 26 | console.log(i, '错误'); 27 | await waitTime(10000); 28 | } 29 | } 30 | }; 31 | start(); 32 | -------------------------------------------------------------------------------- /filterApiResultToFile/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "getapiinfotofile", 3 | "version": "1.0.0", 4 | "lockfileVersion": 3, 5 | "requires": true, 6 | "packages": { 7 | "": { 8 | "name": "getapiinfotofile", 9 | "version": "1.0.0", 10 | "license": "ISC", 11 | "dependencies": { 12 | "axios": "^1.7.2", 13 | "qs": "^6.12.3" 14 | } 15 | }, 16 | "node_modules/asynckit": { 17 | "version": "0.4.0", 18 | "resolved": "https://registry.npmmirror.com/asynckit/-/asynckit-0.4.0.tgz", 19 | "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" 20 | }, 21 | "node_modules/axios": { 22 | "version": "1.7.2", 23 | "resolved": "https://registry.npmmirror.com/axios/-/axios-1.7.2.tgz", 24 | "integrity": "sha512-2A8QhOMrbomlDuiLeK9XibIBzuHeRcqqNOHp0Cyp5EoJ1IFDh+XZH3A6BkXtv0K4gFGCI0Y4BM7B1wOEi0Rmgw==", 25 | "dependencies": { 26 | "follow-redirects": "^1.15.6", 27 | "form-data": "^4.0.0", 28 | "proxy-from-env": "^1.1.0" 29 | } 30 | }, 31 | "node_modules/call-bind": { 32 | "version": "1.0.7", 33 | "resolved": "https://registry.npmmirror.com/call-bind/-/call-bind-1.0.7.tgz", 34 | "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", 35 | "dependencies": { 36 | "es-define-property": "^1.0.0", 37 | "es-errors": "^1.3.0", 38 | "function-bind": "^1.1.2", 39 | "get-intrinsic": "^1.2.4", 40 | "set-function-length": "^1.2.1" 41 | }, 42 | "engines": { 43 | "node": ">= 0.4" 44 | }, 45 | "funding": { 46 | "url": "https://github.com/sponsors/ljharb" 47 | } 48 | }, 49 | "node_modules/combined-stream": { 50 | "version": "1.0.8", 51 | "resolved": "https://registry.npmmirror.com/combined-stream/-/combined-stream-1.0.8.tgz", 52 | "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", 53 | "dependencies": { 54 | "delayed-stream": "~1.0.0" 55 | }, 56 | "engines": { 57 | "node": ">= 0.8" 58 | } 59 | }, 60 | "node_modules/define-data-property": { 61 | "version": "1.1.4", 62 | "resolved": "https://registry.npmmirror.com/define-data-property/-/define-data-property-1.1.4.tgz", 63 | "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", 64 | "dependencies": { 65 | "es-define-property": "^1.0.0", 66 | "es-errors": "^1.3.0", 67 | "gopd": "^1.0.1" 68 | }, 69 | "engines": { 70 | "node": ">= 0.4" 71 | }, 72 | "funding": { 73 | "url": "https://github.com/sponsors/ljharb" 74 | } 75 | }, 76 | "node_modules/delayed-stream": { 77 | "version": "1.0.0", 78 | "resolved": "https://registry.npmmirror.com/delayed-stream/-/delayed-stream-1.0.0.tgz", 79 | "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", 80 | "engines": { 81 | "node": ">=0.4.0" 82 | } 83 | }, 84 | "node_modules/es-define-property": { 85 | "version": "1.0.0", 86 | "resolved": "https://registry.npmmirror.com/es-define-property/-/es-define-property-1.0.0.tgz", 87 | "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==", 88 | "dependencies": { 89 | "get-intrinsic": "^1.2.4" 90 | }, 91 | "engines": { 92 | "node": ">= 0.4" 93 | } 94 | }, 95 | "node_modules/es-errors": { 96 | "version": "1.3.0", 97 | "resolved": "https://registry.npmmirror.com/es-errors/-/es-errors-1.3.0.tgz", 98 | "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", 99 | "engines": { 100 | "node": ">= 0.4" 101 | } 102 | }, 103 | "node_modules/follow-redirects": { 104 | "version": "1.15.6", 105 | "resolved": "https://registry.npmmirror.com/follow-redirects/-/follow-redirects-1.15.6.tgz", 106 | "integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==", 107 | "funding": [ 108 | { 109 | "type": "individual", 110 | "url": "https://github.com/sponsors/RubenVerborgh" 111 | } 112 | ], 113 | "engines": { 114 | "node": ">=4.0" 115 | }, 116 | "peerDependenciesMeta": { 117 | "debug": { 118 | "optional": true 119 | } 120 | } 121 | }, 122 | "node_modules/form-data": { 123 | "version": "4.0.0", 124 | "resolved": "https://registry.npmmirror.com/form-data/-/form-data-4.0.0.tgz", 125 | "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", 126 | "dependencies": { 127 | "asynckit": "^0.4.0", 128 | "combined-stream": "^1.0.8", 129 | "mime-types": "^2.1.12" 130 | }, 131 | "engines": { 132 | "node": ">= 6" 133 | } 134 | }, 135 | "node_modules/function-bind": { 136 | "version": "1.1.2", 137 | "resolved": "https://registry.npmmirror.com/function-bind/-/function-bind-1.1.2.tgz", 138 | "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", 139 | "funding": { 140 | "url": "https://github.com/sponsors/ljharb" 141 | } 142 | }, 143 | "node_modules/get-intrinsic": { 144 | "version": "1.2.4", 145 | "resolved": "https://registry.npmmirror.com/get-intrinsic/-/get-intrinsic-1.2.4.tgz", 146 | "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", 147 | "dependencies": { 148 | "es-errors": "^1.3.0", 149 | "function-bind": "^1.1.2", 150 | "has-proto": "^1.0.1", 151 | "has-symbols": "^1.0.3", 152 | "hasown": "^2.0.0" 153 | }, 154 | "engines": { 155 | "node": ">= 0.4" 156 | }, 157 | "funding": { 158 | "url": "https://github.com/sponsors/ljharb" 159 | } 160 | }, 161 | "node_modules/gopd": { 162 | "version": "1.0.1", 163 | "resolved": "https://registry.npmmirror.com/gopd/-/gopd-1.0.1.tgz", 164 | "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", 165 | "dependencies": { 166 | "get-intrinsic": "^1.1.3" 167 | }, 168 | "funding": { 169 | "url": "https://github.com/sponsors/ljharb" 170 | } 171 | }, 172 | "node_modules/has-property-descriptors": { 173 | "version": "1.0.2", 174 | "resolved": "https://registry.npmmirror.com/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", 175 | "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", 176 | "dependencies": { 177 | "es-define-property": "^1.0.0" 178 | }, 179 | "funding": { 180 | "url": "https://github.com/sponsors/ljharb" 181 | } 182 | }, 183 | "node_modules/has-proto": { 184 | "version": "1.0.3", 185 | "resolved": "https://registry.npmmirror.com/has-proto/-/has-proto-1.0.3.tgz", 186 | "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==", 187 | "engines": { 188 | "node": ">= 0.4" 189 | }, 190 | "funding": { 191 | "url": "https://github.com/sponsors/ljharb" 192 | } 193 | }, 194 | "node_modules/has-symbols": { 195 | "version": "1.0.3", 196 | "resolved": "https://registry.npmmirror.com/has-symbols/-/has-symbols-1.0.3.tgz", 197 | "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", 198 | "engines": { 199 | "node": ">= 0.4" 200 | }, 201 | "funding": { 202 | "url": "https://github.com/sponsors/ljharb" 203 | } 204 | }, 205 | "node_modules/hasown": { 206 | "version": "2.0.2", 207 | "resolved": "https://registry.npmmirror.com/hasown/-/hasown-2.0.2.tgz", 208 | "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", 209 | "dependencies": { 210 | "function-bind": "^1.1.2" 211 | }, 212 | "engines": { 213 | "node": ">= 0.4" 214 | } 215 | }, 216 | "node_modules/mime-db": { 217 | "version": "1.52.0", 218 | "resolved": "https://registry.npmmirror.com/mime-db/-/mime-db-1.52.0.tgz", 219 | "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", 220 | "engines": { 221 | "node": ">= 0.6" 222 | } 223 | }, 224 | "node_modules/mime-types": { 225 | "version": "2.1.35", 226 | "resolved": "https://registry.npmmirror.com/mime-types/-/mime-types-2.1.35.tgz", 227 | "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", 228 | "dependencies": { 229 | "mime-db": "1.52.0" 230 | }, 231 | "engines": { 232 | "node": ">= 0.6" 233 | } 234 | }, 235 | "node_modules/object-inspect": { 236 | "version": "1.13.2", 237 | "resolved": "https://registry.npmmirror.com/object-inspect/-/object-inspect-1.13.2.tgz", 238 | "integrity": "sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g==", 239 | "engines": { 240 | "node": ">= 0.4" 241 | }, 242 | "funding": { 243 | "url": "https://github.com/sponsors/ljharb" 244 | } 245 | }, 246 | "node_modules/proxy-from-env": { 247 | "version": "1.1.0", 248 | "resolved": "https://registry.npmmirror.com/proxy-from-env/-/proxy-from-env-1.1.0.tgz", 249 | "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" 250 | }, 251 | "node_modules/qs": { 252 | "version": "6.12.3", 253 | "resolved": "https://registry.npmmirror.com/qs/-/qs-6.12.3.tgz", 254 | "integrity": "sha512-AWJm14H1vVaO/iNZ4/hO+HyaTehuy9nRqVdkTqlJt0HWvBiBIEXFmb4C0DGeYo3Xes9rrEW+TxHsaigCbN5ICQ==", 255 | "dependencies": { 256 | "side-channel": "^1.0.6" 257 | }, 258 | "engines": { 259 | "node": ">=0.6" 260 | }, 261 | "funding": { 262 | "url": "https://github.com/sponsors/ljharb" 263 | } 264 | }, 265 | "node_modules/set-function-length": { 266 | "version": "1.2.2", 267 | "resolved": "https://registry.npmmirror.com/set-function-length/-/set-function-length-1.2.2.tgz", 268 | "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", 269 | "dependencies": { 270 | "define-data-property": "^1.1.4", 271 | "es-errors": "^1.3.0", 272 | "function-bind": "^1.1.2", 273 | "get-intrinsic": "^1.2.4", 274 | "gopd": "^1.0.1", 275 | "has-property-descriptors": "^1.0.2" 276 | }, 277 | "engines": { 278 | "node": ">= 0.4" 279 | } 280 | }, 281 | "node_modules/side-channel": { 282 | "version": "1.0.6", 283 | "resolved": "https://registry.npmmirror.com/side-channel/-/side-channel-1.0.6.tgz", 284 | "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==", 285 | "dependencies": { 286 | "call-bind": "^1.0.7", 287 | "es-errors": "^1.3.0", 288 | "get-intrinsic": "^1.2.4", 289 | "object-inspect": "^1.13.1" 290 | }, 291 | "engines": { 292 | "node": ">= 0.4" 293 | }, 294 | "funding": { 295 | "url": "https://github.com/sponsors/ljharb" 296 | } 297 | } 298 | } 299 | } 300 | -------------------------------------------------------------------------------- /filterApiResultToFile/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "getapiinfotofile", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "author": "", 10 | "license": "ISC", 11 | "dependencies": { 12 | "axios": "^1.7.2", 13 | "qs": "^6.12.3" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /filterApiResultToFile/src/api.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: yuwuwu 3 | * @Date: 2024-06-28 13:37:45 4 | * @LastEditors: yuwuwu 5 | * @LastEditTime: 2024-07-31 20:27:48 6 | * @FilePath: /markdown-code/getApiInfoToFile/src/api.js 7 | * @Description: 8 | */ 9 | const axios = require('axios'); 10 | const qs = require('qs'); 11 | 12 | const getGoodsBySku = async (sku) => { 13 | const { data } = await axios({ 14 | method: 'GET', 15 | url: `https://shop.canon.com.cn/jiekec/index.php?route=mini/catalog/product/productinfo&s_channel=&b_channel=×tamp=${Date.now()}&gate_token=d0bf96cd5ce5c513ddae72a2d1a88ae7&product_id=${sku}`, 16 | headers: { 17 | Host: 'shop.canon.com.cn', 18 | token: '3c03d34e7042eddf92ec167e88da2747109fa79385ed4c89e3ca1fcc067051d6', 19 | Host: 'shop.canon.com.cn', 20 | 'content-type': 'application/x-www-form-urlencoded', 21 | source: 'wx_mini', 22 | 'User-Agent': 23 | 'Mozilla/5.0 (iPhone; CPU iPhone OS 17_5_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148 MicroMessenger/8.0.49(0x18003135) NetType/WIFI Language/zh_CN', 24 | Referer: 25 | 'https://servicewechat.com/wxd3d8769854ba9cd1/70/page-frame.html', 26 | }, 27 | }); 28 | return data; 29 | }; 30 | const checkCode = async (code) => { 31 | const { data } = await axios({ 32 | method: 'post', 33 | url: `https://shop.canon.com.cn/jiekec/index.php?route=mini/checkout/order/shoppingcodeinfo`, 34 | headers: { 35 | Host: 'shop.canon.com.cn', 36 | referer: 37 | 'https://servicewechat.com/wxd3d8769854ba9cd1/72/page-frame.html', 38 | xweb_xhr: '1', 39 | source: 'wx_mini', 40 | 'user-agent': 41 | 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/98.0.4758.102 Safari/537.36 MicroMessenger/6.8.0(0x16080000) NetType/WIFI MiniProgramEnv/Mac MacWechat/WMPF XWEB/30626', 42 | token: 'c3b0e3db0d1f4daae77b3295f46d6be8a019703c5037785113c08dba7910c190', 43 | Accept: '*/*', 44 | 'Sec-Fetch-Site': 'cross-site', 45 | 'Sec-Fetch-Mode': 'cors', 46 | 'Sec-Fetch-Dest': 'empty', 47 | 'Accept-Language': 'zh-CN,zh', 48 | 'Content-Type': 'application/x-www-form-urlencoded', 49 | Cookie: 50 | 'OCSESSID=b28dd541bddb5190926216b053; acw_tc=707c9fc317224271531166502e0f0f04ef03f217f493f28aaa46d9d4aaf1d3', 51 | }, 52 | data: qs.stringify({ 53 | code: code, 54 | s_channel: '', 55 | b_channel: '', 56 | timestamp: '1722427076121', 57 | gate_token: '982e84221290585c6e73f2fe2d761b86', 58 | code: 'E41835V14R', 59 | uid: '66543333663', 60 | token: 'c3b0e3db0d1f4daae77b3295f46d6be8a019703c5037785113c08dba7910c190', 61 | gate_id: 'MINIGATE', 62 | verifycode: 'yes', 63 | }), 64 | }); 65 | return data; 66 | }; 67 | module.exports = { 68 | getGoodsBySku, 69 | checkCode, 70 | }; 71 | -------------------------------------------------------------------------------- /filterApiResultToFile/src/utils.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: yuwuwu 3 | * @Date: 2024-06-28 14:06:13 4 | * @LastEditors: yuwuwu 5 | * @LastEditTime: 2024-06-28 15:48:53 6 | * @FilePath: /markdown-code/getApiInfoToFile/src/utils.js 7 | * @Description: 8 | */ 9 | const fs = require('fs'); 10 | 11 | /** 12 | * 判断文件是否存在 13 | * @param {*} fileName 14 | * @returns 15 | */ 16 | const accessFile = async (fileName) => { 17 | try { 18 | await fs.promises.access(fileName); 19 | return true; 20 | } catch (error) { 21 | return false; 22 | } 23 | }; 24 | /** 25 | * 删除文件 26 | * @param {*} fileName 27 | */ 28 | const deleteFile = async (fileName) => { 29 | try { 30 | await fs.promises.unlink(fileName); 31 | console.log('文件删除成功:', fileName); 32 | } catch (error) { 33 | console.error(`文件删除失败:`, error); 34 | } 35 | }; 36 | /** 37 | * 写入文件 38 | * @param {*} data 39 | * @param {*} fileName 40 | */ 41 | const writeToFile = async (data, fileName = 'data.json') => { 42 | try { 43 | const exist = await accessFile(fileName); 44 | if (exist) { 45 | await fs.promises.appendFile( 46 | fileName, 47 | `,${JSON.stringify(data, null, 2)}` 48 | ); 49 | console.log('文件追加写入成功:'); 50 | } else { 51 | await fs.promises.writeFile(fileName, JSON.stringify(data, null, 2)); 52 | console.log('文件写入成功:'); 53 | } 54 | } catch (error) { 55 | console.error(`文件写入失败:`); 56 | } 57 | }; 58 | /** 59 | * 等待代码延时 60 | * @param {} n 61 | * @returns 62 | */ 63 | const waitTime = (n = 1000) => new Promise((r) => setTimeout(r, n)); 64 | // 生成10位数字随机字符串 65 | const generateRandomString = (length = 10) => { 66 | const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'; 67 | let result = ''; 68 | for (let i = 0; i < length; i++) { 69 | const randomIndex = Math.floor(Math.random() * characters.length); 70 | result += characters.charAt(randomIndex); 71 | } 72 | return result; 73 | }; 74 | 75 | module.exports = { 76 | writeToFile, 77 | deleteFile, 78 | waitTime, 79 | generateRandomString, 80 | }; 81 | -------------------------------------------------------------------------------- /h5网页唤醒app/demo.html: -------------------------------------------------------------------------------- 1 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | Document 16 | 17 | 18 | 19 | 20 | 21 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /h5网页唤醒app/openApp.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: yuyongxing 3 | * @Date: 2022-04-28 23:34:24 4 | * @LastEditors: yuyongxing 5 | * @LastEditTime: 2022-04-28 23:49:50 6 | * @Description: 唤醒app 7 | */ 8 | class openApp { 9 | constructor(opt) { 10 | console.log(opt) 11 | this.URLScheme = opt.URLScheme 12 | this.downLoadUrl = opt.downLoadUrl 13 | this.UniversalLink = opt.UniversalLink 14 | this.ua = navigator.userAgent.toLowerCase() 15 | this.timer = null 16 | } 17 | isIOS() { 18 | return !!this.ua.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/) || this.ua.includes("mac os x") 19 | } 20 | isAndroid() { 21 | return this.ua.includes("android") || this.ua.includes("Android") || this.ua.includes("Adr") 22 | } 23 | isWeixin() { 24 | return this.ua.match(/MicroMessenger/i) == "micromessenger" 25 | } 26 | isQQ() { 27 | return this.ua.match(/QQ/i) == "qq" 28 | } 29 | isWeibo() { 30 | return this.ua.match(/WeiBo/i) == "weibo" 31 | } 32 | watchVisibility() { 33 | document.addEventListener("visibilitychange", ()=> { 34 | if (document.visibilityState == 'hidden') { 35 | this.timer && clearTimeout(this.timer) 36 | } 37 | }) 38 | } 39 | open() { 40 | if (this.isWeixin() || this.isQQ() || this.isWeibo()) { 41 | //逻辑处理 42 | alert('请在在浏览器打开页面') 43 | return false 44 | } 45 | if (this.isAndroid()) { 46 | this.watchVisibility() 47 | window.location.href = this.URLScheme 48 | this.timer = setTimeout( ()=> { 49 | window.location.href = this.downLoadUrl; 50 | }, 3000); 51 | return 52 | } 53 | if (this.isIOS()) { 54 | if (this.UniversalLink) { 55 | window.location.href = this.UniversalLink 56 | return 57 | } 58 | this.watchVisibility() 59 | window.location.href = this.URLScheme 60 | this.timer = setTimeout( ()=> { 61 | window.location.href = this.downLoadUrl; 62 | clearTimeout(this.timer) 63 | }, 3000); 64 | return 65 | } 66 | } 67 | } 68 | 69 | -------------------------------------------------------------------------------- /more-article.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yuwuwu/blog-code/5477dda5b564fbb50de555fd869731a70befcc35/more-article.png -------------------------------------------------------------------------------- /node搭建消息推送/send-wx-message/.gitignore: -------------------------------------------------------------------------------- 1 | 2 | # Created by https://www.toptal.com/developers/gitignore/api/node 3 | # Edit at https://www.toptal.com/developers/gitignore?templates=node 4 | 5 | ### Node ### 6 | # Logs 7 | logs 8 | *.log 9 | npm-debug.log* 10 | yarn-debug.log* 11 | yarn-error.log* 12 | lerna-debug.log* 13 | 14 | # Diagnostic reports (https://nodejs.org/api/report.html) 15 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 16 | 17 | # Runtime data 18 | pids 19 | *.pid 20 | *.seed 21 | *.pid.lock 22 | 23 | # Directory for instrumented libs generated by jscoverage/JSCover 24 | lib-cov 25 | 26 | # Coverage directory used by tools like istanbul 27 | coverage 28 | *.lcov 29 | 30 | # nyc test coverage 31 | .nyc_output 32 | 33 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 34 | .grunt 35 | 36 | # Bower dependency directory (https://bower.io/) 37 | bower_components 38 | 39 | # node-waf configuration 40 | .lock-wscript 41 | 42 | # Compiled binary addons (https://nodejs.org/api/addons.html) 43 | build/Release 44 | 45 | # Dependency directories 46 | node_modules/ 47 | jspm_packages/ 48 | 49 | # TypeScript v1 declaration files 50 | typings/ 51 | 52 | # TypeScript cache 53 | *.tsbuildinfo 54 | 55 | # Optional npm cache directory 56 | .npm 57 | 58 | # Optional eslint cache 59 | .eslintcache 60 | 61 | # Microbundle cache 62 | .rpt2_cache/ 63 | .rts2_cache_cjs/ 64 | .rts2_cache_es/ 65 | .rts2_cache_umd/ 66 | 67 | # Optional REPL history 68 | .node_repl_history 69 | 70 | # Output of 'npm pack' 71 | *.tgz 72 | 73 | # Yarn Integrity file 74 | .yarn-integrity 75 | 76 | # dotenv environment variables file 77 | .env 78 | .env.test 79 | 80 | # parcel-bundler cache (https://parceljs.org/) 81 | .cache 82 | 83 | # Next.js build output 84 | .next 85 | 86 | # Nuxt.js build / generate output 87 | .nuxt 88 | dist 89 | 90 | # Gatsby files 91 | .cache/ 92 | # Comment in the public line in if your project uses Gatsby and not Next.js 93 | # https://nextjs.org/blog/next-9-1#public-directory-support 94 | # public 95 | 96 | # vuepress build output 97 | .vuepress/dist 98 | 99 | # Serverless directories 100 | .serverless/ 101 | 102 | # FuseBox cache 103 | .fusebox/ 104 | 105 | # DynamoDB Local files 106 | .dynamodb/ 107 | 108 | # TernJS port file 109 | .tern-port 110 | 111 | # Stores VSCode versions used for testing VSCode extensions 112 | .vscode-test 113 | 114 | # End of https://www.toptal.com/developers/gitignore/api/node 115 | n -------------------------------------------------------------------------------- /node搭建消息推送/send-wx-message/README.md: -------------------------------------------------------------------------------- 1 | # Express 应用示例 2 | 3 | 这个目录是基于云开发的一个 [Express](https://expressjs.com/zh-cn/) 应用示例,包含 Express + 云函数,可以基于 **[CloudBase Framework](https://github.com/TencentCloudBase/cloudbase-framework)** 框架将项目一键部署到云开发环境 4 | 5 | ## 线上演示地址 6 | 7 | [https://framework.service.tcloudbase.com/express-starter/](https://framework.service.tcloudbase.com/express-starter/) 8 | 9 | 点击下方按钮使用 [CloudBase Framework](https://github.com/TencentCloudBase/cloudbase-framework) 可以在云端一键部署本项目到自己的云开发账号上。 10 | 11 | [![](https://main.qcloudimg.com/raw/67f5a389f1ac6f3b4d04c7256438e44f.svg)](https://console.cloud.tencent.com/tcb/env/index?action=CreateAndDeployCloudBaseProject&tdl_anchor=github&tdl_site=0&appUrl=https%3A%2F%2Fgithub.com%2FTencentCloudBase%2Fcloudbase-templates&workDir=express-starter&appName=express-starter) 12 | 13 | ## 部署一个 Express 应用 14 | 15 | ### 步骤一. 准备工作 16 | 17 | 具体步骤请参照 [准备云开发环境和 CloudBase CLI 命令工具](https://github.com/TencentCloudBase/cloudbase-framework/blob/master/CLI_GUIDE.md) 18 | 19 | ### 步骤二. 初始化应用示例 20 | 21 | 在命令行执行 22 | 23 | ``` 24 | cloudbase init --template express-starter 25 | ``` 26 | 27 | ### 步骤三. 一键部署 28 | 29 | 进入到项目目录,在命令行执行 30 | 31 | ``` 32 | cloudbase framework deploy 33 | ``` 34 | 35 | ## 开发命令及配置 36 | 37 | ### 本地开发 38 | 39 | ``` 40 | npm run dev 41 | ``` 42 | 43 | ### 上线部署 44 | 45 | ``` 46 | npm run deploy 47 | ``` 48 | 49 | ### CloudBase Framework 相关开发配置 50 | 51 | 查看 [CloudBase Framework 配置](https://github.com/TencentCloudBase/cloudbase-framework). 52 | 53 | ### Express 开发文档 54 | 55 | 查看 [starter](https://expressjs.com/zh-cn/starter/installing.html). 56 | -------------------------------------------------------------------------------- /node搭建消息推送/send-wx-message/app.js: -------------------------------------------------------------------------------- 1 | const createError = require("http-errors"); 2 | const express = require("express"); 3 | const path = require("path"); 4 | const cookieParser = require("cookie-parser"); 5 | const logger = require("morgan"); 6 | 7 | const indexRouter = require("./routes/index"); 8 | const usersRouter = require("./routes/users"); 9 | 10 | const app = express(); 11 | 12 | // view engine setup 13 | app.set("views", path.join(__dirname, "views")); 14 | app.set("view engine", "jade"); 15 | 16 | app.use(logger("dev")); 17 | app.use(express.json()); 18 | app.use(express.urlencoded({ extended: false })); 19 | app.use(cookieParser()); 20 | app.use(express.static(path.join(__dirname, "public"))); 21 | 22 | app.use("/", indexRouter); 23 | app.use("/users", usersRouter); 24 | 25 | // catch 404 and forward to error handler 26 | app.use(function (req, res, next) { 27 | next(createError(404)); 28 | }); 29 | 30 | // error handler 31 | app.use(function (err, req, res, next) { 32 | // set locals, only providing error in development 33 | res.locals.message = err.message; 34 | res.locals.error = req.app.get("env") === "development" ? err : {}; 35 | 36 | // render the error page 37 | res.status(err.status || 500); 38 | res.render("error"); 39 | }); 40 | 41 | module.exports = app; 42 | -------------------------------------------------------------------------------- /node搭建消息推送/send-wx-message/bin/www: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | /** 4 | * Module dependencies. 5 | */ 6 | 7 | const app = require('../app'); 8 | const debug = require('debug')('express:server'); 9 | const http = require('http'); 10 | 11 | /** 12 | * Get port from environment and store in Express. 13 | */ 14 | 15 | const port = normalizePort(process.env.PORT || '3000'); 16 | app.set('port', port); 17 | 18 | /** 19 | * Create HTTP server. 20 | */ 21 | 22 | const server = http.createServer(app); 23 | 24 | /** 25 | * Listen on provided port, on all network interfaces. 26 | */ 27 | 28 | server.listen(port); 29 | server.on('error', onError); 30 | server.on('listening', onListening); 31 | 32 | /** 33 | * Normalize a port into a number, string, or false. 34 | */ 35 | 36 | function normalizePort(val) { 37 | const port = parseInt(val, 10); 38 | 39 | if (isNaN(port)) { 40 | // named pipe 41 | return val; 42 | } 43 | 44 | if (port >= 0) { 45 | // port number 46 | return port; 47 | } 48 | 49 | return false; 50 | } 51 | 52 | /** 53 | * Event listener for HTTP server "error" event. 54 | */ 55 | 56 | function onError(error) { 57 | if (error.syscall !== 'listen') { 58 | throw error; 59 | } 60 | 61 | const bind = typeof port === 'string' 62 | ? 'Pipe ' + port 63 | : 'Port ' + port; 64 | 65 | // handle specific listen errors with friendly messages 66 | switch (error.code) { 67 | case 'EACCES': 68 | console.error(bind + ' requires elevated privileges'); 69 | process.exit(1); 70 | break; 71 | case 'EADDRINUSE': 72 | console.error(bind + ' is already in use'); 73 | process.exit(1); 74 | break; 75 | default: 76 | throw error; 77 | } 78 | } 79 | 80 | /** 81 | * Event listener for HTTP server "listening" event. 82 | */ 83 | 84 | function onListening() { 85 | const addr = server.address(); 86 | const bind = typeof addr === 'string' 87 | ? 'pipe ' + addr 88 | : 'port ' + addr.port; 89 | console.log(addr) 90 | debug('Listening on ' + bind); 91 | } 92 | -------------------------------------------------------------------------------- /node搭建消息推送/send-wx-message/cloudbaserc.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "2.0", 3 | "envId": "send-wx-message-9g3383r7e56cf5a4", 4 | "$schema": "https://framework-1258016615.tcloudbaseapp.com/schema/latest.json", 5 | "framework": { 6 | "name": "express-starter", 7 | "plugins": { 8 | "node": { 9 | "use": "@cloudbase/framework-plugin-node", 10 | "inputs": { 11 | "name": "express-starter", 12 | "path": "/express-starter" 13 | } 14 | } 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /node搭建消息推送/send-wx-message/models/wxApi.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: yuyongxing 3 | * @Date: 2022-04-18 22:20:40 4 | * @LastEditors: yuyongxing 5 | * @LastEditTime: 2022-04-21 23:26:37 6 | * @Description: 7 | */ 8 | const axios = require("axios"); 9 | 10 | 11 | module.exports = { 12 | getOpenid: async (appid, secret, code) => { 13 | const url = `https://api.weixin.qq.com/sns/oauth2/access_token?appid=${appid}&secret=${secret}&code=${code}&grant_type=authorization_code` 14 | const { data } = await axios({ 15 | url: url 16 | }) 17 | return data 18 | }, 19 | getAccessToken: async (appid, secret) => { 20 | const accessTokenJson = global.accessTokenJson || {} 21 | const nowTime = new Date().getTime() 22 | // 提前半小时刷新access_token 23 | if (accessTokenJson.access_token && (nowTime - accessTokenJson.createTime < (accessTokenJson.expires_in - 1800) * 1000)) { 24 | return accessTokenJson 25 | } else { 26 | const { data } = await axios({ 27 | url: `https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=${appid}&secret=${secret}` 28 | }) 29 | if (data.access_token) { 30 | global.accessTokenJson = {...data,createTime:nowTime} 31 | } 32 | return data 33 | } 34 | 35 | }, 36 | sendWxMessage: async (openid, access_token, title, desc) => { 37 | const json = { 38 | touser: openid, 39 | template_id: 'Hzz2IF_rF59sOBDdVtrXntuTC4E98XLGUl6_PGUYBHg', 40 | topcolor: "#FF0000", 41 | data: { 42 | title: { 43 | value: title, 44 | color: "#173177" 45 | }, 46 | desc: { 47 | value: desc, 48 | color: '#173177' 49 | } 50 | } 51 | } 52 | const { data } = await axios({ 53 | method: "post", 54 | url: `https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=${access_token}`, 55 | data: json 56 | }) 57 | return data 58 | } 59 | } -------------------------------------------------------------------------------- /node搭建消息推送/send-wx-message/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "express", 3 | "version": "0.0.0", 4 | "private": true, 5 | "scripts": { 6 | "start": "node ./bin/www", 7 | "dev": "npm run start", 8 | "deploy": "cloudbase framework deploy", 9 | "deploy:server": "cloudbase framework deploy node" 10 | }, 11 | "dependencies": { 12 | "axios": "^0.26.1", 13 | "cookie-parser": "~1.4.4", 14 | "debug": "~2.6.9", 15 | "express": "~4.16.1", 16 | "http-errors": "~1.6.3", 17 | "jade": "~1.11.0", 18 | "morgan": "~1.9.1", 19 | "node-sha1": "^1.0.1", 20 | "urlencode": "^1.1.0" 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /node搭建消息推送/send-wx-message/public/js/index.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: yuyongxing 3 | * @Date: 2022-04-19 10:07:06 4 | * @LastEditors: yuyongxing 5 | * @LastEditTime: 2022-04-19 11:06:58 6 | * @Description: 7 | */ 8 | function handleCopy(){ 9 | var input = document.getElementById("copy") 10 | input.select() 11 | document.execCommand("copy") 12 | alert("复制成功") 13 | } -------------------------------------------------------------------------------- /node搭建消息推送/send-wx-message/public/stylesheets/style.css: -------------------------------------------------------------------------------- 1 | body { 2 | padding: 50px; 3 | font: 14px "Lucida Grande", Helvetica, Arial, sans-serif; 4 | } 5 | 6 | a { 7 | color: #00B7FF; 8 | } 9 | input{ 10 | width: 100%; 11 | } 12 | *{ 13 | font-size: 2em; 14 | } -------------------------------------------------------------------------------- /node搭建消息推送/send-wx-message/routes/index.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: yuyongxing 3 | * @Date: 2021-12-20 07:28:48 4 | * @LastEditors: yuyongxing 5 | * @LastEditTime: 2022-04-22 11:06:15 6 | * @Description: 7 | */ 8 | const express = require("express"); 9 | const config = require("../utils/wxConfig.js") 10 | const sha1 = require('node-sha1') 11 | const router = express.Router(); 12 | const urlencode= require('urlencode') 13 | const {getOpenid,getAccessToken,sendWxMessage} = require('../models/wxApi') 14 | 15 | // 验证消息来自微信服务器 16 | router.get("/", function (req, res, next) { 17 | const token = config.token 18 | const signature = req.query.signature 19 | const nonce = req.query.nonce 20 | const timestamp = req.query.timestamp 21 | const str = [token, timestamp, nonce].sort().join('') 22 | const sha = sha1(str) 23 | if (sha === signature) { 24 | const echostr = req.query.echostr; //获取微信请求参数echostr 25 | res.send(echostr + ''); //正常返回请求参数echostr 26 | } else { 27 | res.send('验证失败'); 28 | } 29 | }); 30 | 31 | // 网页授权回调获取code 32 | router.get("/authorize", function (req, res, next) { 33 | const appid = config.appid 34 | const redirect_uri = urlencode("https://send-wx-message-xxxxxxxxxxxxxxxx.ap-shanghai.app.tcloudbase.com/express-starter/getUserInfo") 35 | const scope = 'snsapi_userinfo'; 36 | res.redirect(`https://open.weixin.qq.com/connect/oauth2/authorize?appid=${appid}&redirect_uri=${redirect_uri}&response_type=code&scope=${scope}&state=STATE&connect_redirect=1#wechat_redirect`) 37 | }); 38 | 39 | // 根据code当前用户查询信息 40 | router.get("/getUserInfo", async (req, res, next)=> { 41 | try { 42 | const {appid,secret} = config 43 | const code = req.query.code 44 | const res_getOpenid = await getOpenid(appid,secret,code) 45 | if(res_getOpenid.openid){ 46 | res.render("index", { title: "复制key" ,openid:res_getOpenid.openid}); 47 | }else{ 48 | res.render("error", { res_getOpenid}); 49 | } 50 | } catch (error) { 51 | res.render("error", { errcode:500,errmsg: error }); 52 | } 53 | 54 | }); 55 | 56 | // 推送模板消息 57 | router.post("/sendMessage",async (req, res, next)=> { 58 | try { 59 | const {openid,title,desc} = req.body 60 | const {appid,secret} = config 61 | const res_getAccessToken = await getAccessToken(appid,secret) 62 | console.log(res_getAccessToken) 63 | if(res_getAccessToken.errcode > 0){ 64 | res.send(res_getAccessToken) 65 | return 66 | } 67 | const res_sendWxMessage = await sendWxMessage(openid,res_getAccessToken.access_token,title,desc) 68 | if(res_sendWxMessage.errcode > 0){ 69 | res.send(res_sendWxMessage) 70 | return 71 | } 72 | res.send({ 73 | errcode:0, 74 | errmsg:'ok' 75 | }) 76 | } catch (error) { 77 | res.send( { errcode:500,errmsg: error }); 78 | } 79 | }) 80 | module.exports = router; 81 | 82 | -------------------------------------------------------------------------------- /node搭建消息推送/send-wx-message/routes/users.js: -------------------------------------------------------------------------------- 1 | const express = require('express'); 2 | const router = express.Router(); 3 | 4 | /* GET users listing. */ 5 | router.get('/', function(req, res, next) { 6 | res.send('respond with a resource'); 7 | }); 8 | 9 | module.exports = router; 10 | -------------------------------------------------------------------------------- /node搭建消息推送/send-wx-message/utils/wxConfig.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: yuyongxing 3 | * @Date: 2022-04-08 10:40:07 4 | * @LastEditors: yuyongxing 5 | * @LastEditTime: 2022-04-21 18:56:01 6 | * @Description: 7 | */ 8 | module.exports = { 9 | appid:"", 10 | secret:"", 11 | token:"" 12 | } -------------------------------------------------------------------------------- /node搭建消息推送/send-wx-message/views/error.jade: -------------------------------------------------------------------------------- 1 | extends layout 2 | 3 | block content 4 | h1= errcode 5 | h2= errmsg 6 | -------------------------------------------------------------------------------- /node搭建消息推送/send-wx-message/views/index.jade: -------------------------------------------------------------------------------- 1 | extends layout 2 | 3 | block content 4 | h1 用户标识 5 | p 你可以点击复制按钮或者手动复制你的openid 6 | input(id='copy',type="text",value= openid,style ={border:'1px solid #333'} ) 7 | button(onclick="handleCopy()") 复制 8 | script(src="js/index.js") -------------------------------------------------------------------------------- /node搭建消息推送/send-wx-message/views/layout.jade: -------------------------------------------------------------------------------- 1 | doctype html 2 | html 3 | head 4 | title= title 5 | link(rel='stylesheet', href='stylesheets/style.css') 6 | body 7 | block content 8 | -------------------------------------------------------------------------------- /node服务解决跨域/dist/css/app.e20425ad.css: -------------------------------------------------------------------------------- 1 | .hello[data-v-7ac9f755]{width:100%}.hello p[data-v-7ac9f755]{text-align:center;color:#00f}.home[data-v-7c9ece68]{width:100%;display:flex;flex-wrap:wrap;justify-content:center}.home img[data-v-7c9ece68]{width:2rem}*{margin:0;padding:0;box-sizing:border-box}body{height:100%;width:100%;-webkit-text-size-adjust:100%!important;text-size-adjust:100%!important;-moz-text-size-adjust:100%!important}input{background:none;outline:none;-webkit-tap-highlight-color:transparent;-webkit-appearance:none}input,input:focus{border:none} -------------------------------------------------------------------------------- /node服务解决跨域/dist/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yuwuwu/blog-code/5477dda5b564fbb50de555fd869731a70befcc35/node服务解决跨域/dist/favicon.ico -------------------------------------------------------------------------------- /node服务解决跨域/dist/img/logo.82b9c7a5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yuwuwu/blog-code/5477dda5b564fbb50de555fd869731a70befcc35/node服务解决跨域/dist/img/logo.82b9c7a5.png -------------------------------------------------------------------------------- /node服务解决跨域/dist/index.html: -------------------------------------------------------------------------------- 1 | vue-mobile-template
-------------------------------------------------------------------------------- /node服务解决跨域/dist/js/app.d7538b2e.js: -------------------------------------------------------------------------------- 1 | (function(e){function t(t){for(var r,i,c=t[0],u=t[1],s=t[2],f=0,p=[];f=750?"100px":e/750*100+"px")};e.addEventListener&&(t.addEventListener(r,o,!1),e.addEventListener("DOMContentLoaded",o,!1))})(document,window)},"4f32":function(e,t,n){},"56d7":function(e,t,n){"use strict";n.r(t);n("e260"),n("e6cf"),n("cca6"),n("a79d");var r=n("2b0e"),o=function(){var e=this,t=e.$createElement,n=e._self._c||t;return n("div",{attrs:{id:"app"}},[n("router-view")],1)},a=[],i=n("2877"),c={},u=Object(i["a"])(c,o,a,!1,null,null,null),s=u.exports,l=n("8c4f"),f=function(){var e=this,t=e.$createElement,r=e._self._c||t;return r("div",{staticClass:"home"},[r("img",{attrs:{src:n("cf05")}}),r("HelloWorld",{attrs:{msg:"hello world"}}),r("van-button",{attrs:{type:"primary"},on:{click:e.showToast}},[e._v(" primary ")])],1)},p=[],d=function(){var e=this,t=e.$createElement,n=e._self._c||t;return n("div",{staticClass:"hello"},[n("p",[e._v(e._s(e.msg))])])},v=[],m={name:"HelloWorld",props:{msg:{type:String,default:""}}},h=m,b=(n("f82c"),Object(i["a"])(h,d,v,!1,null,"7ac9f755",null)),g=b.exports,y=(n("d3b7"),n("caad"),n("2532"),n("bc3a")),w=n.n(y),j=n("d399"),_="/api/",O=w.a.create({baseURL:_,timeout:5e4});O.interceptors.request.use((function(e){var t=localStorage.token;return e.headers=e.header||{"Content-Type":"application/json;charset=UTF-8"},t&&(e.headers["Authorization"]=t),e}),(function(e){return Promise.reject(e)})),O.interceptors.response.use((function(e){console.log("🚀 ~ file: request.js ~ line 39 ~ response",e);var t="content-type";if("application/json"!==e.headers[t])return e.data;var n=e.data;switch(n.code){case 200:return n;default:return Object(j["a"])(n.msg),n}}),(function(e){var t=e.message;return"Network Error"===t?t="后端接口连接异常":t.includes("timeout")?t="系统接口请求超时":t.includes("Request failed with status code")&&(t="系统接口"+t.substr(t.length-3)+"异常"),Object(j["a"])(t),Promise.reject(e)}));var x=O;function E(e){return x({url:"/login",method:"post",data:e})}var P={name:"Home",components:{HelloWorld:g},methods:{showToast:function(){var e=this;E().then((function(t){console.log(t),1===t.code&&e.$toast("成功")}))}}},S=P,k=(n("12bd"),Object(i["a"])(S,f,p,!1,null,"7c9ece68",null)),T=k.exports,$=function(){var e=this,t=e.$createElement;e._self._c;return e._m(0)},C=[function(){var e=this,t=e.$createElement,n=e._self._c||t;return n("div",{staticClass:"about"},[n("h1",[e._v("This is an about page")])])}],H={},L=Object(i["a"])(H,$,C,!1,null,null,null),M=L.exports;r["a"].use(l["a"]);var W=[{path:"/",name:"Home",meta:{title:"主页",keepAlive:!0},component:T},{path:"/login",name:"login",meta:{title:"登录",keepAlive:!0},component:M}],q=new l["a"]({routes:W});q.beforeEach((function(e,t,n){var r,o;document.title=null!==(r=null===e||void 0===e||null===(o=e.meta)||void 0===o?void 0:o.title)&&void 0!==r?r:"vue-mobile-template",n()}));var z=q,A=n("2f62");r["a"].use(A["a"]);var J=new A["a"].Store({state:{},mutations:{},actions:{},modules:{}}),R=function(e,t){Object(j["a"])(e)},U=n("b970");n("157a"),n("4942"),n("a9c6");r["a"].use(U["a"]),r["a"].prototype.$toast=R,r["a"].config.productionTip=!1,new r["a"]({router:z,store:J,render:function(e){return e(s)}}).$mount("#app")},a9c6:function(e,t,n){},cf05:function(e,t,n){e.exports=n.p+"img/logo.82b9c7a5.png"},d794:function(e,t,n){},f82c:function(e,t,n){"use strict";n("d794")}}); -------------------------------------------------------------------------------- /node服务解决跨域/index.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: yuyongxing 3 | * @Date: 2021-08-27 10:09:47 4 | * @LastEditors: yuyongxing 5 | * @LastEditTime: 2021-12-15 09:46:33 6 | * @Description: 7 | */ 8 | let express = require('express'); 9 | let app = express() 10 | let { createProxyMiddleware } = require('http-proxy-middleware'); 11 | 12 | app.use('/', express.static('dist')) 13 | const options = { 14 | target: 'http://localhost:3000', 15 | changeOrigin: true, 16 | ws: true, 17 | pathRewrite: { 18 | '/api': '', 19 | }, 20 | }; 21 | app.use('/api', createProxyMiddleware(options)); 22 | app.listen(7000); -------------------------------------------------------------------------------- /node服务解决跨域/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "node", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1", 8 | "start": "nodemon index.js" 9 | }, 10 | "author": "", 11 | "license": "ISC", 12 | "dependencies": { 13 | "express": "^4.17.1", 14 | "http-proxy-middleware": "^2.0.1", 15 | "nodemon": "^2.0.12" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /object和map的性能比较/index.html: -------------------------------------------------------------------------------- 1 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | Document 16 | 17 | 18 | 19 | 77 | 78 | 79 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "markdown-code", 3 | "version": "1.0.0", 4 | "description": "博客代码--代码支持文章", 5 | "main": "index.js", 6 | "directories": { 7 | "doc": "./" 8 | }, 9 | "scripts": { 10 | "test": "echo \"Error: no test specified\" && exit 1" 11 | }, 12 | "repository": { 13 | "type": "git", 14 | "url": "git+https://github.com/yuwuwu/markdown-code.git" 15 | }, 16 | "keywords": [ 17 | "博客", 18 | "javascript", 19 | "node", 20 | "脚本" 21 | ], 22 | "author": "yyxpublic@163.com", 23 | "license": "ISC", 24 | "bugs": { 25 | "url": "https://github.com/yuwuwu/markdown-code/issues" 26 | }, 27 | "homepage": "https://github.com/yuwuwu/markdown-code#readme" 28 | } 29 | -------------------------------------------------------------------------------- /puppeteer截图/README.md: -------------------------------------------------------------------------------- 1 | 8 | 9 | # node+puppeteer的截图服务 10 | 11 | ## 安装 12 | ``` 13 | npm install 14 | yarn install 15 | ``` 16 | 17 | ## 运行 18 | ``` 19 | npm start 20 | yarn start 21 | ``` 22 | 23 | ## 使用 24 | 以jq为例 25 | ``` 26 | $.ajax({ 27 | method: "post", 28 | url: "node服务启动的地址" + "/api/getShareImg", 29 | headers: { "content-type": "application/json" }, 30 | type: "JSON", 31 | data: JSON.stringify({ 32 | "width": 750, 33 | "height": 750, 34 | "url": "要访问的地址", 35 | "ele": "body", 36 | "waitTime": 0 37 | }), 38 | success: res => { 39 | console.log(res) 40 | }, 41 | 42 | }) 43 | ``` 44 | src/puppeteer.js里的代码是未使用连接池的代码,如果并发量很小或者本地测试的话可以引用这个文件。src/puppeteerByPool.js里的代码是使用了连接池的代码,相关配置项都有注释,可以根据自己的需求修改。 -------------------------------------------------------------------------------- /puppeteer截图/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "puppeteer-screenshot", 3 | "version": "1.0.0", 4 | "lockfileVersion": 1, 5 | "requires": true, 6 | "dependencies": { 7 | "@types/node": { 8 | "version": "17.0.8", 9 | "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.8.tgz", 10 | "integrity": "sha512-YofkM6fGv4gDJq78g4j0mMuGMkZVxZDgtU0JRdx6FgiJDG+0fY0GKVolOV8WqVmEhLCXkQRjwDdKyPxJp/uucg==", 11 | "optional": true 12 | }, 13 | "@types/yauzl": { 14 | "version": "2.9.2", 15 | "resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.9.2.tgz", 16 | "integrity": "sha512-8uALY5LTvSuHgloDVUvWP3pIauILm+8/0pDMokuDYIoNsOkSwd5AiHBTSEJjKTDcZr5z8UpgOWZkxBF4iJftoA==", 17 | "optional": true, 18 | "requires": { 19 | "@types/node": "*" 20 | } 21 | }, 22 | "agent-base": { 23 | "version": "6.0.2", 24 | "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", 25 | "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", 26 | "requires": { 27 | "debug": "4" 28 | } 29 | }, 30 | "balanced-match": { 31 | "version": "1.0.2", 32 | "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", 33 | "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" 34 | }, 35 | "base64-js": { 36 | "version": "1.5.1", 37 | "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", 38 | "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==" 39 | }, 40 | "bl": { 41 | "version": "4.1.0", 42 | "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", 43 | "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", 44 | "requires": { 45 | "buffer": "^5.5.0", 46 | "inherits": "^2.0.4", 47 | "readable-stream": "^3.4.0" 48 | } 49 | }, 50 | "brace-expansion": { 51 | "version": "1.1.11", 52 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", 53 | "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", 54 | "requires": { 55 | "balanced-match": "^1.0.0", 56 | "concat-map": "0.0.1" 57 | } 58 | }, 59 | "buffer": { 60 | "version": "5.7.1", 61 | "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", 62 | "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", 63 | "requires": { 64 | "base64-js": "^1.3.1", 65 | "ieee754": "^1.1.13" 66 | } 67 | }, 68 | "buffer-crc32": { 69 | "version": "0.2.13", 70 | "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", 71 | "integrity": "sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI=" 72 | }, 73 | "chownr": { 74 | "version": "1.1.4", 75 | "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", 76 | "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==" 77 | }, 78 | "concat-map": { 79 | "version": "0.0.1", 80 | "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", 81 | "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" 82 | }, 83 | "debug": { 84 | "version": "4.3.2", 85 | "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", 86 | "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", 87 | "requires": { 88 | "ms": "2.1.2" 89 | } 90 | }, 91 | "devtools-protocol": { 92 | "version": "0.0.937139", 93 | "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.937139.tgz", 94 | "integrity": "sha512-daj+rzR3QSxsPRy5vjjthn58axO8c11j58uY0lG5vvlJk/EiOdCWOptGdkXDjtuRHr78emKq0udHCXM4trhoDQ==" 95 | }, 96 | "end-of-stream": { 97 | "version": "1.4.4", 98 | "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", 99 | "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", 100 | "requires": { 101 | "once": "^1.4.0" 102 | } 103 | }, 104 | "extract-zip": { 105 | "version": "2.0.1", 106 | "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-2.0.1.tgz", 107 | "integrity": "sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==", 108 | "requires": { 109 | "@types/yauzl": "^2.9.1", 110 | "debug": "^4.1.1", 111 | "get-stream": "^5.1.0", 112 | "yauzl": "^2.10.0" 113 | } 114 | }, 115 | "fd-slicer": { 116 | "version": "1.1.0", 117 | "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", 118 | "integrity": "sha1-JcfInLH5B3+IkbvmHY85Dq4lbx4=", 119 | "requires": { 120 | "pend": "~1.2.0" 121 | } 122 | }, 123 | "find-up": { 124 | "version": "4.1.0", 125 | "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", 126 | "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", 127 | "requires": { 128 | "locate-path": "^5.0.0", 129 | "path-exists": "^4.0.0" 130 | } 131 | }, 132 | "fs-constants": { 133 | "version": "1.0.0", 134 | "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", 135 | "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==" 136 | }, 137 | "fs.realpath": { 138 | "version": "1.0.0", 139 | "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", 140 | "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" 141 | }, 142 | "get-stream": { 143 | "version": "5.2.0", 144 | "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", 145 | "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", 146 | "requires": { 147 | "pump": "^3.0.0" 148 | } 149 | }, 150 | "glob": { 151 | "version": "7.2.0", 152 | "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", 153 | "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", 154 | "requires": { 155 | "fs.realpath": "^1.0.0", 156 | "inflight": "^1.0.4", 157 | "inherits": "2", 158 | "minimatch": "^3.0.4", 159 | "once": "^1.3.0", 160 | "path-is-absolute": "^1.0.0" 161 | } 162 | }, 163 | "https-proxy-agent": { 164 | "version": "5.0.0", 165 | "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz", 166 | "integrity": "sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA==", 167 | "requires": { 168 | "agent-base": "6", 169 | "debug": "4" 170 | } 171 | }, 172 | "ieee754": { 173 | "version": "1.2.1", 174 | "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", 175 | "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==" 176 | }, 177 | "inflight": { 178 | "version": "1.0.6", 179 | "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", 180 | "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", 181 | "requires": { 182 | "once": "^1.3.0", 183 | "wrappy": "1" 184 | } 185 | }, 186 | "inherits": { 187 | "version": "2.0.4", 188 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", 189 | "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" 190 | }, 191 | "locate-path": { 192 | "version": "5.0.0", 193 | "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", 194 | "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", 195 | "requires": { 196 | "p-locate": "^4.1.0" 197 | } 198 | }, 199 | "minimatch": { 200 | "version": "3.0.4", 201 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", 202 | "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", 203 | "requires": { 204 | "brace-expansion": "^1.1.7" 205 | } 206 | }, 207 | "mkdirp-classic": { 208 | "version": "0.5.3", 209 | "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", 210 | "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==" 211 | }, 212 | "ms": { 213 | "version": "2.1.2", 214 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", 215 | "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" 216 | }, 217 | "node-fetch": { 218 | "version": "2.6.5", 219 | "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.5.tgz", 220 | "integrity": "sha512-mmlIVHJEu5rnIxgEgez6b9GgWXbkZj5YZ7fx+2r94a2E+Uirsp6HsPTPlomfdHtpt/B0cdKviwkoaM6pyvUOpQ==", 221 | "requires": { 222 | "whatwg-url": "^5.0.0" 223 | } 224 | }, 225 | "once": { 226 | "version": "1.4.0", 227 | "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", 228 | "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", 229 | "requires": { 230 | "wrappy": "1" 231 | } 232 | }, 233 | "p-limit": { 234 | "version": "2.3.0", 235 | "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", 236 | "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", 237 | "requires": { 238 | "p-try": "^2.0.0" 239 | } 240 | }, 241 | "p-locate": { 242 | "version": "4.1.0", 243 | "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", 244 | "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", 245 | "requires": { 246 | "p-limit": "^2.2.0" 247 | } 248 | }, 249 | "p-try": { 250 | "version": "2.2.0", 251 | "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", 252 | "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==" 253 | }, 254 | "path-exists": { 255 | "version": "4.0.0", 256 | "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", 257 | "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==" 258 | }, 259 | "path-is-absolute": { 260 | "version": "1.0.1", 261 | "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", 262 | "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" 263 | }, 264 | "pend": { 265 | "version": "1.2.0", 266 | "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", 267 | "integrity": "sha1-elfrVQpng/kRUzH89GY9XI4AelA=" 268 | }, 269 | "pkg-dir": { 270 | "version": "4.2.0", 271 | "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", 272 | "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", 273 | "requires": { 274 | "find-up": "^4.0.0" 275 | } 276 | }, 277 | "progress": { 278 | "version": "2.0.3", 279 | "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", 280 | "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==" 281 | }, 282 | "proxy-from-env": { 283 | "version": "1.1.0", 284 | "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", 285 | "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" 286 | }, 287 | "pump": { 288 | "version": "3.0.0", 289 | "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", 290 | "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", 291 | "requires": { 292 | "end-of-stream": "^1.1.0", 293 | "once": "^1.3.1" 294 | } 295 | }, 296 | "puppeteer-core": { 297 | "version": "13.0.1", 298 | "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-13.0.1.tgz", 299 | "integrity": "sha512-aKTN7Rtu7zJuhadihaxXnbC4fRPe/Q6VR8u6krJk3dnmTL7am01hl3XG1x9nNCkxi5fA4+e4ba9QmTvFiqGxSA==", 300 | "requires": { 301 | "debug": "4.3.2", 302 | "devtools-protocol": "0.0.937139", 303 | "extract-zip": "2.0.1", 304 | "https-proxy-agent": "5.0.0", 305 | "node-fetch": "2.6.5", 306 | "pkg-dir": "4.2.0", 307 | "progress": "2.0.3", 308 | "proxy-from-env": "1.1.0", 309 | "rimraf": "3.0.2", 310 | "tar-fs": "2.1.1", 311 | "unbzip2-stream": "1.4.3", 312 | "ws": "8.2.3" 313 | } 314 | }, 315 | "readable-stream": { 316 | "version": "3.6.0", 317 | "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", 318 | "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", 319 | "requires": { 320 | "inherits": "^2.0.3", 321 | "string_decoder": "^1.1.1", 322 | "util-deprecate": "^1.0.1" 323 | } 324 | }, 325 | "rimraf": { 326 | "version": "3.0.2", 327 | "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", 328 | "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", 329 | "requires": { 330 | "glob": "^7.1.3" 331 | } 332 | }, 333 | "safe-buffer": { 334 | "version": "5.2.1", 335 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", 336 | "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" 337 | }, 338 | "string_decoder": { 339 | "version": "1.3.0", 340 | "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", 341 | "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", 342 | "requires": { 343 | "safe-buffer": "~5.2.0" 344 | } 345 | }, 346 | "tar-fs": { 347 | "version": "2.1.1", 348 | "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.1.tgz", 349 | "integrity": "sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==", 350 | "requires": { 351 | "chownr": "^1.1.1", 352 | "mkdirp-classic": "^0.5.2", 353 | "pump": "^3.0.0", 354 | "tar-stream": "^2.1.4" 355 | } 356 | }, 357 | "tar-stream": { 358 | "version": "2.2.0", 359 | "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", 360 | "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", 361 | "requires": { 362 | "bl": "^4.0.3", 363 | "end-of-stream": "^1.4.1", 364 | "fs-constants": "^1.0.0", 365 | "inherits": "^2.0.3", 366 | "readable-stream": "^3.1.1" 367 | } 368 | }, 369 | "through": { 370 | "version": "2.3.8", 371 | "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", 372 | "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=" 373 | }, 374 | "tr46": { 375 | "version": "0.0.3", 376 | "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", 377 | "integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o=" 378 | }, 379 | "unbzip2-stream": { 380 | "version": "1.4.3", 381 | "resolved": "https://registry.npmjs.org/unbzip2-stream/-/unbzip2-stream-1.4.3.tgz", 382 | "integrity": "sha512-mlExGW4w71ebDJviH16lQLtZS32VKqsSfk80GCfUlwT/4/hNRFsoscrF/c++9xinkMzECL1uL9DDwXqFWkruPg==", 383 | "requires": { 384 | "buffer": "^5.2.1", 385 | "through": "^2.3.8" 386 | } 387 | }, 388 | "util-deprecate": { 389 | "version": "1.0.2", 390 | "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", 391 | "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" 392 | }, 393 | "webidl-conversions": { 394 | "version": "3.0.1", 395 | "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", 396 | "integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE=" 397 | }, 398 | "whatwg-url": { 399 | "version": "5.0.0", 400 | "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", 401 | "integrity": "sha1-lmRU6HZUYuN2RNNib2dCzotwll0=", 402 | "requires": { 403 | "tr46": "~0.0.3", 404 | "webidl-conversions": "^3.0.0" 405 | } 406 | }, 407 | "wrappy": { 408 | "version": "1.0.2", 409 | "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", 410 | "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" 411 | }, 412 | "ws": { 413 | "version": "8.2.3", 414 | "resolved": "https://registry.npmjs.org/ws/-/ws-8.2.3.tgz", 415 | "integrity": "sha512-wBuoj1BDpC6ZQ1B7DWQBYVLphPWkm8i9Y0/3YdHjHKHiohOJ1ws+3OccDWtH+PoC9DZD5WOTrJvNbWvjS6JWaA==" 416 | }, 417 | "yauzl": { 418 | "version": "2.10.0", 419 | "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", 420 | "integrity": "sha1-x+sXyT4RLLEIb6bY5R+wZnt5pfk=", 421 | "requires": { 422 | "buffer-crc32": "~0.2.3", 423 | "fd-slicer": "~1.1.0" 424 | } 425 | } 426 | } 427 | } 428 | -------------------------------------------------------------------------------- /puppeteer截图/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "puppeteer-screenshot", 3 | "version": "1.0.0", 4 | "description": "puppeteer生成分享海报", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1", 8 | "start": "nodemon src/index.js" 9 | }, 10 | "author": "", 11 | "license": "ISC", 12 | "devDependencies": { 13 | "generic-pool": "3.7.1", 14 | "puppeteer": "^13.0.1" 15 | }, 16 | "dependencies": { 17 | "express": "^4.17.2", 18 | "http-errors": "^2.0.0" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /puppeteer截图/src/index.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: yuyongxing 3 | * @Date: 2022-01-10 11:33:26 4 | * @LastEditors: yuyongxing 5 | * @LastEditTime: 2022-01-16 18:51:21 6 | * @Description: 主入口文件 7 | */ 8 | const express = require('express') 9 | const createError = require("http-errors") 10 | const route = require("./route.js") 11 | const app = express() 12 | 13 | 14 | app.all('*', function(req, res, next) { 15 | res.header("Access-Control-Allow-Origin", req.headers.origin); 16 | // res.header("Access-Control-Allow-Origin", '*'); 17 | res.header("Access-Control-Allow-Headers", "Content-Type,Content-Length, Authorization, Accept,X-Requested-With"); 18 | res.header("Access-Control-Allow-Methods","PUT,POST,GET,DELETE,OPTIONS"); 19 | res.header("Access-Control-Allow-Credentials","true"); 20 | res.header("X-Powered-By",' 3.2.1') 21 | if(req.method === "OPTIONS") res.sendStatus(200);/*让options请求快速返回*/ 22 | else next(); 23 | }); 24 | 25 | 26 | // 中间件--json化入参 27 | app.use(express.json()) 28 | // 初始化路由 29 | route(app) 30 | // 错误拦截 31 | app.use(function(req, res, next) { 32 | next(createError(404)); 33 | }); 34 | app.use(function (err, req, res, next) { 35 | let result = { 36 | code:0, 37 | msg: err.message, 38 | err: err.stack 39 | } 40 | res.status(err.status||500).json(result) 41 | }) 42 | // 启动服务监听7000端口 43 | const server = app.listen(7000, '0.0.0.0', () => { 44 | const host = server.address().address; 45 | const port = server.address().port; 46 | console.log('app start listening at http://%s:%s', host, port); 47 | }); -------------------------------------------------------------------------------- /puppeteer截图/src/puppeteer.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: yuyongxing 3 | * @Date: 2022-01-13 18:07:56 4 | * @LastEditors: yuyongxing 5 | * @LastEditTime: 2022-01-16 18:30:22 6 | * @Description: 工具方法 7 | */ 8 | const puppeteer = require("puppeteer"); 9 | 10 | 11 | const waitTime = (n) => new Promise((r) => setTimeout(r, n)); 12 | module.exports = async (opt) => { 13 | try { 14 | const browser = await puppeteer.launch({ 15 | args: [ 16 | '--no-zygote', 17 | '--no-sandbox', 18 | '--disable-gpu', 19 | '--no-first-run', 20 | '--single-process', 21 | '--disable-extensions', 22 | "--disable-xss-auditor", 23 | '--disable-dev-shm-usage', 24 | '--disable-popup-blocking', 25 | '--disable-setuid-sandbox', 26 | '--disable-accelerated-2d-canvas', 27 | '--enable-features=NetworkService', 28 | ] 29 | }); 30 | const page = await browser.newPage(); 31 | await page.goto(opt.url); 32 | await page.setViewport({ 33 | width: opt.width, 34 | height: opt.height, 35 | }); 36 | await waitTime(opt.waitTime || 0); 37 | const ele = await page.$(opt.ele); 38 | const base64 = await ele.screenshot({ 39 | fullPage: false, 40 | omitBackground: true, 41 | encoding: 'base64' 42 | }); 43 | await browser.close(); 44 | return 'data:image/png;base64,'+ base64 45 | } catch (error) { 46 | throw error 47 | } 48 | }; 49 | -------------------------------------------------------------------------------- /puppeteer截图/src/puppeteerByPool.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: yuyongxing 3 | * @Date: 2022-01-13 18:07:56 4 | * @LastEditors: yuyongxing 5 | * @LastEditTime: 2022-01-16 20:32:08 6 | * @Description: 工具方法 7 | */ 8 | const puppeteer = require("puppeteer"); 9 | const genericPool = require('generic-pool') 10 | 11 | 12 | const waitTime = (n) => new Promise((r) => setTimeout(r, n)); 13 | const initPuppeteerPool = () => { 14 | if (global.pp) global.pp.drain().then(() => global.pp.clear()) 15 | const opt = { 16 | max: 4,//最多产生多少个 puppeteer 实例 。 17 | min: 1,//保证池中最少有多少个实例存活 18 | testOnBorrow: true,// 在将 实例 提供给用户之前,池应该验证这些实例。 19 | autostart: false,//是不是需要在 池 初始化时 初始化 实例 20 | idleTimeoutMillis: 1000 * 60 * 60,//如果一个实例 60分钟 都没访问就关掉他 21 | evictionRunIntervalMillis: 1000 * 60 * 3,//每 3分钟 检查一次 实例的访问状态 22 | maxUses: 2048,//自定义的属性:每一个 实例 最大可重用次数。 23 | validator: () => Promise.resolve(true) 24 | } 25 | const factory = { 26 | create: () => 27 | puppeteer.launch({ 28 | // headless:false,//有头模式 29 | args: [ 30 | '--no-zygote', 31 | '--no-sandbox', 32 | '--disable-gpu', 33 | '--no-first-run', 34 | '--single-process', 35 | '--disable-extensions', 36 | "--disable-xss-auditor", 37 | '--disable-dev-shm-usage', 38 | '--disable-popup-blocking', 39 | '--disable-setuid-sandbox', 40 | '--disable-accelerated-2d-canvas', 41 | '--enable-features=NetworkService', 42 | ] 43 | }).then(instance => { 44 | instance.useCount = 0; 45 | return instance; 46 | }), 47 | destroy: instance => { 48 | instance.close() 49 | }, 50 | validate: instance => { 51 | return opt.validator(instance).then(valid => Promise.resolve(valid && (opt.maxUses <= 0 || instance.useCount < opt.maxUses))); 52 | } 53 | }; 54 | const pool = genericPool.createPool(factory, opt) 55 | const genericAcquire = pool.acquire.bind(pool) 56 | // 重写了原有池的消费实例的方法。添加一个实例使用次数的增加 57 | pool.acquire = () => 58 | genericAcquire().then(instance => { 59 | instance.useCount += 1 60 | return instance 61 | }) 62 | 63 | pool.use = fn => { 64 | let resource 65 | return pool 66 | .acquire() 67 | .then(r => { 68 | resource = r 69 | return resource 70 | }) 71 | .then(fn) 72 | .then( 73 | result => { 74 | // 不管业务方使用实例成功与后都表示一下实例消费完成 75 | pool.release(resource) 76 | return result 77 | }, 78 | err => { 79 | pool.release(resource) 80 | throw err 81 | } 82 | ) 83 | } 84 | return pool; 85 | } 86 | global.pp = initPuppeteerPool() 87 | 88 | module.exports = async (opt) => { 89 | try { 90 | const browser = await global.pp.use() 91 | const page = await browser.newPage(); 92 | await page.goto(opt.url); 93 | await page.setViewport({ 94 | width: opt.width, 95 | height: opt.height, 96 | }); 97 | await waitTime(opt.waitTime || 0); 98 | const ele = await page.$(opt.ele); 99 | const base64 = await ele.screenshot({ 100 | // path: "a.png", 101 | fullPage: false, 102 | omitBackground: true, 103 | encoding: 'base64' 104 | }); 105 | await page.close() 106 | return 'data:image/png;base64,'+ base64 107 | } catch (error) { 108 | throw error 109 | } 110 | }; 111 | -------------------------------------------------------------------------------- /puppeteer截图/src/route.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: yuyongxing 3 | * @Date: 2022-01-14 14:29:07 4 | * @LastEditors: yuyongxing 5 | * @LastEditTime: 2022-01-16 18:58:35 6 | * @Description: 7 | */ 8 | // const getImg = require('./puppeteer.js') 9 | const getImg = require('./puppeteerByPool') 10 | 11 | module.exports = app => { 12 | app.post('/api/getShareImg', (req, res) => { 13 | let params = req.body 14 | let errorMap = { 15 | width: "海报宽度", 16 | height: "海报高度", 17 | url: "生成海报页面地址", 18 | ele: "截取的元素", 19 | } 20 | for (let i in errorMap) { 21 | if (!params[i]) { 22 | res.json({ 23 | code: 0, 24 | msg: `${errorMap[i]}必传` 25 | }) 26 | return 27 | } 28 | } 29 | // res.json({ 30 | // code: 1, 31 | // data: "file", 32 | // msg: "" 33 | // }) 34 | // return 35 | getImg(req.body).then(file => { 36 | res.json({ 37 | code: 1, 38 | data: file, 39 | msg: "" 40 | }) 41 | }).catch(err => { 42 | res.json({ 43 | code: 0, 44 | data: null, 45 | msg: "海报生成失败", 46 | err: String(err) 47 | }) 48 | }) 49 | }); 50 | } -------------------------------------------------------------------------------- /puppeteer截图/test.html: -------------------------------------------------------------------------------- 1 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | Document 16 | 17 | 18 | 19 | 20 | 21 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /qr.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yuwuwu/blog-code/5477dda5b564fbb50de555fd869731a70befcc35/qr.png -------------------------------------------------------------------------------- /yuwuwu-cli/README.md: -------------------------------------------------------------------------------- 1 | 8 | ## yuwuwu-cli 9 | **** 10 | 自定义脚手架工具,可以直接下载github上的项目模板或者通过问询,自定义生成项目模板。 11 | 12 | 13 | ## 安装 14 | ``` 15 | npm install yuwuwu-cli -g 16 | ``` 17 | 18 | ## 使用 19 | ``` 20 | yuwuwu init 21 | ``` -------------------------------------------------------------------------------- /yuwuwu-cli/bin/index.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | /* 3 | * @Author: yuyongxing 4 | * @Date: 2022-03-09 11:46:31 5 | * @LastEditors: yuyongxing 6 | * @LastEditTime: 2022-03-23 23:33:15 7 | * @Description: cli入口 8 | */ 9 | 10 | const version = require("../package.json").version; 11 | const chalk = require("chalk"); 12 | const program = require("commander"); 13 | const { 14 | mkdirByProjectName, 15 | choiceTemplate, 16 | downloadByGit, 17 | createNodeTemplate, 18 | installModules } = require("../lib/create") 19 | 20 | 21 | program 22 | .command("init ") 23 | .description("初始化项目文件") 24 | .action((projectName) => { 25 | console.log(chalk.green("项目名称:" + projectName)); 26 | cliStart() 27 | }); 28 | 29 | program 30 | .on("--help", function () { 31 | console.log(); 32 | console.log(chalk.green("你可以这样使用:yuwuwu init ")); 33 | console.log(); 34 | }); 35 | 36 | program 37 | .version(version, '-v,--version') 38 | .parse(process.argv); 39 | if (program.args.length < 2) program.help(); 40 | 41 | 42 | 43 | async function cliStart() { 44 | // 1.创建项目文件目录 45 | await mkdirByProjectName() 46 | // 2.选择模板 47 | const { choice } = await choiceTemplate() 48 | // 3.根据模板下载对应的文件 49 | switch (choice) { 50 | case 'node': 51 | await createNodeTemplate() 52 | break; 53 | default: 54 | await downloadByGit(choice); 55 | } 56 | // 4.安装依赖 57 | await installModules() 58 | } -------------------------------------------------------------------------------- /yuwuwu-cli/lib/create.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: yuyongxing 3 | * @Date: 2022-03-15 10:52:57 4 | * @LastEditors: yuyongxing 5 | * @LastEditTime: 2022-03-23 23:42:52 6 | * @Description: 7 | */ 8 | const fs = require("fs"); 9 | const program = require("commander"); 10 | const path = require("path"); 11 | const chalk = require("chalk"); 12 | const rimraf = require("rimraf"); 13 | const download = require("download-git-repo"); 14 | const ora = require("ora"); 15 | const execa = require("execa"); 16 | const { choiceTemplateQuestion, isRemoveDirQuestion, nodeProjectQuestion } = require("./questions") 17 | const { getIndexTemplate, getPackageTemplate } = require("./createNodeTemplate") 18 | 19 | 20 | /** 21 | * @Author: yuyongxing 22 | * @param {*} 23 | * @return {*} 24 | * @Date: 2022-03-15 11:12:54 25 | * @LastEditors: yuyongxing 26 | * @LastEditTime: Do not edit 27 | * @Description: 创建文件夹,问询是否覆盖同名目录 28 | */ 29 | async function mkdirByProjectName() { 30 | if (fs.existsSync(program.args[0])) { 31 | console.log(chalk.red(program.args[0] + "文件夹已存在")); 32 | let answers = await isRemoveDirQuestion() 33 | if (answers.ok) { 34 | rimraf.sync(getProjectName()); 35 | fs.mkdirSync(getProjectName()); 36 | } 37 | } else { 38 | fs.mkdirSync(getProjectName()); 39 | } 40 | } 41 | 42 | /** 43 | * @Author: yuyongxing 44 | * @param {*} 45 | * @return {*} answer:选择的模板 46 | * @Date: 2022-03-15 11:13:41 47 | * @LastEditors: yuyongxing 48 | * @LastEditTime: Do not edit 49 | * @Description: 问询选择的模板 50 | */ 51 | async function choiceTemplate() { 52 | return await choiceTemplateQuestion() 53 | } 54 | 55 | /** 56 | * @Author: yuyongxing 57 | * @param {*} url 58 | * @return {*} 59 | * @Date: 2022-03-15 11:14:54 60 | * @LastEditors: yuyongxing 61 | * @LastEditTime: Do not edit 62 | * @Description: 根据url下载github模板 63 | */ 64 | function downloadByGit(url) { 65 | const loading = ora("downloading").start() 66 | return new Promise((res, rej) => { 67 | download(url, getProjectName(), { clone: false }, function (err) { 68 | loading.stop() 69 | if (err) { 70 | console.log(chalk.red(err)); 71 | rej() 72 | process.exit(1) 73 | } 74 | console.log(chalk.green('download success!')); 75 | res() 76 | }); 77 | }) 78 | } 79 | 80 | 81 | /** 82 | * @Author: yuyongxing 83 | * @param {*} 84 | * @return {*} 85 | * @Date: 2022-03-15 11:15:25 86 | * @LastEditors: yuyongxing 87 | * @LastEditTime: Do not edit 88 | * @Description: 问询用户需要选择的插件,通过ejs语法写入 89 | */ 90 | async function createNodeTemplate() { 91 | let answers = await nodeProjectQuestion() 92 | fs.writeFileSync(getProjectName() + "/index.js", getIndexTemplate(answers)) 93 | fs.writeFileSync(getProjectName() + "/package.json", getPackageTemplate(answers)) 94 | } 95 | 96 | 97 | /** 98 | * @Author: yuyongxing 99 | * @param {*} 100 | * @return {*} 101 | * @Date: 2022-03-15 11:16:04 102 | * @LastEditors: yuyongxing 103 | * @LastEditTime: Do not edit 104 | * @Description: 执行 'cd xxxx';'yarn install' 105 | */ 106 | async function installModules() { 107 | const loading = ora("install...").start() 108 | await execa("yarn", { cwd: getProjectName() }, ["install"]) 109 | .then(() => { 110 | loading.succeed("install") 111 | console.log(chalk.green("install success!!!")) 112 | }) 113 | .catch((err) => { 114 | console.log(chalk.red(err)) 115 | loading.stop() 116 | }) 117 | } 118 | 119 | /** 120 | * @Author: yuyongxing 121 | * @param {*} 122 | * @return {*} path 123 | * @Date: 2022-03-15 11:28:40 124 | * @LastEditors: yuyongxing 125 | * @LastEditTime: Do not edit 126 | * @Description: 返回文件绝对路径 127 | */ 128 | function getProjectName() { 129 | return path.resolve(process.cwd(), program.args[0]) 130 | } 131 | 132 | module.exports = { 133 | mkdirByProjectName, 134 | choiceTemplate, 135 | downloadByGit, 136 | createNodeTemplate, 137 | installModules 138 | } -------------------------------------------------------------------------------- /yuwuwu-cli/lib/createNodeTemplate.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: yuyongxing 3 | * @Date: 2022-03-13 17:22:41 4 | * @LastEditors: yuyongxing 5 | * @LastEditTime: 2022-03-15 10:52:22 6 | * @Description: 7 | */ 8 | const ejs = require("ejs") 9 | const fs = require("fs"); 10 | const path = require("path"); 11 | const prettier = require("prettier"); 12 | 13 | function getIndexTemplate(config){ 14 | const ejsTemplateData = fs.readFileSync(path.resolve(__dirname,"./nodeTemplate/index.ejs")) 15 | const indexTemplateData = ejs.render(ejsTemplateData.toString(),{ 16 | port: config.port, 17 | modules: config.modules 18 | }) 19 | return prettier.format(indexTemplateData,{ parser: "babel" }) 20 | } 21 | function getPackageTemplate(config){ 22 | const ejsTemplateData = fs.readFileSync(path.resolve(__dirname,"./nodeTemplate/package.ejs")) 23 | const packageTemplateData = ejs.render(ejsTemplateData.toString(),{ 24 | name: config.name, 25 | description: config.description, 26 | author: config.author, 27 | modules: config.modules 28 | }) 29 | return prettier.format(packageTemplateData,{ parser: "json" }) 30 | } 31 | module.exports = { 32 | getIndexTemplate, 33 | getPackageTemplate 34 | } -------------------------------------------------------------------------------- /yuwuwu-cli/lib/nodeTemplate/index.ejs: -------------------------------------------------------------------------------- 1 | const express = require('express'); 2 | const app = express() 3 | 4 | <% if (modules.indexOf("cors")> -1) { -%> 5 | const cors = require('cors'); 6 | <% } -%> 7 | <% if (modules.indexOf("bodyParser")> -1) { -%> 8 | const bodyParser = require("body-parser"); 9 | <% } -%> 10 | <% if (modules.indexOf("fs")> -1) { -%> 11 | const fs = require("fs"); 12 | <% } -%> 13 | <% if (modules.indexOf("axios")> -1) { -%> 14 | const axios = require("axios"); 15 | <% } -%> 16 | <% if (modules.indexOf("qs")> -1) { -%> 17 | const qs = require("qs"); 18 | <% } -%> 19 | <% if (modules.indexOf("lodash")> -1) { -%> 20 | const lodash = require("lodash"); 21 | <% } -%> 22 | <% if (modules.indexOf("cheerio")> -1) { -%> 23 | const cheerio = require("cheerio"); 24 | <% } -%> 25 | 26 | 27 | 28 | <% if (modules.indexOf("cors")> -1) { -%> 29 | app.use(cors()); 30 | <% } -%> 31 | <% if (modules.indexOf("bodyParser")> -1) { -%> 32 | app.use(bodyParser.json()); 33 | app.use(bodyParser.urlencoded({ extended: false })) 34 | <% } -%> 35 | <% if (modules.indexOf("static")> -1) { -%> 36 | app.use(express.static(__dirname+'/public')) 37 | <% } -%> 38 | 39 | 40 | 41 | const server = app.listen(<%= port %> , '0.0.0.0', () => { 42 | const host = server.address().address; 43 | const port = server.address().port; 44 | console.log('app start listening at http://%s:%s', host, port); 45 | }); -------------------------------------------------------------------------------- /yuwuwu-cli/lib/nodeTemplate/package.ejs: -------------------------------------------------------------------------------- 1 | { 2 | "name": "<%= name %>", 3 | "version": "1.0.0", 4 | "description": "<%= description %>", 5 | "main": "index.js", 6 | "directories": { 7 | "test": "test" 8 | }, 9 | "scripts": { 10 | "test": "echo \"Error: no test specified\" && exit 1", 11 | "start": "node index.js" 12 | }, 13 | "author": "<%= author %>", 14 | "license": "ISC", 15 | "dependencies": { 16 | <% if (modules.indexOf("cors") > -1) { -%> 17 | "cors": "^2.8.5", 18 | <% } -%> 19 | <% if (modules.indexOf("bodyParser") > -1) { -%> 20 | "body-parser": "^1.19.2", 21 | <% } -%> 22 | <% if (modules.indexOf("axios") > -1) { -%> 23 | "axios": "^0.26.1", 24 | <% } -%> 25 | <% if (modules.indexOf("qs") > -1) { -%> 26 | "qs": "^6.10.3", 27 | <% } -%> 28 | <% if (modules.indexOf("lodash") > -1) { -%> 29 | "lodash": "^4.17.21", 30 | <% } -%> 31 | <% if (modules.indexOf("cheerio") > -1) { -%> 32 | "cheerio": "^1.0.0-rc.10", 33 | <% } -%> 34 | "express": "^4.17.2" 35 | } 36 | } -------------------------------------------------------------------------------- /yuwuwu-cli/lib/questions.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: yuyongxing 3 | * @Date: 2022-03-11 15:24:59 4 | * @LastEditors: yuyongxing 5 | * @LastEditTime: 2022-03-14 16:48:26 6 | * @Description: 用户交互模块,需要用户输入、选择 7 | */ 8 | const inquirer = require("inquirer"); 9 | 10 | /** 11 | * @Author: yuyongxing 12 | * @param {*} 13 | * @return {*} 14 | * @Date: 2022-03-11 15:53:00 15 | * @LastEditors: yuyongxing 16 | * @LastEditTime: Do not edit 17 | * @Description: 问题:选择要生成的模板 18 | */ 19 | function choiceTemplateQuestion() { 20 | return inquirer.prompt([ 21 | { 22 | type: "list", 23 | name: "choice", 24 | message: "选择要使用的模板:", 25 | choices: [ 26 | { 27 | value: "github:yuwuwu/vue-mobile-template", 28 | name: "vue2+vant移动端模板", 29 | }, 30 | { 31 | value: "github:yuwuwu/vue-pc-template", 32 | name: "vue2+element后台管理模板", 33 | }, 34 | { 35 | value: "node", 36 | name: "自定义node模板", 37 | }, 38 | ], 39 | }, 40 | ]) 41 | } 42 | /** 43 | * @Author: yuyongxing 44 | * @param {*} 45 | * @return {*} 46 | * @Date: 2022-03-11 15:53:20 47 | * @LastEditors: yuyongxing 48 | * @LastEditTime: Do not edit 49 | * @Description: 问题:是否覆盖同名文件价 50 | */ 51 | function isRemoveDirQuestion() { 52 | return inquirer.prompt([ 53 | { 54 | type: "confirm", 55 | message: "是否覆盖原文件夹?", 56 | name: "ok", 57 | } 58 | ]) 59 | } 60 | function nodeProjectQuestion() { 61 | return inquirer.prompt([ 62 | { 63 | type: 'inpute', 64 | name: 'name', 65 | message: '请输入项目名称', 66 | validate(name) { 67 | if (name) return true; 68 | return "请输入项目名称"; 69 | } 70 | }, 71 | { 72 | type: 'inpute', 73 | name: 'description', 74 | message: '请输入项目简介' 75 | }, 76 | { 77 | type: 'inpute', 78 | name: 'author', 79 | message: '请输入作者名称' 80 | }, 81 | { 82 | type: "input", 83 | name: "port", 84 | message: "请输入运行端口,默认8000", 85 | default() { 86 | return 8000; 87 | }, 88 | }, 89 | { 90 | type: "checkbox", 91 | name: "modules", 92 | message: "选择要使用的中间件或依赖", 93 | choices: [ 94 | { 95 | name: "cors", 96 | }, 97 | { 98 | name: "bodyParser", 99 | }, 100 | { 101 | name: "fs", 102 | }, 103 | { 104 | name: "static", 105 | }, 106 | { 107 | name: "axios", 108 | }, 109 | { 110 | name: "qs", 111 | }, 112 | { 113 | name: "lodash", 114 | }, 115 | ], 116 | } 117 | ]) 118 | } 119 | module.exports = { 120 | choiceTemplateQuestion, 121 | isRemoveDirQuestion, 122 | nodeProjectQuestion 123 | } -------------------------------------------------------------------------------- /yuwuwu-cli/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "yuwuwu-cli", 3 | "version": "1.0.3", 4 | "description": "", 5 | "main": "index.js", 6 | "directories": { 7 | "test": "test" 8 | }, 9 | "scripts": { 10 | "test": "echo \"Error: no test specified\" && exit 1" 11 | }, 12 | "bin": { 13 | "yuwuwu": "./bin/index.js" 14 | }, 15 | "author": "yuwuwu", 16 | "license": "ISC", 17 | "dependencies": { 18 | "chalk": "^2.3.0", 19 | "commander": "^2.11.0", 20 | "download-git-repo": "^3.0.2", 21 | "ejs": "^3.1.6", 22 | "execa": "^4.1.0", 23 | "inquirer": "^4.0.0", 24 | "ora": "^1.3.0", 25 | "prettier": "^2.5.1", 26 | "rimraf": "^3.0.2" 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /串行异步操作/index.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: yuyongxing 3 | * @Date: 2021-12-07 21:54:35 4 | * @LastEditors: yuyongxing 5 | * @LastEditTime: 2021-12-19 15:49:58 6 | * @Description: 7 | */ 8 | 9 | 10 | 11 | // callback方式 12 | 13 | // let callback1 = () => { 14 | // setTimeout(() => { 15 | // console.log("callback1") 16 | // callback2("callback1") 17 | // }, 1000); 18 | // } 19 | // let callback2 = (data) => { 20 | // setTimeout(() => { 21 | // console.log("callback2","传入的数据"+data) 22 | // }, 500); 23 | // } 24 | // callback1() 25 | 26 | 27 | // promise方式 28 | 29 | // let promise1 = () => new Promise((resolve, reject) => { 30 | // setTimeout(() => { 31 | // console.log("promise1") 32 | // resolve("promise1") 33 | // }, 2000); 34 | // }) 35 | // let promise2 = (data) => new Promise((resolve, reject) => { 36 | // setTimeout(() => { 37 | // console.log("promise2", "传入的数据" + data) 38 | // resolve() 39 | // }, 1500); 40 | // }) 41 | // promise1() 42 | // .then((res) => { 43 | // return promise2(res) 44 | // }) 45 | // .then(() => { 46 | // }) 47 | 48 | 49 | // generator方式 50 | 51 | // let generator1 = function () { 52 | // setTimeout(() => { 53 | // console.log("generator1") 54 | // it.next("generator1") 55 | // }, 2000); 56 | // } 57 | // let generator2 = function (data) { 58 | // setTimeout(() => { 59 | // console.log("generator2", "传入的数据" + data) 60 | // it.next() 61 | // }, 1500); 62 | // } 63 | // let generator = function* () { 64 | // let result = yield generator1() 65 | // yield generator2(result) 66 | // } 67 | // let it = generator() 68 | // it.next() 69 | 70 | 71 | // let co = require('co') 72 | // let generator3 = () => new Promise((resolve, reject) => { 73 | // setTimeout(() => { 74 | // console.log("generator3") 75 | // resolve("generator3") 76 | // }, 2000); 77 | // }) 78 | // let generator4 = (data) => new Promise((resolve, reject) => { 79 | // setTimeout(() => { 80 | // console.log("generator4", "传入的数据" + data) 81 | // resolve("generator4") 82 | // }, 2000); 83 | // }) 84 | // let generatorByCo = function* () { 85 | // let result = yield generator3() 86 | // let result2 = yield generator4(result) 87 | // return result2 88 | // } 89 | // co(generatorByCo).then(res => { 90 | // console.log(res) 91 | // }) 92 | // 等同于 93 | // let itByCo = generatorByCo() 94 | // itByCo.next().value.then(res=>{ 95 | // itByCo.next(res).value.then(res=>{ 96 | // let data = itByCo.next(res).value 97 | // }) 98 | // }) 99 | 100 | 101 | // async/await方式 102 | 103 | // let asyncAwait1 = () => new Promise((resolve, reject) => { 104 | // setTimeout(() => { 105 | // console.log("asyncAwait1") 106 | // resolve("asyncAwait1") 107 | // }, 1000); 108 | // }) 109 | // let asyncAwait2 = (data) => new Promise((resolve, reject) => { 110 | // setTimeout(() => { 111 | // console.log("asyncAwait2", "传入的数据" + data) 112 | // resolve() 113 | // }, 1000); 114 | // }) 115 | // async function async() { 116 | // let result = await asyncAwait1() 117 | // await asyncAwait2(result) 118 | // } 119 | // async() 120 | 121 | 122 | // 事件监听方式 123 | let events = require("events") 124 | let emitter = new events.EventEmitter() 125 | let event1 = () => { 126 | setTimeout(() => { 127 | console.log("event1") 128 | emitter.emit("end","event1") 129 | }, 1000); 130 | } 131 | let event2 = (data) => { 132 | setTimeout(() => { 133 | console.log("event2", "传入的数据" + data) 134 | }, 1000); 135 | } 136 | emitter.on("end",event2) 137 | event1() 138 | -------------------------------------------------------------------------------- /查询佳能是否补货脚本/README.md: -------------------------------------------------------------------------------- 1 | 9 | 10 | # 查询淘宝商品是否补货脚本 11 | 12 | ## 功能 13 | 14 | 1.对于加密做的不够好的接口直接模拟接口请求,获取商品的库存信息。 2.针对淘宝商品使用无头浏览器加载对应的商品详情页,然后根据按钮状态判断是否补货。 15 | 16 | ## 运行 17 | 18 | 注:项目里包含 project.config.js 文件,因为是个人的敏感信息,所以从 git 中过滤掉了,使用时需要自己添加 project.config.js 文件。 19 | 20 | ``` 21 | npm install 22 | npm run dev:wx //通过api获取商品信息 23 | npm run dev:tb //通过无头浏览器获取商品信息 24 | ``` 25 | 26 | ``` 27 | // project.config.js 28 | module.exports = { 29 | emailConfig: { 30 | user: 发送邮件的邮箱账号, 31 | pass: 发送邮件的邮箱密钥, 32 | to: 接收邮件的邮箱账号, 33 | }, 34 | wxConfig: { 35 | token: token, 36 | gate_token: gete_token, 37 | uid: uid, 38 | }, 39 | }; 40 | 41 | 42 | ``` 43 | -------------------------------------------------------------------------------- /查询佳能是否补货脚本/index_tb.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: yuwuwu 3 | * @Date: 2024-06-25 15:28:06 4 | * @LastEditors: yuwuwu 5 | * @LastEditTime: 2024-06-26 17:33:50 6 | * @FilePath: /查询淘宝商品是否补货脚本/index_tb.js 7 | * @Description: 8 | */ 9 | 10 | const getTbGoods = require("./src/getGoodsByTb.js"); 11 | const sendEmail = require("./src/sendEmail.js"); 12 | 13 | 14 | const tb_goods_url = [ 15 | { url: "https://detail.tmall.com/item.htm?id=677388240047", title: "R10" }, 16 | { url: "https://detail.tmall.com/item.htm?id=702916527846", title: "R50" }, 17 | // { url: "https://detail.tmall.com/item.htm?id=623306082845", title: "R5" }, 18 | ]; 19 | 20 | 21 | const start = async () => { 22 | const tb_goods = await getTbGoods(tb_goods_url); 23 | console.log(tb_goods); 24 | let tb_text = ""; 25 | let isError = false; 26 | tb_goods.forEach((item) => { 27 | if (item.error) isError = true; 28 | if (!item.disabled) { 29 | tb_text += `【${item.title}】 按钮状态:${item.text}\n`; 30 | } 31 | }); 32 | if (isError) { 33 | await sendEmail("淘宝商品查询出错了", tb_text); 34 | } else if (!isError && tb_text.length > 0) { 35 | await sendEmail("淘宝商品可能补货", tb_text); 36 | } 37 | }; 38 | 39 | start(); 40 | -------------------------------------------------------------------------------- /查询佳能是否补货脚本/index_wx.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: yuwuwu 3 | * @Date: 2024-06-17 17:27:34 4 | * @LastEditors: yuwuwu 5 | * @LastEditTime: 2024-07-17 15:03:53 6 | * @FilePath: /markdown-code/查询淘宝商品是否补货脚本/index_wx.js 7 | * @Description: 8 | */ 9 | const getWxGoods = require('./src/getGoodsByWx.js'); 10 | const sendEmail = require('./src/sendEmail.js'); 11 | 12 | const wx_r10_sku_list = ['3020', '3021', '3024', '3025', '3390']; 13 | // const wx_r10_sku_list = ['3127', '3409', '3410']; 14 | 15 | const start = async () => { 16 | const wx_goods = await getWxGoods(wx_r10_sku_list); 17 | let wx_text = ''; 18 | let isError = false; 19 | wx_goods.forEach((item) => { 20 | if (!item.isSuccess) isError = true; 21 | if (item.hasStock) { 22 | wx_text += `【${item.title}】\n`; 23 | } 24 | }); 25 | if (isError) { 26 | await sendEmail('出错了', wx_text); 27 | } else if (!isError && wx_text.length > 0) { 28 | await sendEmail('商品补货提醒', wx_text); 29 | } 30 | console.log(wx_goods); 31 | console.log(wx_text); 32 | return JSON.stringify(wx_goods); 33 | }; 34 | 35 | start(); 36 | -------------------------------------------------------------------------------- /查询佳能是否补货脚本/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "get_inventory", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "dev:wx": "nodemon index_wx.js", 8 | "dev:tb": "nodemon index_tb.js", 9 | "getGoods": "cd src/filterResult && node index.js", 10 | "test": "echo \"Error: no test specified\" && exit 1" 11 | }, 12 | "author": "", 13 | "license": "ISC", 14 | "dependencies": { 15 | "axios": "^1.7.2", 16 | "nodemailer": "^6.9.13", 17 | "nodemon": "^3.1.3", 18 | "puppeteer": "^10.0.0", 19 | "qs": "^6.13.1" 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /查询佳能是否补货脚本/src/filterResult/getGoodsInfoBySku.js: -------------------------------------------------------------------------------- 1 | const axios = require('axios'); 2 | const qs = require('qs'); 3 | const { getTimestamp } = require('../utils'); 4 | const { wxConfig } = require('../../project.config.js'); 5 | 6 | const getGoodsBySku = async (sku) => { 7 | const { data } = await axios({ 8 | method: 'GET', 9 | url: `https://shop.canon.com.cn/jiekec/index.php?route=mini/catalog/product/productinfo&s_channel=&b_channel=×tamp=${Date.now()}&gate_token=d0bf96cd5ce5c513ddae72a2d1a88ae7&product_id=${sku}`, 10 | headers: { 11 | Host: 'shop.canon.com.cn', 12 | token: wxConfig.token, 13 | Host: 'shop.canon.com.cn', 14 | 'content-type': 'application/x-www-form-urlencoded', 15 | source: 'wx_mini', 16 | 'User-Agent': 17 | 'Mozilla/5.0 (iPhone; CPU iPhone OS 17_5_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148 MicroMessenger/8.0.49(0x18003135) NetType/WIFI Language/zh_CN', 18 | Referer: 19 | 'https://servicewechat.com/wxd3d8769854ba9cd1/70/page-frame.html', 20 | }, 21 | }); 22 | return data; 23 | }; 24 | const checkCode = async (code) => { 25 | const { data } = await axios({ 26 | method: 'post', 27 | url: `https://shop.canon.com.cn/jiekec/index.php?route=mini/checkout/order/shoppingcodeinfo`, 28 | headers: { 29 | Host: 'shop.canon.com.cn', 30 | referer: 31 | 'https://servicewechat.com/wxd3d8769854ba9cd1/72/page-frame.html', 32 | xweb_xhr: '1', 33 | source: 'wx_mini', 34 | 'user-agent': 35 | 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/98.0.4758.102 Safari/537.36 MicroMessenger/6.8.0(0x16080000) NetType/WIFI MiniProgramEnv/Mac MacWechat/WMPF XWEB/30626', 36 | token: wxConfig.token, 37 | Accept: '*/*', 38 | 'Sec-Fetch-Site': 'cross-site', 39 | 'Sec-Fetch-Mode': 'cors', 40 | 'Sec-Fetch-Dest': 'empty', 41 | 'Accept-Language': 'zh-CN,zh', 42 | 'Content-Type': 'application/x-www-form-urlencoded', 43 | Cookie: wxConfig.cookie, 44 | }, 45 | data: qs.stringify({ 46 | code: code, 47 | s_channel: '', 48 | b_channel: '', 49 | timestamp: getTimestamp(), 50 | gate_token: wxConfig.gate_token, 51 | code: code, 52 | uid: wxConfig.uid, 53 | token: wxConfig.token, 54 | gate_id: 'MINIGATE', 55 | verifycode: 'yes', 56 | }), 57 | }); 58 | return data; 59 | }; 60 | module.exports = { 61 | getGoodsBySku, 62 | checkCode, 63 | }; 64 | -------------------------------------------------------------------------------- /查询佳能是否补货脚本/src/filterResult/index.js: -------------------------------------------------------------------------------- 1 | const { getGoodsBySku } = require('./getGoodsInfoBySku'); 2 | const { writeToFile, waitTime } = require('../utils'); 3 | 4 | const start = async () => { 5 | for (let i = 3000; i <= 5000; i++) { 6 | try { 7 | if (i % 50 == 0) { 8 | await waitTime(5000); 9 | } else { 10 | await waitTime(2000); 11 | } 12 | const result = await getGoodsBySku(i); 13 | console.log(result?.data?.title, i, result?.data?.quantity); 14 | if (result.code == 1000 && result?.data?.title?.includes('AD-E1')) { 15 | writeToFile(result); 16 | } 17 | } catch (error) { 18 | console.log(i, '错误'); 19 | await waitTime(10000); 20 | } 21 | } 22 | }; 23 | start(); 24 | -------------------------------------------------------------------------------- /查询佳能是否补货脚本/src/filterResult/处理后的数据.json: -------------------------------------------------------------------------------- 1 | { 2 | "code": 1000, 3 | "info": "catalog.product.success", 4 | "data": { 5 | "product_id": "2930", 6 | "title": "多功能靴适配器AD-E1", 7 | "brief": "相机:具备多功能靴的EOS机型、EOS R5 C除外 闪光灯相关:EL-1 / 600EX II-RT / 600EX-RT / 580EX II / ST-E3 / OC-E3", 8 | "image": "https://shop.canon.com.cn/image/catalog/AD-E1.jpg", 9 | "spu": "", 10 | "spu_id": "0", 11 | "sku": "", 12 | "isnew": "0", 13 | "ishot": "0", 14 | "rawprice": 309, 15 | "price": 309, 16 | "weight": "0.00000000", 17 | "quantity": "0", 18 | "tags": [], 19 | "original_website_url": "", 20 | "content_url_selected": "1", 21 | "content_url": "/ADE102/index.html", 22 | "attribute_url": "/ADE102/spec.html", 23 | "content": "", 24 | "content2": "", 25 | "status": 1, 26 | "keywords": "", 27 | "description": "", 28 | "grouppriceconfig": "[]", 29 | "imagelist": [ 30 | "https://shop.canon.com.cn/image/catalog/AD-E1.jpg", 31 | "https://shop.canon.com.cn/image/catalog/AD-E10.jpg" 32 | ], 33 | "skulist": "", 34 | "iswishlist": false, 35 | "categorylist": [ 36 | { 37 | "category_id": "59", 38 | "title": "EOS单反/微单相机", 39 | "parent_id": "0" 40 | }, 41 | { 42 | "category_id": "129", 43 | "title": "EOS数码相机附件", 44 | "parent_id": "59" 45 | } 46 | ], 47 | "presentlist": [], 48 | "carelist": [], 49 | "isspecialproduct": false, 50 | "installment_price": [], 51 | "relatedlist": [], 52 | "recommendlist": [ 53 | { 54 | "product_id": "1662", 55 | "title": "佳能闪光灯信号发射器 ST-E3-RT", 56 | "brief": "", 57 | "image": "https://shop.canon.com.cn/image/catalog/10.25/-ST-E3-RT.jpg", 58 | "spu": "", 59 | "sku": "佳能闪光灯信号发射器 ST-E3-RT", 60 | "isnew": "0", 61 | "ishot": "0", 62 | "rawprice": 2099, 63 | "price": 2099, 64 | "weight": "0.00000000", 65 | "quantity": "0", 66 | "tags": "", 67 | "original_website_url": "", 68 | "content_url_selected": "1", 69 | "content_url": "/ST-E3-RT/index.html", 70 | "attribute_url": "", 71 | "content": "", 72 | "content2": "", 73 | "status": "1", 74 | "purchase_number_limit": "1", 75 | "purchase_limit_range": "10", 76 | "isspecialproduct": false 77 | }, 78 | { 79 | "product_id": "2634", 80 | "title": "闪光灯 SPEEDLITE EL-1旧", 81 | "brief": "专业级红线外接闪光灯,强悍而细腻的专业之选", 82 | "image": "https://shop.canon.com.cn/image/catalog/SPEEDLITE-EL-1000.jpg", 83 | "spu": "", 84 | "sku": "", 85 | "isnew": "0", 86 | "ishot": "0", 87 | "rawprice": 7899, 88 | "price": 7399, 89 | "weight": "0.00000000", 90 | "quantity": "0", 91 | "tags": "", 92 | "original_website_url": "http://www.canon.com.cn/product/speedliteel1/", 93 | "content_url_selected": "1", 94 | "content_url": "/shanguangEL0205/index.html", 95 | "attribute_url": "/shanguangEL0205/spec.html", 96 | "content": "", 97 | "content2": "", 98 | "status": "0", 99 | "purchase_number_limit": "1", 100 | "purchase_limit_range": "180", 101 | "isspecialproduct": false 102 | }, 103 | { 104 | "product_id": "1315", 105 | "title": "闪光灯 Speedlite 600EX II-RT", 106 | "brief": "", 107 | "image": "https://shop.canon.com.cn/image/catalog/product/Speedlite-600EX1.png", 108 | "spu": "12163", 109 | "sku": "闪光灯 Speedlite 600EX II-RT", 110 | "isnew": "0", 111 | "ishot": "0", 112 | "rawprice": 3599, 113 | "price": 3599, 114 | "weight": "0.00000000", 115 | "quantity": "0", 116 | "tags": "", 117 | "original_website_url": "http://www.canon.com.cn/product/speedlite600exiirt/", 118 | "content_url_selected": "1", 119 | "content_url": "/speedlite600exiirt0615A/index.html", 120 | "attribute_url": "/speedlite600exiirt0615A/spec.html", 121 | "content": "", 122 | "content2": "", 123 | "status": "1", 124 | "purchase_number_limit": "1", 125 | "purchase_limit_range": "180", 126 | "isspecialproduct": false 127 | }, 128 | { 129 | "product_id": "1324", 130 | "title": "离机热靴连线 OC-E3", 131 | "brief": "", 132 | "image": "https://shop.canon.com.cn/image/catalog/product/-OC-E3.png", 133 | "spu": "12175", 134 | "sku": "离机热靴连线 OC-E3", 135 | "isnew": "0", 136 | "ishot": "0", 137 | "rawprice": 499, 138 | "price": 499, 139 | "weight": "0.00000000", 140 | "quantity": "0", 141 | "tags": "", 142 | "original_website_url": "", 143 | "content_url_selected": "1", 144 | "content_url": "/OCE3/index.html", 145 | "attribute_url": "", 146 | "content": "", 147 | "content2": "", 148 | "status": "0", 149 | "purchase_number_limit": "1000", 150 | "purchase_limit_range": "30", 151 | "isspecialproduct": false 152 | } 153 | ], 154 | "groupbuyproductlist": [] 155 | } 156 | } -------------------------------------------------------------------------------- /查询佳能是否补货脚本/src/getGoodsByTb.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: yuwuwu 3 | * @Date: 2024-06-18 16:32:53 4 | * @LastEditors: yuwuwu 5 | * @LastEditTime: 2024-06-26 17:32:31 6 | * @FilePath: /查询淘宝商品是否补货脚本/src/getGoodsByTb.js 7 | * @Description: 获取淘宝商城商品库存 8 | */ 9 | const puppeteer = require("puppeteer"); 10 | 11 | const waitTime = (n) => new Promise((r) => setTimeout(r, n)); 12 | const getTbGoods = async (list = []) => { 13 | const browser = await puppeteer.launch({ 14 | headless: true, //使无头浏览器可见,便于开发过程中观察 15 | devtools: true, // 启动浏览器时默认打开开发者工具控制台 16 | ignoreHTTPSErrors: true, //忽略https错误 17 | defaultViewport: null, //默认视窗大小 18 | slowMo: 100, //慢速模式,模拟人类操作 19 | args: [ 20 | "--disable-infobars", 21 | "--no-zygote", 22 | "--no-sandbox", 23 | "--disable-gpu", 24 | "--no-first-run", 25 | "--single-process", 26 | "--disable-extensions", 27 | "--disable-xss-auditor", 28 | "--disable-dev-shm-usage", 29 | "--disable-popup-blocking", 30 | "--disable-setuid-sandbox", 31 | "--disable-accelerated-2d-canvas", 32 | "--enable-features=NetworkService", 33 | ], 34 | }); 35 | 36 | const getResult = async () => { 37 | const result = []; 38 | for (let el of list) { 39 | const page = await browser.newPage(); //打开新的空白页 40 | await page.goto(el.url, { 41 | waitUntil: "domcontentloaded", 42 | }); //访问页面 43 | await waitTime(1500); 44 | const hasStock = await page.evaluate((el) => { 45 | console.log(el, "el"); 46 | Object.defineProperty(navigator, "webdriver", { get: () => false }); 47 | const loginDom = document.querySelector(".baxia-dialog"); 48 | if (loginDom) { 49 | loginDom.style.display = "none"; 50 | } 51 | const divList = document.querySelectorAll("div"); 52 | let buttonDom = null; 53 | for (let element of divList) { 54 | if (element.className.includes("Actions--leftButtons")) { 55 | buttonDom = element.childNodes[0]; 56 | } 57 | } 58 | if (buttonDom) { 59 | return { 60 | error: false, 61 | text: buttonDom.textContent, 62 | disabled: buttonDom.className.includes("disabled"), 63 | title: el.title, 64 | }; 65 | } 66 | return { 67 | error: true, 68 | title: el.title, 69 | }; 70 | }, el); 71 | result.push(hasStock); 72 | } 73 | // await browser.close(); 74 | return result; 75 | }; 76 | return await getResult(); 77 | }; 78 | module.exports = getTbGoods; 79 | -------------------------------------------------------------------------------- /查询佳能是否补货脚本/src/getGoodsByWx.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: yuwuwu 3 | * @Date: 2024-06-18 18:19:12 4 | * @LastEditors: yuwuwu 5 | * @LastEditTime: 2024-07-17 11:33:55 6 | * @FilePath: /markdown-code/查询淘宝商品是否补货脚本/src/getGoodsByWx.js 7 | * @Description:查询小程序商城是否有货,有货自动下单 8 | */ 9 | 10 | const request = require('./request.js'); 11 | const { wxConfig } = require('../project.config.js'); 12 | const sendEmail = require('./sendEmail.js'); 13 | 14 | const getTimestamp = () => Date.now(); 15 | const goodsBaseUrl = ''; 16 | 17 | // 预下单 18 | const buyGoods = async (sku) => { 19 | const url = `https://shop.canon.com.cn/jiekec/index.php?route=mini/checkout/buy/product`; 20 | const { data } = await request({ 21 | method: 'post', 22 | url, 23 | data: { 24 | s_channel: '', 25 | b_channel: '', 26 | timestamp: getTimestamp(), 27 | gate_token: wxConfig.gate_token, 28 | installment_count: 0, 29 | productinfo: `${sku}-1`, 30 | careinfo: `${sku}-0`, 31 | uid: wxConfig.uid, 32 | token: wxConfig.token, 33 | gate_id: 'MINIGATE', 34 | }, 35 | }); 36 | console.log('预下单', data); 37 | return data; 38 | }; 39 | // 确认下单 40 | const confirmBuyGoods = async (sku) => { 41 | const url = `https://shop.canon.com.cn/jiekec/index.php?route=mini/checkout/buy/confirm`; 42 | const { data } = await request({ 43 | method: 'post', 44 | url, 45 | data: { 46 | s_channel: '', 47 | b_channel: '', 48 | timestamp: getTimestamp(), 49 | gate_token: wxConfig.gate_token, 50 | installment_count: 0, 51 | productinfo: `${sku}-1`, 52 | careinfo: `${sku}-0`, 53 | payment_method: 'weixin', 54 | address_id: '199326', 55 | invoice_id: undefined, 56 | coupon_id: 0, 57 | uid: wxConfig.uid, 58 | token: wxConfig.token, 59 | gate_id: 'MINIGATE', 60 | }, 61 | }); 62 | console.log('确认下单', data); 63 | return data; 64 | }; 65 | // 获取商品有无库存 66 | const getWxGoods = async (skuList) => { 67 | const result = []; 68 | try { 69 | for (let sku of skuList) { 70 | const url = `https://shop.canon.com.cn/jiekec/index.php?route=mini/catalog/product/productinfo&s_channel=&b_channel=×tamp=${getTimestamp}&gate_token=${wxConfig.gate_token}&product_id=${sku}`; 71 | const { data } = await request({ 72 | method: 'get', 73 | url, 74 | }); 75 | result.push({ 76 | isSuccess: data.code === 1000, 77 | hasStock: data.data.quantity != '0', 78 | title: data.code === 1000 ? data.data.title : JSON.stringify(data), 79 | }); 80 | if ( 81 | data.code === 1000 && 82 | data.data.quantity !== '0' && 83 | data.data.status 84 | ) { 85 | const buyRes = await buyGoods(sku); 86 | if (buyRes.code === 1000) { 87 | const confirmRes = await confirmBuyGoods(sku); 88 | if (confirmRes.code === 1000) { 89 | await sendEmail('下单成功', ''); 90 | } 91 | } 92 | } 93 | } 94 | } catch (error) { 95 | console.log(error, 'error'); 96 | result.push({ 97 | isSuccess: false, 98 | hasStock: false, 99 | title: String(error), 100 | }); 101 | } 102 | 103 | return result; 104 | }; 105 | 106 | module.exports = getWxGoods; 107 | -------------------------------------------------------------------------------- /查询佳能是否补货脚本/src/request.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: yuwuwu 3 | * @Date: 2024-06-20 17:56:46 4 | * @LastEditors: yuwuwu 5 | * @LastEditTime: 2024-06-20 18:47:58 6 | * @FilePath: /markdown-code/查询淘宝商品是否补货脚本/src/request.js 7 | * @Description: 8 | */ 9 | const axios = require("axios"); 10 | const { wxConfig } = require("../project.config.js"); 11 | 12 | const request = axios.create({ 13 | headers: { 14 | Host: "shop.canon.com.cn", 15 | token: wxConfig.token, 16 | "content-type": "application/x-www-form-urlencoded", 17 | source: "wx_mini", 18 | "User-Agent": 19 | "Mozilla/5.0 (iPhone; CPU iPhone OS 17_5_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148 MicroMessenger/8.0.49(0x18003135) NetType/WIFI Language/zh_CN", 20 | Referer: "https://servicewechat.com/wxd3d8769854ba9cd1/70/page-frame.html", 21 | }, 22 | }); 23 | 24 | module.exports = request; 25 | -------------------------------------------------------------------------------- /查询佳能是否补货脚本/src/sendEmail.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: yuwuwu 3 | * @Date: 2024-06-18 20:42:07 4 | * @LastEditors: yuwuwu 5 | * @LastEditTime: 2024-07-17 11:26:38 6 | * @FilePath: /markdown-code/查询淘宝商品是否补货脚本/src/sendEmail.js 7 | * @Description: 发送邮件 8 | */ 9 | const nodeMailer = require('nodemailer'); 10 | const { emailConfig } = require('../project.config.js'); 11 | 12 | const transporter = nodeMailer.createTransport({ 13 | service: '163', 14 | auth: { 15 | user: emailConfig.user, 16 | pass: emailConfig.pass, 17 | }, 18 | }); 19 | const sendEmail = async (title = '补货啦', text = '') => { 20 | await transporter.sendMail({ 21 | from: emailConfig.user, 22 | to: emailConfig.to, 23 | subject: title, 24 | text, 25 | }); 26 | return true; 27 | }; 28 | module.exports = sendEmail; 29 | -------------------------------------------------------------------------------- /查询佳能是否补货脚本/src/utils.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs'); 2 | 3 | /** 4 | * 判断文件是否存在 5 | * @param {*} fileName 6 | * @returns 7 | */ 8 | const accessFile = async (fileName) => { 9 | try { 10 | await fs.promises.access(fileName); 11 | return true; 12 | } catch (error) { 13 | return false; 14 | } 15 | }; 16 | /** 17 | * 删除文件 18 | * @param {*} fileName 19 | */ 20 | const deleteFile = async (fileName) => { 21 | try { 22 | await fs.promises.unlink(fileName); 23 | console.log('文件删除成功:', fileName); 24 | } catch (error) { 25 | console.error(`文件删除失败:`, error); 26 | } 27 | }; 28 | /** 29 | * 写入文件 30 | * @param {*} data 31 | * @param {*} fileName 32 | */ 33 | const writeToFile = async (data, fileName = '处理后的数据.json') => { 34 | try { 35 | const exist = await accessFile(fileName); 36 | if (exist) { 37 | await fs.promises.appendFile( 38 | fileName, 39 | `,${JSON.stringify(data, null, 2)}` 40 | ); 41 | console.log('文件追加写入成功:'); 42 | } else { 43 | await fs.promises.writeFile(fileName, JSON.stringify(data, null, 2)); 44 | console.log('文件写入成功:'); 45 | } 46 | } catch (error) { 47 | console.error(`文件写入失败:`); 48 | } 49 | }; 50 | /** 51 | * 等待代码延时 52 | * @param {} n 53 | * @returns 54 | */ 55 | const waitTime = (n = 1000) => new Promise((r) => setTimeout(r, n)); 56 | /* 57 | * 生成随机字符串 58 | * @param {number} length 59 | * @returns {string} 60 | */ 61 | const generateRandomString = (length = 10) => { 62 | const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'; 63 | let result = ''; 64 | for (let i = 0; i < length; i++) { 65 | const randomIndex = Math.floor(Math.random() * characters.length); 66 | result += characters.charAt(randomIndex); 67 | } 68 | return result; 69 | }; 70 | /** 71 | * 获取当前时间戳 72 | * @returns {number} 73 | */ 74 | const getTimestamp = () => Date.now(); 75 | module.exports = { 76 | writeToFile, 77 | deleteFile, 78 | waitTime, 79 | generateRandomString, 80 | getTimestamp, 81 | }; 82 | -------------------------------------------------------------------------------- /离线缓存Server Worker/demo.html: -------------------------------------------------------------------------------- 1 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | Document 16 | 17 | 18 | 19 | 20 | 21 |
这是一串文字
22 |
23 | 42 | 56 | 57 | 58 | -------------------------------------------------------------------------------- /离线缓存Server Worker/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yuwuwu/blog-code/5477dda5b564fbb50de555fd869731a70befcc35/离线缓存Server Worker/favicon.ico -------------------------------------------------------------------------------- /离线缓存Server Worker/img/t.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yuwuwu/blog-code/5477dda5b564fbb50de555fd869731a70befcc35/离线缓存Server Worker/img/t.jpeg -------------------------------------------------------------------------------- /离线缓存Server Worker/sw.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: yuyongxing 3 | * @Date: 2021-08-30 17:36:41 4 | * @LastEditors: yuyongxing 5 | * @LastEditTime: 2021-08-31 20:09:01 6 | * @Description: 7 | */ 8 | // https://zhuanlan.zhihu.com/p/29869709 9 | // https://www.cnblogs.com/violinux/p/10249515.html 更新 10 | // http://help.z01.com/Item/1298 更新 11 | var verson = "v1" 12 | self.addEventListener('install', event => { 13 | console.log("install") 14 | this.skipWaiting() 15 | }) 16 | self.addEventListener('activate', event => { 17 | console.log("activate") 18 | caches.open(verson).then(cache => { 19 | return cache.addAll(['demo.html', 'js/jqurey.js', 'https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/154cd131b76e431897c2c04af97880df~tplv-k3u1fbpfcp-watermark.image']) 20 | }) 21 | var delFn = caches.keys().then(function (cacheList) { 22 | return Promise.all( 23 | cacheList.map(function (cacheName) { 24 | if (cacheName !== verson) { 25 | return caches.delete(cacheName); 26 | } 27 | }) 28 | ); 29 | }) 30 | event.waitUntil(Promise.all([delFn]) 31 | .then(() => { 32 | return self.clients.claim() 33 | }) 34 | ) 35 | }); 36 | self.addEventListener('fetch', function (event) { 37 | console.log("fetch",event.request.url) 38 | event.respondWith( 39 | caches.match(event.request).then(function (response) { 40 | if (response) { 41 | return response 42 | } 43 | return fetch(event.request) 44 | }) 45 | ) 46 | }) 47 | // self.addEventListener('fetch', function (event) { 48 | // console.log("fetch", event.request.url) 49 | // event.respondWith( 50 | // caches.match(event.request).then(function (response) { 51 | // if (response) { 52 | // return response; 53 | // } 54 | // var request = event.request.clone(); 55 | // // if (request.mode !== 'navigate' && request.url.indexOf(request.referrer) === -1) { 56 | // // request = new Request(request, { mode: 'no-cors' }) 57 | // // } 58 | 59 | // return fetch(request).then(function (httpRes) { 60 | // //请求失败了则直接返回、对于post请求也直接返回,sw不能缓存post请求 61 | // if (!httpRes || (httpRes.status !== 200 && httpRes.status !== 304 && httpRes.type !== 'opaque') || request.method === 'POST') { 62 | // return httpRes; 63 | // } 64 | 65 | // // 请求成功的话,将请求缓存起来。 66 | // var responseClone = httpRes.clone(); 67 | // caches.open(verson).then(function (cache) { 68 | // cache.put(event.request, responseClone); 69 | // }); 70 | // return httpRes; 71 | // }); 72 | // }) 73 | // ); 74 | // }); 75 | -------------------------------------------------------------------------------- /红包雨/images/bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yuwuwu/blog-code/5477dda5b564fbb50de555fd869731a70befcc35/红包雨/images/bg.png -------------------------------------------------------------------------------- /红包雨/images/red.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yuwuwu/blog-code/5477dda5b564fbb50de555fd869731a70befcc35/红包雨/images/red.png -------------------------------------------------------------------------------- /红包雨/images/s-bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yuwuwu/blog-code/5477dda5b564fbb50de555fd869731a70befcc35/红包雨/images/s-bg.png -------------------------------------------------------------------------------- /红包雨/index.html: -------------------------------------------------------------------------------- 1 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | Document 20 | 21 | 22 | 23 | 86 | 87 | 88 | 89 | 90 | 91 | 92 |
93 | 开始 94 |
95 |
剩余时间
15
s
96 | 97 | 98 | 99 | 143 | 144 | 145 | -------------------------------------------------------------------------------- /红包雨/js/RedPacketGame.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: yuyongxing 3 | * @Date: 2022-01-20 17:16:48 4 | * @LastEditors: yuyongxing 5 | * @LastEditTime: 2022-02-17 23:05:19 6 | * @Description:红包雨游戏类 7 | */ 8 | class RedPacketGame { 9 | constructor(opt) { 10 | this.width = opt.width 11 | this.height = opt.height 12 | this.targerId = opt.targerId 13 | this.ctx = this.setCanvas() 14 | this.image = opt.image 15 | this.redPacketImg = this.setImage() 16 | this.isIng = false 17 | this.timer = null 18 | this.moveTimer = null 19 | this.redPackets = [] 20 | this.clicks = [] 21 | this.ponitXs = [] 22 | } 23 | setImage() { 24 | const img = new Image() 25 | img.src = this.image 26 | return img 27 | } 28 | setCanvas() { 29 | const canvas = document.getElementById(this.targerId) 30 | canvas.addEventListener('click', this.handleClick.bind(this)) 31 | canvas.width = this.width 32 | canvas.height = this.height 33 | return canvas.getContext("2d") 34 | } 35 | // 设置每一列的起点 36 | setColXs() { 37 | let arr = [], step = Math.floor((this.width - 20) / 60) 38 | for (let i = 0; i < step; i++) { 39 | arr.push(10 + 60 * i) 40 | } 41 | return arr 42 | } 43 | // 打乱数组 44 | sortArr(arr) { 45 | for (let i = 0, len = arr.length; i < len; i++) { 46 | const curRandom = parseInt(Math.random() * (len - 1)); 47 | const cur = arr[i]; 48 | arr[i] = arr[curRandom]; 49 | arr[curRandom] = cur; 50 | } 51 | return arr; 52 | } 53 | // 获取x坐标 54 | getPointX() { 55 | if (this.ponitXs.length == 0) { 56 | let arr = [], step = Math.floor((this.width - 20) / 60) 57 | for (let i = 0; i < step; i++) { 58 | arr.push(10 + 60 * i) 59 | } 60 | this.ponitXs = this.sortArr(arr) 61 | } 62 | let x = this.ponitXs[0] 63 | this.ponitXs.splice(0, 1) 64 | return x 65 | } 66 | // 开始执行动画 67 | start() { 68 | if (this.isIng) return 69 | this.isIng = true 70 | this.clicks = [] 71 | this.redPacketMove() 72 | console.log(this.redPackets) 73 | } 74 | // 结束执行动画 75 | end() { 76 | this.redPackets = [] 77 | this.isIng = false 78 | this.timer && clearInterval(this.timer) 79 | this.moveTimer && window.cancelAnimationFrame(this.moveTimer) 80 | this.ctx.clearRect(0, 0, this.width, this.height); 81 | } 82 | // 点击事件,获取被点击的红包 83 | handleClick(e) { 84 | e.preventDefault && e.preventDefault() 85 | if (!this.isIng) return 86 | const pos = { 87 | x: e.clientX, 88 | y: e.clientY 89 | } 90 | for (let i = 0, length = this.redPackets.length; i < length; i++) { 91 | const redPacket = this.redPackets[i] 92 | // 点击的x坐标大于区域的x坐标,并且小于x+width 93 | // 并且点击的y坐标大于区域的y坐标,并且小于y+height 94 | if ( 95 | pos.x >= redPacket.x && pos.x - redPacket.x <= redPacket.w && 96 | pos.y >= redPacket.y && pos.y - redPacket.y <= redPacket.h 97 | ) { 98 | this.redPackets[i].isClick = true 99 | this.redPackets[i].clickY = redPacket.y 100 | this.clicks.push(this.redPackets[i]) 101 | break 102 | } 103 | } 104 | } 105 | // 创建红包元素 106 | createRedPacket(point) { 107 | point = point || 0 108 | this.redPackets.push(new RedPacket({ 109 | w: 60, 110 | h: 60, 111 | x: this.getPointX(), 112 | y: -60, 113 | step:1, 114 | image: this.redPacketImg, 115 | point: point 116 | })) 117 | } 118 | // 红包动画:先清空画布,在绘制一次 119 | redPacketMove() { 120 | this.ctx.clearRect(0, 0, this.width, this.height); 121 | for (let i = 0, length = this.redPackets.length; i < length; i++) { 122 | const redPacket = this.redPackets[i] 123 | if (redPacket.isClick) { 124 | // 分数向上动画 125 | redPacket.y = redPacket.y - redPacket.step 126 | if (redPacket.y < redPacket.clickY - 100) { 127 | this.redPackets.splice(i, 1) 128 | i-- 129 | length-- 130 | continue 131 | } 132 | this.ctx.font = "18px bold 黑体"; 133 | this.ctx.fillStyle = "#FFD442"; 134 | this.ctx.textAlign = "center"; 135 | this.ctx.textBaseline = "middle"; 136 | this.ctx.fillText("+" + redPacket.point, redPacket.x, redPacket.y) 137 | } else { 138 | // 红包向下动画 139 | redPacket.y = redPacket.y + redPacket.step 140 | if (redPacket.y >= this.height - redPacket.h) { 141 | this.redPackets.splice(i, 1) 142 | i-- 143 | length-- 144 | continue 145 | } 146 | this.ctx.drawImage(redPacket.image, redPacket.x, redPacket.y, redPacket.w, redPacket.h) 147 | } 148 | } 149 | // this.moveTimer && window.cancelAnimationFrame(this.moveTimer) 150 | this.moveTimer = window.requestAnimationFrame(this.redPacketMove.bind(this)) 151 | } 152 | // 生成min到max之间的随机数 153 | randomFn(min, max) { 154 | return parseInt(Math.random() * (max - min + 1) + min + '', 10) 155 | } 156 | } 157 | /** 158 | * 红包类:生成单个红包 159 | * w,h:宽高 160 | * x,y:坐标 161 | * point:积分 162 | * image:图片地址 163 | * step:速度 164 | * isclick:是否被点击了 165 | * clickY:被点击时的y坐标,用来计算显示的积分值什么位置消失 166 | */ 167 | class RedPacket { 168 | constructor(opt) { 169 | this.w = opt.w 170 | this.h = opt.h 171 | this.x = opt.x 172 | this.y = opt.y 173 | this.point = opt.point || 0 174 | this.image = opt.image 175 | this.step = opt.step 176 | this.isClick = false 177 | this.clickY = 0 178 | } 179 | } 180 | -------------------------------------------------------------------------------- /红包雨/js/rem.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: yuyongxing 3 | * @Date: 2021-10-19 14:30:43 4 | * @LastEditors: yuyongxing 5 | * @LastEditTime: 2021-10-19 14:36:30 6 | * @Description:自适应监测屏幕宽度 按照750的设计图,100px=1rem 7 | */ 8 | (function(doc, win) { 9 | var docEl = doc.documentElement; 10 | var resizeEvt = 'orientationchange' in window ? 'orientationchange' : 'resize'; 11 | var recalc = function() { 12 | var clientWidth = docEl.clientWidth; 13 | if (!clientWidth) return; 14 | if (clientWidth >= 750) { 15 | docEl.style.fontSize = '100px'; 16 | } else { 17 | docEl.style.fontSize = 100 * (clientWidth / 750) + 'px'; 18 | } 19 | }; 20 | 21 | if (!doc.addEventListener) return; 22 | win.addEventListener(resizeEvt, recalc, false); 23 | doc.addEventListener('DOMContentLoaded', recalc, false); 24 | })(document, window); 25 | -------------------------------------------------------------------------------- /红包雨/js/requestAnimationFrame.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: yuyongxing 3 | * @Date: 2022-02-22 23:10:56 4 | * @LastEditors: yuyongxing 5 | * @LastEditTime: 2022-02-22 23:21:11 6 | * @Description: requestAnimationFrame兼容 7 | */ 8 | (function() { 9 | var lastTime = 0; 10 | var vendors = ['webkit', 'moz']; 11 | for(var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) { 12 | window.requestAnimationFrame = window[vendors[x] + 'RequestAnimationFrame']; 13 | window.cancelAnimationFrame = window[vendors[x] + 'CancelAnimationFrame'] || window[vendors[x] + 'CancelRequestAnimationFrame']; 14 | } 15 | if(!window.requestAnimationFrame) { 16 | window.requestAnimationFrame = function(callback, element) { 17 | var currTime = new Date().getTime(); 18 | var timeToCall = Math.max(0, 16.7 - (currTime - lastTime)); 19 | var id = window.setTimeout(function() { 20 | callback(currTime + timeToCall); 21 | }, timeToCall); 22 | lastTime = currTime + timeToCall; 23 | return id; 24 | } 25 | } 26 | 27 | if(!window.cancelAnimationFrame) { 28 | window.cancelAnimationFrame = function(id) { 29 | clearTimeout(id); 30 | } 31 | } 32 | })(); -------------------------------------------------------------------------------- /红包雨/js/setRaf.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: yuyongxing 3 | * @Date: 2022-02-22 23:07:58 4 | * @LastEditors: yuyongxing 5 | * @LastEditTime: 2022-02-22 23:21:02 6 | * @Description: 高刷下重写requestAnimationFrame事件 7 | */ 8 | const getScreenFps = (() => { 9 | return (targetCount = 50) => { 10 | const beginDate = Date.now() 11 | let count = 0 12 | return new Promise(resolve => { 13 | (function fn() { 14 | window.requestAnimationFrame(() => { 15 | if (++count >= targetCount) { 16 | const diffDate = Date.now() - beginDate 17 | const fps = (count / diffDate) * 1000 18 | return resolve(fps) 19 | } 20 | fn() 21 | }) 22 | })() 23 | }) 24 | } 25 | })(); 26 | getScreenFps().then(fps => { 27 | if (fps > 70) { 28 | window.requestAnimationFrame = function (callback, element) { 29 | var currTime = new Date().getTime(); 30 | var timeToCall = Math.max(0, 16.7 - (currTime - lastTime)); 31 | var id = window.setTimeout(function () { 32 | callback(currTime + timeToCall); 33 | }, timeToCall); 34 | lastTime = currTime + timeToCall; 35 | return id; 36 | } 37 | window.cancelAnimationFrame = function (id) { 38 | clearTimeout(id); 39 | } 40 | } 41 | }) 42 | -------------------------------------------------------------------------------- /红包雨/js/utils.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: yuyongxing 3 | * @Date: 2022-01-17 18:05:32 4 | * @LastEditors: yuyongxing 5 | * @LastEditTime: 2022-02-22 23:21:25 6 | * @Description: 工具 7 | */ 8 | 9 | /** 10 | * count:要生成的数组长度 11 | * sum:生成的整数之和 12 | */ 13 | function getPointsByCount(count, sum) { 14 | return sortArr(randnum(count, sum)) 15 | } 16 | // 打乱数组 17 | function sortArr(arr) { 18 | for (let i = 0, len = arr.length; i < len; i++) { 19 | const curRandom = parseInt(Math.random() * (len - 1)); 20 | const cur = arr[i]; 21 | arr[i] = arr[curRandom]; 22 | arr[curRandom] = cur; 23 | } 24 | return arr; 25 | } 26 | // 生成n项和为max的数组 27 | function randnum(n, max) { 28 | function random(Min, Max) { 29 | if (Max > 5)Max = 5 30 | var Range = Max - Min; 31 | var Rand = Math.random(); 32 | return (Min + Math.round(Rand * Range)); 33 | } 34 | var arr = []; 35 | if (max > 0) { 36 | for (var i = 0; i < n; i++) { 37 | var num = 0; 38 | if (i === (n - 1)) { 39 | num = max; 40 | } else { 41 | if (max <= 0) { 42 | num = max = 0; 43 | } else { 44 | num = random(0, max); 45 | max -= num; 46 | } 47 | } 48 | arr.push(num); 49 | } 50 | } 51 | return arr; 52 | } 53 | -------------------------------------------------------------------------------- /自动签到脚本/index.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: yuyongxing 3 | * @Date: 2022-02-25 13:55:12 4 | * @LastEditors: yuwuwu 5 | * @LastEditTime: 2024-08-15 17:39:09 6 | * @Description: 7 | */ 8 | 9 | const nodeMailer = require('nodemailer'); 10 | const axios = require('axios'); 11 | const { userConfig, tos } = require('./project.config.js'); 12 | 13 | const transporter = nodeMailer.createTransport({ 14 | service: userConfig.service, 15 | auth: { 16 | user: userConfig.user, 17 | pass: userConfig.pass, 18 | }, 19 | }); 20 | 21 | // 签到 22 | const handleCheckIn = async (to) => { 23 | // console.log(to); 24 | let { data } = await axios({ 25 | url: `https://api.juejin.cn/growth_api/v1/check_in?aid=${to.aid}&uuid=${to.uuid}&spider=0&msToken=${to.msToken}&a_bogus=${to.a_bogus}`, 26 | method: 'post', 27 | data: '{}', 28 | headers: { 29 | cookie: to.cookie, 30 | origin: 'https://juejin.cn', 31 | referer: 'https://juejin.cn/', 32 | 'sec-ch-ua': 33 | '"Not)A;Brand";v="99", "Google Chrome";v="127", "Chromium";v="127"', 34 | 'sec-ch-ua-mobile': '?0', 35 | 'sec-ch-ua-platform': '"macOS"', 36 | 'sec-fetch-dest': 'empty', 37 | 'sec-fetch-mode': 'cors', 38 | 'sec-fetch-site': 'same-origin', 39 | 'user-agent': 40 | 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36', 41 | 'x-secsdk-csrf-token': 42 | '00010000000187c2f68fe0e28d9e05b01be8ccd29f21d1366734f094c53c64918dccef8358a517ebda42161b0419', 43 | 'accept-language': 'zh-CN,zh;q=0.9,en;q=0.8', 44 | 'content-type': 'application/json', 45 | }, 46 | }).catch((error) => { 47 | console.log(error); 48 | }); 49 | console.log(data); 50 | return data; 51 | }; 52 | // 免费抽奖 53 | const handleDraw = async (to) => { 54 | let { data } = await axios({ 55 | url: `https://api.juejin.cn/growth_api/v1/lottery/draw?aid=${to.aid}&uuid=${to.uuid}&spider=0&msToken=${to.msToken}&a_bogus=${to.a_bogus}`, 56 | method: 'post', 57 | data: '{}', 58 | headers: { 59 | cookie: to.cookie, 60 | origin: 'https://juejin.cn', 61 | referer: 'https://juejin.cn/', 62 | 'sec-ch-ua': 63 | '"Not)A;Brand";v="99", "Google Chrome";v="127", "Chromium";v="127"', 64 | 'sec-ch-ua-mobile': '?0', 65 | 'sec-ch-ua-platform': '"macOS"', 66 | 'sec-fetch-dest': 'empty', 67 | 'sec-fetch-mode': 'cors', 68 | 'sec-fetch-site': 'same-origin', 69 | 'user-agent': 70 | 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36', 71 | 'x-secsdk-csrf-token': 72 | '00010000000187c2f68fe0e28d9e05b01be8ccd29f21d1366734f094c53c64918dccef8358a517ebda42161b0419', 73 | 'accept-language': 'zh-CN,zh;q=0.9,en;q=0.8', 74 | 'content-type': 'application/json', 75 | }, 76 | }); 77 | console.log(data); 78 | return data; 79 | }; 80 | 81 | const sendEmail = (to, subject, text) => { 82 | transporter.sendMail({ from: userConfig.user, to, subject, text }, (err) => { 83 | if (err) { 84 | console.log(`发送邮件失败:${err}`); 85 | } 86 | }); 87 | }; 88 | const init = async () => { 89 | let title = ''; 90 | let text = ''; 91 | for (let i = 0, len = tos.length; i < len; i++) { 92 | let to = tos[i]; 93 | let checkIn_res = await handleCheckIn(to); 94 | let draw_res = await handleDraw(to); 95 | if (checkIn_res.err_no == 0 && draw_res.err_no == 0) { 96 | title = '签到、免费抽奖成功'; 97 | text = `签到成功,本次获得 ${checkIn_res.data.incr_point} 矿石;免费抽奖获得 ${draw_res.data.lottery_name};`; 98 | sendEmail(to.email, title, text); 99 | } else { 100 | title = '签到、免费抽奖失败'; 101 | text = ''; 102 | let map = [ 103 | { name: '签到', data: checkIn_res }, 104 | { name: '抽奖', data: draw_res }, 105 | ]; 106 | for (let j = 0; j < map.length; j++) { 107 | if (map[j].data.err_no != 0) { 108 | text += `${map[j].name}失败,错误原因为:${map[j].data.err_msg};`; 109 | } 110 | } 111 | console.log(text, to.email); 112 | sendEmail(to.email, title, text); 113 | } 114 | } 115 | }; 116 | init(); 117 | exports.todo = async () => { 118 | init(); 119 | }; 120 | -------------------------------------------------------------------------------- /自动签到脚本/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "auto_sign", 3 | "version": "1.0.0", 4 | "lockfileVersion": 3, 5 | "requires": true, 6 | "packages": { 7 | "": { 8 | "name": "auto_sign", 9 | "version": "1.0.0", 10 | "license": "ISC", 11 | "dependencies": { 12 | "axios": "^0.21.4", 13 | "nodemailer": "^6.7.2" 14 | } 15 | }, 16 | "node_modules/axios": { 17 | "version": "0.21.4", 18 | "resolved": "https://registry.npmmirror.com/axios/-/axios-0.21.4.tgz", 19 | "integrity": "sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==", 20 | "dependencies": { 21 | "follow-redirects": "^1.14.0" 22 | } 23 | }, 24 | "node_modules/follow-redirects": { 25 | "version": "1.15.6", 26 | "resolved": "https://registry.npmmirror.com/follow-redirects/-/follow-redirects-1.15.6.tgz", 27 | "integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==", 28 | "funding": [ 29 | { 30 | "type": "individual", 31 | "url": "https://github.com/sponsors/RubenVerborgh" 32 | } 33 | ], 34 | "engines": { 35 | "node": ">=4.0" 36 | }, 37 | "peerDependenciesMeta": { 38 | "debug": { 39 | "optional": true 40 | } 41 | } 42 | }, 43 | "node_modules/nodemailer": { 44 | "version": "6.7.2", 45 | "resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-6.7.2.tgz", 46 | "integrity": "sha512-Dz7zVwlef4k5R71fdmxwR8Q39fiboGbu3xgswkzGwczUfjp873rVxt1O46+Fh0j1ORnAC6L9+heI8uUpO6DT7Q==", 47 | "license": "MIT", 48 | "engines": { 49 | "node": ">=6.0.0" 50 | } 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /自动签到脚本/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "auto_sign", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "author": "", 10 | "license": "ISC", 11 | "dependencies": { 12 | "axios": "^0.21.4", 13 | "nodemailer": "^6.7.2" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /自动签到脚本/yarn.lock: -------------------------------------------------------------------------------- 1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 | # yarn lockfile v1 3 | 4 | 5 | axios@^0.21.4: 6 | version "0.21.4" 7 | resolved "https://registry.npmmirror.com/axios/-/axios-0.21.4.tgz" 8 | integrity sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg== 9 | dependencies: 10 | follow-redirects "^1.14.0" 11 | 12 | follow-redirects@^1.14.0: 13 | version "1.15.6" 14 | resolved "https://registry.npmmirror.com/follow-redirects/-/follow-redirects-1.15.6.tgz" 15 | integrity sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA== 16 | 17 | nodemailer@^6.7.2: 18 | version "6.7.2" 19 | resolved "https://registry.npmjs.org/nodemailer/-/nodemailer-6.7.2.tgz" 20 | integrity sha512-Dz7zVwlef4k5R71fdmxwR8Q39fiboGbu3xgswkzGwczUfjp873rVxt1O46+Fh0j1ORnAC6L9+heI8uUpO6DT7Q== 21 | -------------------------------------------------------------------------------- /运动轨迹/canvas-game.html: -------------------------------------------------------------------------------- 1 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | canvas 20 | 39 | 59 | 60 | 61 | 62 |
63 | 64 | 65 |
66 | 67 | 272 | 273 | 274 | -------------------------------------------------------------------------------- /运动轨迹/test.html: -------------------------------------------------------------------------------- 1 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 运动 16 | 35 | 46 | 47 | 48 | 49 |
50 | 51 | 52 |
53 | 177 | 178 | 179 | -------------------------------------------------------------------------------- /骨架屏1-简单的骨架屏方案/img.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yuwuwu/blog-code/5477dda5b564fbb50de555fd869731a70befcc35/骨架屏1-简单的骨架屏方案/img.jpg -------------------------------------------------------------------------------- /骨架屏1-简单的骨架屏方案/index-css.html: -------------------------------------------------------------------------------- 1 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | css骨架屏 16 | 17 | 18 | 19 | 51 | 52 | 53 | 54 |
55 |
56 |
57 |
58 |

59 |

60 |
61 |
62 |
63 |
64 |
65 |

66 |

67 |
68 |
69 |
70 |
71 |
72 |

73 |

74 |
75 |
76 |
77 | 78 |
79 |
80 | 81 | 82 | 101 | 102 | -------------------------------------------------------------------------------- /骨架屏1-简单的骨架屏方案/index-img.html: -------------------------------------------------------------------------------- 1 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 图片实现骨架屏 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 26 | 27 | 28 | 29 | 49 | 50 | -------------------------------------------------------------------------------- /骨架屏1-简单的骨架屏方案/index.css: -------------------------------------------------------------------------------- 1 | *{ 2 | margin: 0; 3 | padding: 0; 4 | } 5 | .box{ 6 | width: 100%; 7 | padding: 8px; 8 | box-sizing: border-box; 9 | } 10 | .item{ 11 | width: 100%; 12 | height: 80px; 13 | display: flex; 14 | padding-bottom: 5px; 15 | align-items: center; 16 | border-bottom: 1px solid #F5F7F8; 17 | margin-bottom: 10px; 18 | } 19 | .item-left{ 20 | width: 105px; 21 | height: 75px; 22 | } 23 | .item-right{ 24 | flex: 1; 25 | height: 75px; 26 | padding-left: 10px; 27 | } 28 | .item-right p{ 29 | font-weight: 500; 30 | line-height: 25px; 31 | height: 25px; 32 | font-size: 16px; 33 | color: #2D2D2F; 34 | } 35 | .item-right p:nth-child(2){ 36 | font-weight: normal; 37 | line-height: 20px; 38 | margin-top: 10px; 39 | height: 40px; 40 | font-size: 14px; 41 | color: #2D2D2F; 42 | } 43 | .box-list{ 44 | display: none; 45 | } -------------------------------------------------------------------------------- /骨架屏2-自动生成页面骨架/getDom.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: yuyongxing 3 | * @Date: 2021-11-13 15:01:31 4 | * @LastEditors: yuyongxing 5 | * @LastEditTime: 2021-11-16 22:56:43 6 | * @Description: 7 | */ 8 | let skeletonHtml = "" 9 | let removeClass = [] 10 | let removeId = [] 11 | function getDom(options = { removeElements: [] }) { 12 | const { removeElements } = options 13 | for (var i = 0; i < removeElements.length; i++) { 14 | let el = removeElements[i] 15 | let reg = /^./ 16 | if (el.match(reg) == ".") { 17 | removeClass.push(el.substr(1)) 18 | } 19 | if (el.match(reg) == "#") { 20 | removeId.push(el.substr(1)) 21 | } 22 | } 23 | const dom = document.body 24 | const nodes = dom.childNodes 25 | dom.style.overflow = "hidden" 26 | deepNode(nodes) 27 | return skeletonHtml 28 | } 29 | /** 30 | * @Author: yuyongxing 31 | * @param {*} nodes 32 | * @return {*} 33 | * @Date: 2021-11-13 15:52:17 34 | * @LastEditors: yuyongxing 35 | * @LastEditTime: Do not edit 36 | * @Description: 遍历节点 37 | */ 38 | function deepNode(nodes) { 39 | for (let i = 0; i < nodes.length; i++) { 40 | let node = nodes[i] 41 | if (isHide(node) || isRemove(node)) continue 42 | let flag = false 43 | for (let j = 0; j < node.childNodes.length; j++) { 44 | let childNode = node.childNodes[j] 45 | if (childNode.nodeType == 1) { 46 | flag = true 47 | } 48 | } 49 | if ((node.nodeType == 1 && !flag) || (node.nodeType == 1 && node.childNodes.length == 0)) { 50 | createDiv(node) 51 | } 52 | 53 | if (node.childNodes.length) { 54 | deepNode(node.childNodes) 55 | } 56 | } 57 | } 58 | 59 | /** 60 | * @Author: yuyongxing 61 | * @param {*} node 62 | * @return {*} true/false 63 | * @Date: 2021-11-13 15:51:53 64 | * @LastEditors: yuyongxing 65 | * @LastEditTime: Do not edit 66 | * @Description: 过滤节点,只保留元素节点 67 | */ 68 | function isHide(node) { 69 | if (node.nodeType != 1) return false 70 | let style = getComputedStyle(node, null) 71 | return node.nodeName == "SCRIPT"|| style.display == 'none' || style.opacity == 0 || style.visibility == 'hidden' 72 | } 73 | /** 74 | * @Author: yuyongxing 75 | * @param {*} node 76 | * @return {*} true/false 77 | * @Date: 2021-11-13 15:51:53 78 | * @LastEditors: yuyongxing 79 | * @LastEditTime: Do not edit 80 | * @Description: 判断该节点是否需要隐藏 81 | */ 82 | function isRemove(node) { 83 | let { className, id } = node 84 | if (className || id) { 85 | for (let i = 0; i < removeClass.length; i++) { 86 | if (className.indexOf(removeClass[i]) > -1) { 87 | return true 88 | } 89 | } 90 | if (removeId.includes(id)) { 91 | return true 92 | } 93 | } 94 | return false 95 | } 96 | /** 97 | * @Author: yuyongxing 98 | * @param {*} node 99 | * @return {*} 100 | * @Date: 2021-11-13 17:24:48 101 | * @LastEditors: yuyongxing 102 | * @LastEditTime: Do not edit 103 | * @Description: 插入带样式的div 104 | */ 105 | function createDiv(node) { 106 | let { width, height, top, left } = node.getBoundingClientRect() 107 | const { borderRadius, zIndex } = getComputedStyle(node, null) 108 | const { innerWidth, innerHeight } = window//可视区域宽高 109 | let nodeClassName = node.className ? `node-class=${node.className}`:"" 110 | let nodeId = node.id ? `node-id=${node.id}`:"" 111 | // 必须符合要求的元素才渲染:有大小,并且在视图内 112 | if (width > 5 && height > 5 && top < innerHeight && left < innerWidth) { 113 | width = ((width / innerWidth) * 100).toFixed(2) + '%' 114 | height = ((height / innerHeight) * 100).toFixed(2) + '%' 115 | left = ((left / innerWidth) * 100).toFixed(2) + '%' 116 | top = ((top / innerHeight) * 100).toFixed(2) + '%' 117 | skeletonHtml += `
` 118 | } 119 | } 120 | document.body.innerHTML=getDom() -------------------------------------------------------------------------------- /骨架屏2-自动生成页面骨架/img.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yuwuwu/blog-code/5477dda5b564fbb50de555fd869731a70befcc35/骨架屏2-自动生成页面骨架/img.jpg -------------------------------------------------------------------------------- /骨架屏2-自动生成页面骨架/index.css: -------------------------------------------------------------------------------- 1 | *{ 2 | margin: 0; 3 | padding: 0; 4 | } 5 | .box{ 6 | width: 100%; 7 | padding: 8px; 8 | box-sizing: border-box; 9 | } 10 | .item{ 11 | width: 100%; 12 | height: 80px; 13 | display: flex; 14 | padding-bottom: 5px; 15 | align-items: center; 16 | border-bottom: 1px solid #F5F7F8; 17 | margin-bottom: 10px; 18 | } 19 | .item-left{ 20 | width: 105px; 21 | height: 75px; 22 | border-radius: 8px; 23 | } 24 | .item-right{ 25 | flex: 1; 26 | height: 75px; 27 | padding-left: 10px; 28 | } 29 | .item-right p{ 30 | font-weight: 500; 31 | line-height: 25px; 32 | height: 25px; 33 | font-size: 16px; 34 | color: #2D2D2F; 35 | } 36 | .item-right p:nth-child(2){ 37 | font-weight: normal; 38 | line-height: 20px; 39 | margin-top: 10px; 40 | height: 40px; 41 | font-size: 14px; 42 | color: #2D2D2F; 43 | } 44 | .box-list{ 45 | display: none; 46 | } -------------------------------------------------------------------------------- /骨架屏2-自动生成页面骨架/index.html: -------------------------------------------------------------------------------- 1 | 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 |
39 |
40 |

41 |

42 |
43 |
44 |
45 |
46 |
47 | 48 | 49 | 68 | 69 | --------------------------------------------------------------------------------