├── .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://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 |
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 |
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 |
25 |
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 |
45 |
46 |
47 |
48 |
49 |
68 |
69 |
--------------------------------------------------------------------------------