-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathatom.xml
349 lines (186 loc) · 139 KB
/
atom.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<title>Raindew Tech</title>
<subtitle>学而不思则罔,思而不学则殆</subtitle>
<link href="https://floiges.github.io/atom.xml" rel="self"/>
<link href="https://floiges.github.io/"/>
<updated>2022-07-06T09:29:32.620Z</updated>
<id>https://floiges.github.io/</id>
<author>
<name>Raindew</name>
</author>
<generator uri="https://hexo.io/">Hexo</generator>
<entry>
<title>WebAssembly 入门</title>
<link href="https://floiges.github.io/2022/07/06/WebAssembly-%E5%85%A5%E9%97%A8/"/>
<id>https://floiges.github.io/2022/07/06/WebAssembly-%E5%85%A5%E9%97%A8/</id>
<published>2022-07-06T17:00:53.000Z</published>
<updated>2022-07-06T09:29:32.620Z</updated>
<content type="html"><![CDATA[<p>以下我们用简称 <code>wasm</code> 代替 <code>WebAssembly</code></p><a id="more"></a><h2 id="wasm-是什么"><a href="#wasm-是什么" class="headerlink" title="wasm 是什么"></a><code>wasm</code> 是什么</h2><p><code>wasm</code> 技术已经出来很久了,曾经也是引起了非常广泛的关注,发展历程就不一一展开了。作为 Web 支持的第四们语言来说,它可移植、体积小、加载快。说它是一门语言呢,也有点夸张,毕竟没有人会直接去写二进制,<code>wasm</code> 本身是被设计为高级编程语言的可移植编译目标。</p><p>所以我们会看到,目前有非常多的语言都提供了对应的编译器,可以很方便的把 <code>java</code>、<code>Rust</code>、<code>Go</code>等高级语言完美的编译为 <code>wasm</code> 并运行到浏览器中。当然,对于前端同学来说,这些语言还是会有一些门槛,不过我们也有 <code>[AssemblyScript](https://www.assemblyscript.org/introduction.html)</code> 语言来做相同的事情。</p><p>在使用之前呢,我们肯定要安装对应的工具,来达到把高级语言编译到 <code>wasm</code> 的目的,这里我主要讲两种,分别针对 <code>C/C++</code> 以及 <code>AssemblyScript</code>。今天我们主要讲一下 C/C++ 对应的工具安装,注:以下均以 mac 电脑为例。</p><h2 id="emsdk-安装"><a href="#emsdk-安装" class="headerlink" title="emsdk 安装"></a>emsdk 安装</h2><p>对于 C/C++ 的开发者来说,我们需要安装的编译工具就是 <code>[emsdk](https://github.com/emscripten-core/emsdk)</code>。按照文档上来说,具体有以下几步:</p><pre><code class="hljs bash"><span class="hljs-comment"># 首先需要打开命令行,执行</span>git <span class="hljs-built_in">clone</span> https://github.com/emscripten-core/emsdk.git<span class="hljs-built_in">cd</span> emsdk<span class="hljs-comment"># 安装以及激活最新版本</span>./emsdk install latest./emsdk activate latest<span class="hljs-comment"># 激活环境变量</span><span class="hljs-built_in">source</span> ./emsdk_env.sh</code></pre><h2 id="安装时遇到的问题"><a href="#安装时遇到的问题" class="headerlink" title="安装时遇到的问题"></a>安装时遇到的问题</h2><p>正常情况下,就安装 OK 了。但事情肯定不会就这么顺利,起码我在安装的时候就卡在了 <code>./emsdk install latest</code> 这一步,一直报错 <code>tar</code> 命令解压 <code>zip</code> 包失败。这个时候我们就需要看一下这个安装脚本了。</p><p>首先,我们看一下 emsdk 这个项目的目录结构:</p><p><img src="https://cdn.jsdelivr.net/gh/floiges/pics/img/20220706152200.png" alt="https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/4cff6da841264fb28fb41fcbc15593b3~tplv-k3u1fbpfcp-zoom-1.image"></p><p>图中标注的部分即是我们需要重点关注的部分了,当我们运行 <code>./emsdk install latest</code> 这条命令时,最终执行的是 <a href="http://emsdk.py/"><code>emsdk.py</code></a> 这个 <code>python</code> 脚本文件,脚本文件的具体逻辑大家感兴趣的可以自己看下,非常的简单。</p><h2 id="emsdk-install-latest-执行流程"><a href="#emsdk-install-latest-执行流程" class="headerlink" title="./emsdk install latest 执行流程"></a>./emsdk install latest 执行流程</h2><p>具体来说,<code>sdk</code> 安装时会分为以下几步:</p><ul><li>就是根据我们命令行的参数,在 <code>emscripten-releases-tags.json</code> 文件中找到具体的 <code>sdk</code> 版本,我们的命令是 <code>./emsdk install latest</code> ,那么此时命令行参数就是 <code>latest</code> ,</li></ul><pre><code class="hljs bash">{ <span class="hljs-string">"aliases"</span>: { <span class="hljs-string">"latest"</span>: <span class="hljs-string">"3.1.8"</span>, <span class="hljs-string">"latest-sdk"</span>: <span class="hljs-string">"latest"</span>, <span class="hljs-string">"latest-64bit"</span>: <span class="hljs-string">"latest"</span>, <span class="hljs-string">"sdk-latest-64bit"</span>: <span class="hljs-string">"latest"</span>, <span class="hljs-string">"latest-upstream"</span>: <span class="hljs-string">"latest"</span>, <span class="hljs-string">"latest-clang-upstream"</span>: <span class="hljs-string">"latest"</span>, <span class="hljs-string">"latest-releases-upstream"</span>: <span class="hljs-string">"latest"</span> }, <span class="hljs-string">"releases"</span>: { <span class="hljs-string">"3.1.8"</span>: <span class="hljs-string">"8c9e0a76ebed2c5e88a718d43e8b62452def3771"</span>, <span class="hljs-string">"3.1.8-asserts"</span>: <span class="hljs-string">"d33ae3c8d16f04b004b76c1d7c1989d637aa36e0"</span>, <span class="hljs-string">"3.1.7"</span>: <span class="hljs-string">"d0e637fe48197587d981f79e8114757731d0c2a9"</span>, <span class="hljs-string">"3.1.7-asserts"</span>: <span class="hljs-string">"88f0cab4e7db846e171cbbbbf20cc1a51b8c779f"</span>, <span class="hljs-string">"3.1.6"</span>: <span class="hljs-string">"8791c3e936141cbc2dd72d76290ea9b2726d39f3"</span>, <span class="hljs-string">"3.1.6-asserts"</span>: <span class="hljs-string">"84fa976d87a29ea1734601b042f3c6809ecb89f0"</span>, <span class="hljs-string">"3.1.5"</span>: <span class="hljs-string">"2dee36c7163f7394ab9341854ef5281501dd97d0"</span>, ... }}</code></pre><p>我们看到 <code>latest</code> 对应的版本是 <code>3.1.8</code>,同时也能获取到版本对应的 hash 值。</p><ul><li>找到版本号、<code>hash</code> 值的同时,命令行中的 <code>latest</code> 参数还会被解析为 <code>releases-upstream-%releases-tag%</code></li><li>同时,在 <code>emsdk_manifest.json</code> 文件中,<code>sdks</code> 里面有具体的环境依赖关系:</li></ul><pre><code class="hljs json">{........"sdks": [ ...., ...., { <span class="hljs-attr">"version"</span>: <span class="hljs-string">"releases-upstream-%releases-tag%"</span>, <span class="hljs-attr">"bitness"</span>: <span class="hljs-number">64</span>, <span class="hljs-attr">"uses"</span>: [<span class="hljs-string">"node-14.18.2-64bit"</span>, <span class="hljs-string">"releases-upstream-%releases-tag%-64bit"</span>], <span class="hljs-attr">"os"</span>: <span class="hljs-string">"linux"</span>, <span class="hljs-attr">"custom_install_script"</span>: <span class="hljs-string">"emscripten_npm_install"</span> }, { <span class="hljs-attr">"version"</span>: <span class="hljs-string">"releases-upstream-%releases-tag%"</span>, <span class="hljs-attr">"bitness"</span>: <span class="hljs-number">64</span>, <span class="hljs-attr">"uses"</span>: [<span class="hljs-string">"node-14.18.2-64bit"</span>, <span class="hljs-string">"python-3.9.2-64bit"</span>, <span class="hljs-string">"releases-upstream-%releases-tag%-64bit"</span>], <span class="hljs-attr">"os"</span>: <span class="hljs-string">"macos"</span>, <span class="hljs-attr">"arch"</span>: <span class="hljs-string">"x86_64"</span>, <span class="hljs-attr">"custom_install_script"</span>: <span class="hljs-string">"emscripten_npm_install"</span> },........], .... ....}</code></pre><p>可以看到,<code>version</code> 为 <code>releases-upstream-%releases-tag%</code> 且 <code>os</code> 是 <code>macos</code> 时,会依赖 <code>node-14.18.2</code> 、<code>python-3.9.2</code>以及 <code>releases-upstream-8c9e0a76ebed2c5e88a718d43e8b62452def3771</code> 。</p><ul><li>根据各依赖版本,下载对应的包,并放在对应的目录下,比如:新建 node 目录,并在下载完 <code>node-14.18.2</code> 之后,以版本号为名新建子目录并解压到此目录中,<code>python</code> 同理:</li></ul><p><img src="https://cdn.jsdelivr.net/gh/floiges/pics/img/20220706155223.png" alt="https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/f9e816395bcd48609b3871a95ad8024d~tplv-k3u1fbpfcp-zoom-1.image"></p><p>在子目录中,我们看到都会有一个 <code>.emsdk_version</code> 文件,其实里面的内容特别简单,就是记录一下当前依赖的版本号,脚本会读取这个文件来判断是否安装或更新了对应的依赖:</p><pre><code class="hljs bash"><span class="hljs-comment"># node/14.18.2_64bit/.emsdk_version</span>node-14.18.2-64bit</code></pre><h2 id="解决方法"><a href="#解决方法" class="headerlink" title="解决方法"></a>解决方法</h2><p>好了,到这里一切就很简单了,当我们运行 <code>./emsdk install latest</code> 却遇到各种问题安装失败时,我们可以自行查看 <code>emscripten-releases-tags.json</code> 以及 <code>emsdk_manifest.json</code> 文件,查找到对应的依赖以及对应的版本,下载好之后按照上面的方式新建目录,放入内容,并新建<code>.emsdk_version</code> 放入版本号,就完成了。</p><p>如果找不到对应的版本怎么办?其实运行命令如果报错的话,命令行也会直接提示当前下载的是哪个版本,我们把链接拷贝出来自行下载也是可以的,链接示例参考如下:</p><pre><code class="hljs bash"><span class="hljs-comment">#node-14.18.2-64bit</span>https://storage.googleapis.com/webassembly/emscripten-releases-builds/deps/node-v14.18.2-darwin-x64.tar.gz<span class="hljs-comment">#python-3.9.2-64bit</span>https://storage.googleapis.com/webassembly/emscripten-releases-builds/deps/python-3.9.2-3-macos-x86_64.tar.gz<span class="hljs-comment">#releases-upstream-568a46a9fb7e1f1686a6f7216b3dc976f28d2a79-64bit</span>https://storage.googleapis.com/webassembly/emscripten-releases-builds/mac/568a46a9fb7e1f1686a6f7216b3dc976f28d2a79/wasm-binaries.tbz2</code></pre><h2 id="小结"><a href="#小结" class="headerlink" title="小结"></a>小结</h2><p>当然,安装时没有任何问题时最好的。如果说安装时遇到不成功的情况,比如说 <code>tar</code> 解压缩 <code>zip</code> 包失败等问题,倒是可以参考一下。</p>]]></content>
<summary type="html"><p>以下我们用简称 <code>wasm</code> 代替 <code>WebAssembly</code></p></summary>
<category term="前端" scheme="https://floiges.github.io/categories/%E5%89%8D%E7%AB%AF/"/>
<category term="WebAssembly" scheme="https://floiges.github.io/tags/WebAssembly/"/>
</entry>
<entry>
<title>实操:开发 Fastlane 插件</title>
<link href="https://floiges.github.io/2020/09/16/%E5%AE%9E%E6%93%8D%EF%BC%9A%E5%BC%80%E5%8F%91-Fastlane-%E6%8F%92%E4%BB%B6/"/>
<id>https://floiges.github.io/2020/09/16/%E5%AE%9E%E6%93%8D%EF%BC%9A%E5%BC%80%E5%8F%91-Fastlane-%E6%8F%92%E4%BB%B6/</id>
<published>2020-09-16T18:19:50.000Z</published>
<updated>2022-07-06T09:29:32.620Z</updated>
<content type="html"><![CDATA[<p>开始整活</p><a id="more"></a><blockquote><p>jenkins 打包机器坏了还没修,本地打包之后每次都要通知测试去下载测试包。太麻烦了,直接搞个插件,打包之后自动发送钉钉消息到群里吧</p></blockquote><h2 id="创建-gem-项目"><a href="#创建-gem-项目" class="headerlink" title="创建 gem 项目"></a>创建 gem 项目</h2><pre><code class="hljs shell">fastlane new_plugin ykz_dingding_notify</code></pre><p>创建好的项目目录如下:</p><pre><code class="hljs crystal">├── Gemfile├── Gemfile.lock├── LICENSE├── README.md├── Rakefile├── coverage├── fastlane│ ├── Fastfile│ ├── Pluginfile│ ├── README.md│ └── report.xml├── fastlane-plugin-ykz_upload_bugly.gemspec├── <span class="hljs-class"><span class="hljs-keyword">lib</span></span>│ └── fastlane│ └── plugin│ ├── ykz_upload_bugly│ │ ├── actions│ │ │ └── ykz_upload_bugly_action.rb│ │ ├── helper│ │ │ └── ykz_upload_bugly_helper.rb│ │ └── version.rb│ └── ykz_upload_bugly.rb├── spec</code></pre><p>其中需要重点关注下面2个文件(目录):</p><ul><li><p>fastlane-plugin-ykz_upload_bugly.gemspec</p><p>基础配置文件,如果我们有额外的三方依赖的话,可以在这里进行配置,这次没有改动次文件</p></li><li><p>lib 目录</p><p>是我们需要重点关注的目录,我们主要的工作就是在 actions/ykz_upload_bugly_action.rb 中</p><p>编写主要的代码逻辑,例如处理参数、调用钉钉通知、处理返回结果等。</p><p>其中,helper/ykz_upload_bugly_helper.rb 中可以定义一些工具方法,versions.rb 则是配置此插件的版本号。</p></li></ul><h2 id="Fastlane-Action"><a href="#Fastlane-Action" class="headerlink" title="Fastlane Action"></a>Fastlane Action</h2><p>actions/ykz_upload_bugly_action.rb 文件内容如下:</p><pre><code class="hljs ruby"><span class="hljs-keyword">require</span> <span class="hljs-string">'fastlane/action'</span>require_relative <span class="hljs-string">'../helper/ykz_dingding_notify_helper'</span><span class="hljs-class"><span class="hljs-keyword">module</span> <span class="hljs-title">Fastlane</span></span> <span class="hljs-class"><span class="hljs-keyword">module</span> <span class="hljs-title">Actions</span></span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">YkzDingdingNotifyAction</span> < Action</span> <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">self</span>.<span class="hljs-title">run</span><span class="hljs-params">(params)</span></span> <span class="hljs-comment"># 处理核心逻辑的地方</span> <span class="hljs-comment"># 处理参数、调用接口、处理返回</span> <span class="hljs-keyword">end</span> <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">self</span>.<span class="hljs-title">description</span></span> <span class="hljs-string">"notify after app build"</span> <span class="hljs-keyword">end</span> <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">self</span>.<span class="hljs-title">authors</span></span> [<span class="hljs-string">"yadong"</span>] <span class="hljs-keyword">end</span> <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">self</span>.<span class="hljs-title">return_value</span></span> <span class="hljs-comment"># If your method provides a return value, you can describe here what it does</span> <span class="hljs-keyword">end</span> <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">self</span>.<span class="hljs-title">details</span></span> <span class="hljs-comment"># Optional:</span> <span class="hljs-string">"notify after app build"</span> <span class="hljs-keyword">end</span> <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">self</span>.<span class="hljs-title">available_options</span></span> <span class="hljs-comment"># 一般来说,我们肯定是需要接受外部传递参数的,这时就需要在此定义需要接收哪些参数</span> <span class="hljs-comment"># 返回值为一个 FastlaneCore::ConfigItem 类型的数组</span> <span class="hljs-keyword">end</span> <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">self</span>.<span class="hljs-title">is_supported?</span><span class="hljs-params">(platform)</span></span> <span class="hljs-comment"># Adjust this if your plugin only works for a particular platform (iOS vs. Android, for example)</span> <span class="hljs-comment"># See: https://docs.fastlane.tools/advanced/#control-configuration-by-lane-and-by-platform</span> <span class="hljs-comment">#</span> [<span class="hljs-symbol">:ios</span>, <span class="hljs-symbol">:mac</span>].<span class="hljs-keyword">include</span>?(platform) <span class="hljs-literal">true</span> <span class="hljs-keyword">end</span> <span class="hljs-keyword">end</span> <span class="hljs-keyword">end</span><span class="hljs-keyword">end</span></code></pre><p>我们先来想一下钉钉通知插件需要什么参数吧,最简单来说,我们需要如下2个参数:</p><ul><li>access_token: 钉钉机器人发送消息,这个是必备的了</li><li>message: 简单点,我们只处理 text 类型消息,那么我们就再额外传递一个消息内容就 OK 了</li></ul><p>首先我们来写 <code>self.available_options</code> 方法,编辑我们需要接收的参数:</p><pre><code class="hljs ruby"><span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">self</span>.<span class="hljs-title">available_options</span></span> [ FastlaneCore::ConfigItem.new(<span class="hljs-symbol">key:</span> <span class="hljs-symbol">:access_token</span>, <span class="hljs-symbol">env_name:</span> <span class="hljs-string">"YKZ_DINGDING_NOTIFY_ACCESS_TOKEN"</span>, <span class="hljs-symbol">description:</span> <span class="hljs-string">"dingding access_token"</span>, <span class="hljs-symbol">optional:</span> <span class="hljs-literal">false</span>, <span class="hljs-symbol">type:</span> String), FastlaneCore::ConfigItem.new(<span class="hljs-symbol">key:</span> <span class="hljs-symbol">:message</span>, <span class="hljs-symbol">env_name:</span> <span class="hljs-string">"YKZ_DINGDING_NOTIFY_MESSAGE"</span>, <span class="hljs-symbol">description:</span> <span class="hljs-string">"message if needed"</span>, <span class="hljs-symbol">optional:</span> <span class="hljs-literal">false</span>, <span class="hljs-symbol">type:</span> String) ]<span class="hljs-keyword">end</span></code></pre><p>参数定义好了,可以写核心的逻辑了。其实核心的逻辑相当简单,利用接收到的参数,拼接好 <code>curl</code> 请求然后调用并处理返回结果就行了。我们先看一下官方文档的钉钉通知 <code>curl 请求</code>:</p><pre><code class="hljs shell">curl 'https://oapi.dingtalk.com/robot/send?access_token=your_access_token' \ -H 'Content-Type: application/json' \ -d '{"msgtype": "text","text": {"content": "我就是我, 是不一样的烟火"}}'</code></pre><p>我们只要替换到请求中的 <code>access_token </code> 和 <code>content</code> 两个地方就可以达到我们的目的。</p><p>继续写 <code>self.run</code>方法:</p><pre><code class="hljs ruby"><span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">self</span>.<span class="hljs-title">run</span><span class="hljs-params">(params)</span></span> <span class="hljs-keyword">require</span> <span class="hljs-string">'json'</span> UI.message(<span class="hljs-string">"start notify dingding..."</span>) <span class="hljs-comment"># 处理 curl 返回,返回结果会被存储到 json_file 中</span> json_file = <span class="hljs-string">'notify_dingding_result.json'</span> <span class="hljs-comment"># 获取 access_token</span> <span class="hljs-keyword">begin</span> access_token = <span class="hljs-string">''</span> <span class="hljs-keyword">unless</span> params[<span class="hljs-symbol">:access_token</span>].empty? access_token = params[<span class="hljs-symbol">:access_token</span>] UI.message(<span class="hljs-string">"access_token: <span class="hljs-subst">#{access_token}</span>"</span>) <span class="hljs-keyword">end</span> <span class="hljs-keyword">rescue</span> => exception UI.message(<span class="hljs-string">"error at checking access_token, caused by <span class="hljs-subst">#{exception}</span>"</span>) <span class="hljs-keyword">return</span> <span class="hljs-keyword">end</span> <span class="hljs-comment"># 获取 message</span> <span class="hljs-keyword">begin</span> message = <span class="hljs-string">''</span> <span class="hljs-keyword">unless</span> params[<span class="hljs-symbol">:message</span>].empty? message = params[<span class="hljs-symbol">:message</span>] <span class="hljs-keyword">end</span> <span class="hljs-keyword">rescue</span> => exception UI.message(<span class="hljs-string">"error at checking message, caused by <span class="hljs-subst">#{exception}</span>"</span>) <span class="hljs-keyword">return</span> <span class="hljs-keyword">end</span> <span class="hljs-comment"># 拼接 curl</span> cmd = <<-DESC curl <span class="hljs-string">'https://oapi.dingtalk.com/robot/send?access_token=<span class="hljs-subst">#{access_token}</span>'</span> \ -H <span class="hljs-string">'Content-Type: application/json'</span> \ -d <span class="hljs-string">'{"msgtype": "text","text": {"content": "<span class="hljs-subst">#{message}</span>"}}'</span> \ -o <span class="hljs-comment">#{json_file}</span> DESC <span class="hljs-comment"># 调用 curl 执行请求</span> sh(cmd)<span class="hljs-comment"># 处理返回结果</span> obj = JSON.parse(File.read(json_file)) ret = obj[<span class="hljs-string">'errcode'</span>] <span class="hljs-keyword">if</span> ret == <span class="hljs-number">0</span> UI.message(<span class="hljs-string">"notify dingding successfully"</span>) <span class="hljs-keyword">else</span> UI.message(<span class="hljs-string">"notify dingding failed, result is <span class="hljs-subst">#{obj}</span>"</span>) <span class="hljs-keyword">end</span><span class="hljs-comment"># 最后删除 json 文件,避免占用空间</span> <span class="hljs-string">`rm notify_dingding_result.json`</span><span class="hljs-keyword">end</span></code></pre><h2 id="测试"><a href="#测试" class="headerlink" title="测试"></a>测试</h2><p>最主要的逻辑写完了,我们想要测试一下。我们在项目内 <code>fastlane/Fastfile</code> 文件中编写我们的测试逻辑:</p><pre><code class="hljs ruby">lane <span class="hljs-symbol">:test</span> <span class="hljs-keyword">do</span> ykz_dingding_notify( <span class="hljs-symbol">access_token:</span> <span class="hljs-string">'xxxxx'</span>, <span class="hljs-symbol">message:</span> <span class="hljs-string">'构建:哈哈哈哈哈'</span>, )<span class="hljs-keyword">end</span></code></pre><p>然后命令行进入我们项目目录,执行:</p><pre><code class="hljs shell">fastlane test<span class="hljs-meta">#</span><span class="bash"> 由于我这里用了 bundle,因此我执行了 bundle <span class="hljs-built_in">exec</span> fastlane <span class="hljs-built_in">test</span></span></code></pre><h2 id="iOS-工程里使用插件"><a href="#iOS-工程里使用插件" class="headerlink" title="iOS 工程里使用插件"></a>iOS 工程里使用插件</h2><p>我们把插件项目上传到 git 仓库中,然后打开 iOS 项目中的 fastlane/Pluginfile 文件:</p><pre><code class="hljs ruby">gem <span class="hljs-string">'fastlane-plugin-ykz_dingding_notify'</span>, <span class="hljs-symbol">git:</span> <span class="hljs-string">'your plugin git'</span></code></pre><p>然后再安装我们的插件信息:</p><pre><code class="hljs mipsasm">fastlane <span class="hljs-keyword">install_plugins</span><span class="hljs-keyword"># </span>由于我用了 <span class="hljs-keyword">bundle,因此我这里执行 </span><span class="hljs-keyword">bundle </span><span class="hljs-keyword">install </span>和 <span class="hljs-keyword">bundle </span>exec fastlane <span class="hljs-keyword">install_plugins</span></code></pre><p>现在,我们可以在我们的 <code>lane</code> 中使用通知插件了:</p><pre><code class="hljs ruby">desc <span class="hljs-string">"ad-hoc"</span>lane <span class="hljs-symbol">:adhoc</span> <span class="hljs-keyword">do</span> <span class="hljs-params">|options|</span>... ... ykz_dingding_notify( <span class="hljs-symbol">access_token:</span> <span class="hljs-string">'xxxx'</span>, <span class="hljs-symbol">message:</span> <span class="hljs-string">'构建通知:老铁们,打包成功了啊'</span>, )<span class="hljs-keyword">end</span></code></pre><p>喜大普奔!!!!</p>]]></content>
<summary type="html"><p>开始整活</p></summary>
<category term="工具" scheme="https://floiges.github.io/categories/%E5%B7%A5%E5%85%B7/"/>
<category term="Fastlane" scheme="https://floiges.github.io/tags/Fastlane/"/>
</entry>
<entry>
<title>学了 gulp 想练练手?正好压缩下你的博客</title>
<link href="https://floiges.github.io/2020/04/24/%E5%AD%A6%E4%BA%86-gulp-%E6%83%B3%E7%BB%83%E7%BB%83%E6%89%8B%EF%BC%9F%E6%AD%A3%E5%A5%BD%E5%8E%8B%E7%BC%A9%E4%B8%8B%E4%BD%A0%E7%9A%84%E5%8D%9A%E5%AE%A2/"/>
<id>https://floiges.github.io/2020/04/24/%E5%AD%A6%E4%BA%86-gulp-%E6%83%B3%E7%BB%83%E7%BB%83%E6%89%8B%EF%BC%9F%E6%AD%A3%E5%A5%BD%E5%8E%8B%E7%BC%A9%E4%B8%8B%E4%BD%A0%E7%9A%84%E5%8D%9A%E5%AE%A2/</id>
<published>2020-04-24T13:57:53.000Z</published>
<updated>2022-07-06T09:29:32.620Z</updated>
<content type="html"><![CDATA[<p>用自动化构建工具增强你的工作流程!</p><a id="more"></a><h2 id="Update"><a href="#Update" class="headerlink" title="Update"></a>Update</h2><p>最近升级 hexo,顺带也升级了 gulp 的依赖,运行 gulp 之后,报 <code>GulpUglifyError: unable to minify JavaScript Caused by: SyntaxError: Unexpected token: punc «)»</code> 错误,其实还是依赖没搞对, gulp-uglify 不识别 es6 的问题,想着博客项目也不考虑什么兼容性了,果断换插件。</p><p>先删除多余的插件:</p><pre><code class="hljs livescript"><span class="hljs-built_in">npm</span> uninstall<span class="hljs-string">\</span> gulp-babel@<span class="hljs-number">7</span><span class="hljs-string">\</span> babel-core<span class="hljs-string">\</span> babel-preset-env<span class="hljs-string">\</span> babel-preset-es2015<span class="hljs-string">\</span></code></pre><p>之后安装 <code>gulp-uglify-es</code>,它使用 <code>Terser</code> 压缩代码(支持 es6),非常人性化:</p><pre><code class="hljs q">npm install gulp-uglify-es --<span class="hljs-built_in">save</span>-<span class="hljs-built_in">dev</span></code></pre><p>最后<code>gulpfile</code> 里面这样改:</p><pre><code class="hljs javascript">......<span class="hljs-keyword">const</span> uglify = <span class="hljs-built_in">require</span>(<span class="hljs-string">'gulp-uglify-es'</span>).default; <span class="hljs-comment">// 引用 gulp-uglify-es</span>......<span class="hljs-comment">// 压缩 js</span><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">minifyJS</span>(<span class="hljs-params"></span>) </span>{<span class="hljs-keyword">return</span> gulp.src(<span class="hljs-string">'./public/js/**/*.js'</span>).pipe(uglify()) <span class="hljs-comment">// 直接压缩即可</span>.pipe(gulp.dest(<span class="hljs-string">'./public'</span>));}............</code></pre><p>———————— 以下为原文 ————————</p><h2 id="一些关于-Gulp的基础概念"><a href="#一些关于-Gulp的基础概念" class="headerlink" title="一些关于 Gulp的基础概念"></a>一些关于 <code>Gulp</code>的基础概念</h2><h3 id="任务"><a href="#任务" class="headerlink" title="任务"></a>任务</h3><p>首选要明确的一点是,<code>gulp</code> 中的每个任务都是一个 <code>javascript</code> 异步函数。处理异步任务,最基础也最常用的就是 <code>error-first callbacks</code> , 但是 <code>gulp</code> 也支持流、<code>promises</code>、<code>async/await</code> 等等其他异步方式,根据自己的需要进行选择即可,我们这里选用的就是返回流的方式。</p><h3 id="Globs"><a href="#Globs" class="headerlink" title="Globs"></a>Globs</h3><p>代表一串文字和/或通配符,如 <code>*</code>, <code>**</code>, 或 <code>!</code>,用于匹配文件路径。例如: <code>./public/js/**.js</code> 代表匹配当前 <code>public/js</code> 目录下的所有 <code>js</code>文件。</p><h3 id="插件"><a href="#插件" class="headerlink" title="插件"></a>插件</h3><blockquote><p>Gulp 插件实质上是 <a href="https://github.com/rvagg/through2">Node 转换流(Transform Streams)</a>,它封装了通过管道(pipeline)转换文件的常见功能,通常是使用 <code>.pipe()</code> 方法并放在 <code>src()</code> 和 <code>dest()</code> 之间。他们可以更改经过流(stream)的每个文件的文件名、元数据或文件内容。</p></blockquote><p>插件是用来转换文件的,可以简化我们的操作,让我们快速上手。我们这次也是使用了很多的插件,比如压缩文件、压缩图片等 <code>gulp</code> 插件。</p><h2 id="实操"><a href="#实操" class="headerlink" title="实操"></a>实操</h2><p>引入依赖:</p><pre><code class="hljs bash">npm install\ gulp gulp-minify-css\ gulp-uglify\ gulp-htmlmin\ gulp-htmlclean\ gulp-imagemin\ --save-dev</code></pre><p>这里面遇到个问题,因为 <code>gulp-uglify</code> 压缩 <code>js</code> 文件的时候,遇见 ES6 语法会报错,因此我们还需要引入下 <code>babel</code> 的插件,先转换下语法再压缩文件:</p><pre><code class="hljs bash">npm install\ gulp-babel@7\ babel-core\ babel-preset-env\ babel-preset-es2015\ --save-dev</code></pre><p>运行 <code>hexo g</code> 之后,会生成可发布的 <code>public</code> 文件夹,因为我们的 <code>gulp</code> 任务,都是基于此文件夹操作的。</p><pre><code class="hljs javascript"><span class="hljs-keyword">const</span> gulp = <span class="hljs-built_in">require</span>(<span class="hljs-string">'gulp'</span>);<span class="hljs-keyword">const</span> minifycss = <span class="hljs-built_in">require</span>(<span class="hljs-string">'gulp-minify-css'</span>);<span class="hljs-keyword">const</span> uglify = <span class="hljs-built_in">require</span>(<span class="hljs-string">'gulp-uglify'</span>);<span class="hljs-keyword">const</span> htmlmin = <span class="hljs-built_in">require</span>(<span class="hljs-string">'gulp-htmlmin'</span>);<span class="hljs-keyword">const</span> htmlclean = <span class="hljs-built_in">require</span>(<span class="hljs-string">'gulp-htmlclean'</span>);<span class="hljs-keyword">const</span> imagemin = <span class="hljs-built_in">require</span>(<span class="hljs-string">'gulp-imagemin'</span>);<span class="hljs-keyword">const</span> babel = <span class="hljs-built_in">require</span>(<span class="hljs-string">'gulp-babel'</span>);<span class="hljs-comment">// 压缩 js</span><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">minifyJS</span>(<span class="hljs-params"></span>) </span>{<span class="hljs-keyword">return</span> gulp.src(<span class="hljs-string">'./public/js/**/*.js'</span>).pipe(babel({ <span class="hljs-attr">presets</span>: [<span class="hljs-string">'es2015'</span>] })) <span class="hljs-comment">// 先转换语法</span>.pipe(uglify()).pipe(gulp.dest(<span class="hljs-string">'./public'</span>));}<span class="hljs-comment">// 压缩html</span><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">minifyHTML</span>(<span class="hljs-params"></span>) </span>{<span class="hljs-keyword">return</span> gulp.src(<span class="hljs-string">'./public/**/*.html'</span>).pipe(htmlclean()).pipe(htmlmin({removeComments: <span class="hljs-literal">true</span>,minifyJS: <span class="hljs-literal">true</span>,minifyCSS: <span class="hljs-literal">true</span>,minifyURLs: <span class="hljs-literal">true</span>,}),).pipe(gulp.dest(<span class="hljs-string">'./public'</span>));}<span class="hljs-comment">// 压缩css</span><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">minifyCSS</span>(<span class="hljs-params"></span>) </span>{<span class="hljs-keyword">return</span> gulp.src(<span class="hljs-string">'./public/**/*.css'</span>).pipe(minifycss({compatibility: <span class="hljs-string">'ie8'</span>,}),).pipe(gulp.dest(<span class="hljs-string">'./public'</span>));}<span class="hljs-comment">// 压缩图片</span><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">minifyIMG</span>(<span class="hljs-params"></span>) </span>{<span class="hljs-keyword">return</span> gulp.src(<span class="hljs-string">'./public/images/**/*.*'</span>).pipe(imagemin([imagemin.gifsicle({ <span class="hljs-attr">optimizationLevel</span>: <span class="hljs-number">3</span> }),imagemin.mozjpeg({ <span class="hljs-attr">progressive</span>: <span class="hljs-literal">true</span> }),imagemin.optipng({ <span class="hljs-attr">optimizationLevel</span>: <span class="hljs-number">7</span> }),imagemin.svgo(),],{ <span class="hljs-attr">verbose</span>: <span class="hljs-literal">true</span> },),).pipe(gulp.dest(<span class="hljs-string">'./public/images'</span>));}<span class="hljs-comment">// 导出默认任务,这样命令行下输入 gulp 即可运行</span><span class="hljs-built_in">exports</span>.default = gulp.series(minifyJS, minifyHTML, minifyCSS, minifyIMG);</code></pre><p>接下啦,我们命令行下运行 <code>hexo g && gulp</code> 即可打包并压缩我们的文件了。</p><h2 id="结合自动化"><a href="#结合自动化" class="headerlink" title="结合自动化"></a>结合自动化</h2><p>我在之前的文章<a href="/2020/02/18/%E4%BD%BF%E7%94%A8-github-action-%E5%8F%91%E5%B8%83-hexo/" title="使用 github action 发布 hexo">使用 github action 发布 hexo</a>中,介绍过使用 <code>github action</code>来发布我们的博客,现在只要在<code>action</code>的基础上加上 <code>gulp</code>任务就 ok 了。这样就达到了,博客项目推送<code>master</code>分支,触发 <code>github action</code>,打包压缩之后,上传至 <code>github pages</code>项目,完美。</p><pre><code class="hljs yaml"><span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Install</span> <span class="hljs-string">dependencies</span> <span class="hljs-attr">run:</span> <span class="hljs-string">|</span> <span class="hljs-string">npm</span> <span class="hljs-string">i</span> <span class="hljs-string">-g</span> <span class="hljs-string">hexo-cli</span> <span class="hljs-string">gulp</span> <span class="hljs-string">npm</span> <span class="hljs-string">i</span><span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Deploy</span> <span class="hljs-string">hexo</span> <span class="hljs-attr">run:</span> <span class="hljs-string">|</span> <span class="hljs-string">hexo</span> <span class="hljs-string">clean</span> <span class="hljs-string">hexo</span> <span class="hljs-string">g</span> <span class="hljs-string">&&</span> <span class="hljs-string">gulp</span> <span class="hljs-string">&&</span> <span class="hljs-string">hexo</span> <span class="hljs-string">deploy</span></code></pre>]]></content>
<summary type="html"><p>用自动化构建工具增强你的工作流程!</p></summary>
<category term="工具" scheme="https://floiges.github.io/categories/%E5%B7%A5%E5%85%B7/"/>
<category term="hexo" scheme="https://floiges.github.io/tags/hexo/"/>
</entry>
<entry>
<title>来了,前端一键下载压缩包</title>
<link href="https://floiges.github.io/2020/04/23/%E6%9D%A5%E4%BA%86%EF%BC%8C%E5%89%8D%E7%AB%AF%E4%B8%80%E9%94%AE%E4%B8%8B%E8%BD%BD%E5%8E%8B%E7%BC%A9%E5%8C%85/"/>
<id>https://floiges.github.io/2020/04/23/%E6%9D%A5%E4%BA%86%EF%BC%8C%E5%89%8D%E7%AB%AF%E4%B8%80%E9%94%AE%E4%B8%8B%E8%BD%BD%E5%8E%8B%E7%BC%A9%E5%8C%85/</id>
<published>2020-04-23T17:00:53.000Z</published>
<updated>2022-07-06T09:29:32.620Z</updated>
<content type="html"><![CDATA[<p>什么?你想一键下载图片压缩包</p><a id="more"></a><h2 id="前提"><a href="#前提" class="headerlink" title="前提"></a>前提</h2><blockquote><p>什么?你想一键下载图片压缩包?这还真的是我接到需求后的第一句话。产品想把商品相册中的图片以压缩包的形式下载下来,于是我张口就来:后端开个接口呗。。。</p></blockquote><p>一番调研之后,确认这个需求完全可以由前端独立实现,具体依赖以下两个库:</p><ul><li><p><a href="https://stuk.github.io/jszip/">JSZip</a></p><p>可以用非常简单的 <code>API</code> 来创建、读取和编辑 <code>.zip</code>压缩包文件。</p></li><li><p><a href="https://stuk.github.io/jszip/">FileSaver</a></p><p>可以在 <code>web</code>客户端保存文件</p></li></ul><h2 id="实现思路"><a href="#实现思路" class="headerlink" title="实现思路"></a>实现思路</h2><ul><li>首先利用 <code>Image</code> 下载图片,然后用 <code>canvas</code> 将图片导出 <code>base64</code> 形式</li><li><code>JSZip</code> 创建文件夹,并将上一步获得的图片数据进行打包</li><li>打包之后,使用 <code>FileSaver</code> 将打包好的 <code>zip</code> 保存到本地</li></ul><h3 id="具体代码"><a href="#具体代码" class="headerlink" title="具体代码"></a>具体代码</h3><pre><code class="hljs javascript"><span class="hljs-keyword">import</span> JSZip <span class="hljs-keyword">from</span> <span class="hljs-string">'jszip'</span>;<span class="hljs-keyword">import</span> { saveAs } <span class="hljs-keyword">from</span> <span class="hljs-string">'file-saver'</span>;<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> (urls, zipName = <span class="hljs-string">'素材包'</span>) => {<span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Promise</span>(<span class="hljs-function">(<span class="hljs-params">resolve, reject</span>) =></span> {<span class="hljs-keyword">const</span> zip = <span class="hljs-keyword">new</span> JSZip();<span class="hljs-comment">// 创建文件夹</span><span class="hljs-keyword">const</span> imgFolder = zip.folder(zipName);<span class="hljs-keyword">const</span> imagePromises = urls.map(<span class="hljs-function">(<span class="hljs-params">src</span>) =></span> getBase64Image(src));<span class="hljs-built_in">Promise</span>.all(imagePromises).then(<span class="hljs-function">(<span class="hljs-params">results</span>) =></span> results.filter(<span class="hljs-function">(<span class="hljs-params">result</span>) =></span> result.length > <span class="hljs-number">0</span>)).then(<span class="hljs-function">(<span class="hljs-params">base64Images</span>) =></span> {<span class="hljs-built_in">console</span>.table(base64Images);<span class="hljs-keyword">if</span> (base64Images.length === <span class="hljs-number">0</span>) {reject();<span class="hljs-keyword">return</span>;}<span class="hljs-keyword">for</span> (<span class="hljs-keyword">let</span> i = <span class="hljs-number">0</span>; i < base64Images.length; i++) {<span class="hljs-keyword">let</span> base64Image = base64Images[i];<span class="hljs-comment">// 去掉 bas64, 标志</span>base64Image = base64Image.split(<span class="hljs-string">'base64,'</span>)[<span class="hljs-number">1</span>];<span class="hljs-comment">// 添加文件到 folder 中</span>imgFolder.file(<span class="hljs-string">`<span class="hljs-subst">${i}</span>.png`</span>, base64Image, { <span class="hljs-attr">base64</span>: <span class="hljs-literal">true</span> });}<span class="hljs-comment">// 打包</span>zip.generateAsync({ <span class="hljs-attr">type</span>: <span class="hljs-string">'blob'</span> }).then(<span class="hljs-function">(<span class="hljs-params">blob</span>) =></span> {<span class="hljs-comment">// 导出下载</span>saveAs(blob, <span class="hljs-string">`<span class="hljs-subst">${zipName}</span>.zip`</span>);resolve();}).catch(<span class="hljs-function">() =></span> {reject();});});});};<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getBase64Image</span>(<span class="hljs-params">src, width, height</span>) </span>{<span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Promise</span>(<span class="hljs-function">(<span class="hljs-params">resolve</span>) =></span> {<span class="hljs-keyword">const</span> image = <span class="hljs-keyword">new</span> Image();image.crossOrigin = <span class="hljs-string">''</span>; <span class="hljs-comment">// 设置跨域</span>image.src = src;image.onload = <span class="hljs-function">() =></span> {<span class="hljs-keyword">const</span> canvas = <span class="hljs-built_in">document</span>.createElement(<span class="hljs-string">'canvas'</span>);canvas.width = width || image.width;canvas.height = height || image.height;<span class="hljs-keyword">const</span> ctx = canvas.getContext(<span class="hljs-string">'2d'</span>);ctx.drawImage(image, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, canvas.width, canvas.height);resolve(canvas.toDataURL()); <span class="hljs-comment">// 导出 base64</span>};image.onerror = <span class="hljs-function">() =></span> {<span class="hljs-built_in">console</span>.log(<span class="hljs-string">`图片 <span class="hljs-subst">${src}</span> 加载失败...`</span>);resolve(<span class="hljs-string">''</span>);};});}</code></pre><p>特别要注意一下这句代码:</p><pre><code class="hljs javascript">image.crossOrigin = <span class="hljs-string">''</span>; <span class="hljs-comment">// 设置跨域</span></code></pre><p>如果不设置的话,则 <code>canvas</code> 会报错:</p><pre><code class="hljs bash">Failed to execute ‘toDataURL’ on ’HTMLCanvasElement’: Tainted canvased may not be exported</code></pre><p>H5 中,部分元素提供了支持 <code>CORS</code> 的属性,这些元素包括 <code><img></code>,<code><video></code>,<code><script></code>等,对应的属性名即 <code>crossOrigin</code>:</p><table><thead><tr><th align="center">属性值</th><th align="center">描述</th></tr></thead><tbody><tr><td align="center">use-credentials</td><td align="center">元素的跨域资源请求需要凭证标志设置</td></tr><tr><td align="center">anonymous</td><td align="center">元素的跨域资源请求不需要凭证标志设置</td></tr></tbody></table><p>我们这里虽然设置了 <code>image.crossOrigin</code> 为空字符串,但实际生效的是 <code>anonymous</code>,更详细的内容的可参考张鑫旭的<a href="https://www.zhangxinxu.com/wordpress/2018/02/crossorigin-canvas-getimagedata-cors/">解决 canvas 图片 getImageData,toDataURL 跨域问题</a>这篇文章,我就不多说了。</p>]]></content>
<summary type="html"><p>什么?你想一键下载图片压缩包</p></summary>
<category term="前端" scheme="https://floiges.github.io/categories/%E5%89%8D%E7%AB%AF/"/>
</entry>
<entry>
<title>vue 动态设置页面标题那点儿事</title>
<link href="https://floiges.github.io/2020/04/23/vue-%E5%8A%A8%E6%80%81%E8%AE%BE%E7%BD%AE%E9%A1%B5%E9%9D%A2%E6%A0%87%E9%A2%98%E9%82%A3%E7%82%B9%E5%84%BF%E4%BA%8B/"/>
<id>https://floiges.github.io/2020/04/23/vue-%E5%8A%A8%E6%80%81%E8%AE%BE%E7%BD%AE%E9%A1%B5%E9%9D%A2%E6%A0%87%E9%A2%98%E9%82%A3%E7%82%B9%E5%84%BF%E4%BA%8B/</id>
<published>2020-04-23T15:09:26.000Z</published>
<updated>2022-07-06T09:29:32.620Z</updated>
<content type="html"><![CDATA[<p>正美着准备下班了,突然一个 bug 砸到脸上。。。</p><a id="more"></a><blockquote><p>有这么一个页面,它的页面标题是可在后台配置的,前端正常显示标题即可。话说,这个需求小的不能再小了,上线也快半年了,应该不会有什么问题。直到有一天,运营妹子反馈,这个标题怎么没有更新呢?我????</p></blockquote><blockquote><p>2020-09-15 更新<br>如果这个页面也需要在小程序中,iframe 中设置的图标 url 要配置 webview 域名校验</p></blockquote><h2 id="原因"><a href="#原因" class="headerlink" title="原因"></a>原因</h2><p>原因很快就排查到了,当页面在 <code>iOS</code>中的 <code>webview</code>中显示时,标题设置失效了,而在微信端和安卓端是没有问题的。</p><pre><code class="hljs javascript"><span class="hljs-built_in">document</span>.title = <span class="hljs-string">'标题'</span>;</code></pre><p>正常情况下,我们都是这样设置标题的,而在 <code>iOS</code>的 <code>webview</code>中加载页面时,设置 <code>document.title</code>并不起作用,因为标题栏是原生的,需要调用原生设置标题的方法才可以,那前端就没有办法了吗?</p><h2 id="解决"><a href="#解决" class="headerlink" title="解决"></a>解决</h2><p>其实,多测试几次我们可以发现,<code>iOS</code>第一次加载页面的时候,标题没有生效,但是再刷新一下当前页面,你会发现标题又生效了,这是不是给了我们一点点的启发?</p><p>没错, <code>iOS webview</code> 仅在加载页面的时候才能读取到 <code>document.title</code>,所以页面加载之后使用 <code>js</code>再设置 <code>document.title</code>是根本不会起作用的。。。那么我们是不是可以使用点手段来触发 <code>webview</code>加载而又不影响当前页面呢?</p><h3 id="来了,-iframe"><a href="#来了,-iframe" class="headerlink" title="来了, iframe"></a>来了, <code>iframe</code></h3><p>没错,就是 <code>iframe</code>,虽然很多时候,我们对 <code>iframe</code>嗤之以鼻,但真的遇到问题的时候,还是老大哥靠谱。</p><p><code>iframe</code>是内联框架,也是一种文档对象,于是我们可以:**加载一个不可见的 <code>iframe</code>,并利用它来触发 <code>webview</code>的加载,从而读取到我们设置的 <code>document.title</code>**。</p><pre><code class="hljs javascript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">isIOS</span>(<span class="hljs-params"></span>) </span>{<span class="hljs-keyword">var</span> ua = navigator.userAgent.toLowerCase();<span class="hljs-keyword">if</span> (<span class="hljs-regexp">/iphone|ipad|ipod/</span>.test(ua)) {<span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>;} <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (<span class="hljs-regexp">/android/</span>.test(ua)) {<span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>;}}<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">setDocumentTitle</span>(<span class="hljs-params">title = <span class="hljs-string">'标题'</span></span>) </span>{<span class="hljs-built_in">document</span>.title = title; <span class="hljs-comment">// 设置标题</span><span class="hljs-keyword">if</span> (isIOS()) {<span class="hljs-comment">// 创建空的 iframe,触发 onload 事件</span><span class="hljs-keyword">const</span> iframe = <span class="hljs-built_in">document</span>.createElement(<span class="hljs-string">'iframe'</span>);iframe.style.display = <span class="hljs-string">'none'</span>;iframe.setAttribute(<span class="hljs-string">'src'</span>,<span class="hljs-string">'url'</span>, <span class="hljs-comment">// 搞个小点的图标</span>);<span class="hljs-comment">// onload 回调函数</span><span class="hljs-keyword">const</span> onIframeLoad = <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{<span class="hljs-built_in">setTimeout</span>(<span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{<span class="hljs-comment">// 加载完之后,删除 iframe</span>iframe.removeEventListener(<span class="hljs-string">'load'</span>, onIframeLoad);<span class="hljs-built_in">document</span>.body.removeChild(iframe);}, <span class="hljs-number">0</span>);};iframe.addEventListener(<span class="hljs-string">'load'</span>, onIframeLoad);<span class="hljs-built_in">document</span>.body.appendChild(iframe);}}</code></pre><h2 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h2><p>遇到这个问题的时候,也搜索了不少博客,很多人(包括同事)说在 <code>WKWebView</code> 下面不会有这个问题,只在 <code>UIWebView</code>上才会有。但是我们的 <code>app</code>中,使用的一直都是 <code>WK</code>,还是会有发生标题失效的问题。不管怎么说,适合自己的就是最好的。<code>bug</code>解决了,可以下班了不是吗?</p>]]></content>
<summary type="html"><p>正美着准备下班了,突然一个 bug 砸到脸上。。。</p></summary>
<category term="前端" scheme="https://floiges.github.io/categories/%E5%89%8D%E7%AB%AF/"/>
<category term="vue" scheme="https://floiges.github.io/tags/vue/"/>
</entry>
<entry>
<title>微信小程序之如何保存小程序码</title>
<link href="https://floiges.github.io/2020/04/17/%E5%BE%AE%E4%BF%A1%E5%B0%8F%E7%A8%8B%E5%BA%8F%E4%B9%8B%E5%A6%82%E4%BD%95%E4%BF%9D%E5%AD%98%E5%B0%8F%E7%A8%8B%E5%BA%8F%E7%A0%81/"/>
<id>https://floiges.github.io/2020/04/17/%E5%BE%AE%E4%BF%A1%E5%B0%8F%E7%A8%8B%E5%BA%8F%E4%B9%8B%E5%A6%82%E4%BD%95%E4%BF%9D%E5%AD%98%E5%B0%8F%E7%A8%8B%E5%BA%8F%E7%A0%81/</id>
<published>2020-04-17T17:42:40.000Z</published>
<updated>2022-07-06T09:29:32.620Z</updated>
<content type="html"><![CDATA[<p>兵来将挡,水来土掩</p><a id="more"></a><blockquote><p>最近搞了点微信小程序的东西,其中一个需求就是要把云函数生成的小程序码,保存到本地相册,便于分享。</p></blockquote><h2 id="思路"><a href="#思路" class="headerlink" title="思路"></a>思路</h2><h3 id="关于云函数生成小程序码"><a href="#关于云函数生成小程序码" class="headerlink" title="关于云函数生成小程序码"></a>关于云函数生成小程序码</h3><p>云函数具体怎么用就不说了,官方文档上一看就明白了。我们这里需要用到的是 <a href="https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/qr-code/wxacode.getUnlimited.html">wxacode.getUnlimited</a> 这个获取小程序码的接口。文档上说明,这个接口调用成功之后,返回的小程序码数据是 <code>Buffer</code>形式的。</p><p>按照我们要实现的需求来说,生成小程序码之后,肯定会有如下的两个操作:</p><ul><li>弹窗显示生成的小程序码</li><li>保存小程序码到相册</li></ul><h3 id="wx-arrayBufferToBase64-ArrayBuffer-arrayBuffer"><a href="#wx-arrayBufferToBase64-ArrayBuffer-arrayBuffer" class="headerlink" title="wx.arrayBufferToBase64(ArrayBuffer arrayBuffer)"></a><a href="https://developers.weixin.qq.com/miniprogram/dev/api/base/wx.arrayBufferToBase64.html">wx.arrayBufferToBase64(ArrayBuffer arrayBuffer)</a></h3><p>微信是为我们提供了 <code>arrayBuffer</code> 转 <code>base64</code> 的方法的:</p><pre><code class="hljs javascript"><span class="hljs-keyword">const</span> src = <span class="hljs-string">`data:image/png;base64,<span class="hljs-subst">${wx.arrayBufferToBase64(buffer)}</span>`</span>;</code></pre><p>转化之后,直接用 <code>image</code> 组件显示图片就可以了。但是要保存到相册,<code>base64</code> 肯定是不行的,该怎么办呢?</p><h3 id="wx-saveImageToPhotosAlbum-Object-object"><a href="#wx-saveImageToPhotosAlbum-Object-object" class="headerlink" title="wx.saveImageToPhotosAlbum(Object object)"></a><a href="https://developers.weixin.qq.com/miniprogram/dev/api/media/image/wx.saveImageToPhotosAlbum.html">wx.saveImageToPhotosAlbum(Object object)</a></h3><pre><code class="hljs javascript">wx.saveImageToPhotosAlbum({filePath: tempFilePath, <span class="hljs-comment">// 图片文件路径,可以是临时文件路径或永久文件路径 (本地路径) ,不支持网络路径</span>success: <span class="hljs-function">() =></span> {wx.showToast({title: <span class="hljs-string">'保存成功,从相册中分享给朋友吧'</span>,icon: <span class="hljs-string">'none'</span>,duration: <span class="hljs-number">3000</span>,});},fail: <span class="hljs-function">() =></span> {wx.showToast({title: <span class="hljs-string">'图片保存失败,请稍候重试'</span>,icon: <span class="hljs-string">'none'</span>,duration: <span class="hljs-number">2000</span>,});},});</code></pre><p>文档上说的很明白,我们首先要获取到图片的临时或永久文件路径,那就再一步步找文档。。。</p><h3 id="wx-canvasToTempFilePath-Object-object-Object-this-wx-canvasToTempFilePath-Object-object-Object-this"><a href="#wx-canvasToTempFilePath-Object-object-Object-this-wx-canvasToTempFilePath-Object-object-Object-this" class="headerlink" title="[wx.canvasToTempFilePath(Object object, Object this)](wx.canvasToTempFilePath(Object object, Object this))"></a>[wx.canvasToTempFilePath(Object object, Object this)](wx.canvasToTempFilePath(Object object, Object this))</h3><blockquote><p>把当前画布指定区域的内容导出生成指定大小的图片</p></blockquote><p><code>canvas</code>,没错,这正是我们需要的,那么我们就可以梳理出整个保存图片的流程了:</p><ul><li>调用云函数,获取到小程序 <code>buffer</code>数据</li><li>将图片和一些文案描述(如果需要的话)画在画布上</li><li><code>canvas</code>导出文件临时路径</li><li>保存图片</li></ul><h2 id="源码"><a href="#源码" class="headerlink" title="源码"></a>源码</h2><h3 id="base64src-js"><a href="#base64src-js" class="headerlink" title="base64src.js"></a><code>base64src.js</code></h3><blockquote><p>工具方法,主要是先把小程序码的 <code>buffer</code> 数据写入到本地文件</p><p>这样既可以直接用 <code>image</code> 显示,又可以直接画在 <code>canvas</code>中,一举两得</p></blockquote><pre><code class="hljs javascript"><span class="hljs-keyword">const</span> fileManager = wx.getFileSystemManager();<span class="hljs-keyword">const</span> BASE_FILE_NAME = <span class="hljs-string">'tmp_base64src'</span>;<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> (bufferData) => {<span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Promise</span>(<span class="hljs-function">(<span class="hljs-params">resolve, reject</span>) =></span> {<span class="hljs-keyword">const</span> filePath = <span class="hljs-string">`<span class="hljs-subst">${wx.env.USER_DATA_PATH}</span>/<span class="hljs-subst">${BASE_FILE_NAME}</span>.png`</span>;fileManager.writeFile({filePath,data: bufferData,encoding: <span class="hljs-string">'binary'</span>,success: <span class="hljs-function">() =></span> {resolve(filePath);},fail: <span class="hljs-function">() =></span> {reject(<span class="hljs-keyword">new</span> <span class="hljs-built_in">Error</span>(<span class="hljs-string">'WRITE BASE64SRC ERROR'</span>));},});});};</code></pre><h3 id="生成小程序码"><a href="#生成小程序码" class="headerlink" title="生成小程序码"></a>生成小程序码</h3><pre><code class="hljs javascript">wx.cloud.callFunction({name: <span class="hljs-string">'code'</span>,data: {<span class="hljs-comment">/* your data */</span>},success: <span class="hljs-function">(<span class="hljs-params">res</span>) =></span> {<span class="hljs-built_in">console</span>.log(<span class="hljs-string">'[云函数] [code] 调用成功'</span>);<span class="hljs-keyword">const</span> {result: { buffer },} = res;base64Src(buffer).then(<span class="hljs-function">(<span class="hljs-params">src</span>) =></span> {<span class="hljs-comment">// 获取到小程序码对应的本地路径</span><span class="hljs-built_in">console</span>.log(<span class="hljs-string">'src'</span>, src);});},fail: <span class="hljs-function">(<span class="hljs-params">err</span>) =></span> {<span class="hljs-built_in">console</span>.error(<span class="hljs-string">'[云函数] [code] 调用失败'</span>);},complete: <span class="hljs-function">() =></span> {wx.hideLoading();},});</code></pre><h3 id="canvas绘制图片和文字"><a href="#canvas绘制图片和文字" class="headerlink" title="canvas绘制图片和文字"></a><code>canvas</code>绘制图片和文字</h3><pre><code class="hljs javascript"><span class="hljs-keyword">if</span> (!<span class="hljs-built_in">this</span>.ctx) {<span class="hljs-built_in">this</span>.ctx = wx.createCanvasContext(<span class="hljs-string">'miniCanvas'</span>, <span class="hljs-built_in">this</span>);}<span class="hljs-built_in">this</span>.ctx.setFillStyle(<span class="hljs-string">'#fff'</span>);<span class="hljs-built_in">this</span>.ctx.fillRect(<span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">200</span>, <span class="hljs-number">210</span>);<span class="hljs-comment">// this.properties.src 对应上一步生成的本地路径</span><span class="hljs-built_in">this</span>.ctx.drawImage(<span class="hljs-built_in">this</span>.properties.src, <span class="hljs-number">25</span>, <span class="hljs-number">20</span>, <span class="hljs-number">150</span>, <span class="hljs-number">150</span>);<span class="hljs-built_in">this</span>.ctx.save();<span class="hljs-built_in">this</span>.ctx.setFontSize(<span class="hljs-number">16</span>);<span class="hljs-built_in">this</span>.ctx.setTextAlign(<span class="hljs-string">'left'</span>);<span class="hljs-built_in">this</span>.ctx.setFillStyle(<span class="hljs-string">'#333333'</span>);<span class="hljs-comment">// 绘制多行文字</span><span class="hljs-comment">// 这里指定每行文字高 30</span><span class="hljs-keyword">let</span> lineWidth = <span class="hljs-number">0</span>;<span class="hljs-keyword">let</span> lastSubStrIndex = <span class="hljs-number">0</span>;<span class="hljs-keyword">let</span> startY = <span class="hljs-number">190</span>;<span class="hljs-keyword">const</span> startX = <span class="hljs-number">25</span>;<span class="hljs-keyword">const</span> wordsHeight = <span class="hljs-number">30</span>;<span class="hljs-keyword">const</span> { description } = <span class="hljs-built_in">this</span>.properties;<span class="hljs-keyword">for</span> (<span class="hljs-keyword">let</span> i = <span class="hljs-number">0</span>; i < description.length; i++) {lineWidth += <span class="hljs-built_in">this</span>.ctx.measureText(description[i]).width;<span class="hljs-keyword">if</span> (lineWidth > <span class="hljs-number">150</span>) {<span class="hljs-built_in">this</span>.ctx.fillText(description.substring(lastSubStrIndex, i),startX,startY,);startY += wordsHeight;lineWidth = <span class="hljs-number">0</span>;lastSubStrIndex = i;}<span class="hljs-keyword">if</span> (i === description.length - <span class="hljs-number">1</span>) {<span class="hljs-built_in">this</span>.ctx.fillText(description.substring(lastSubStrIndex, i + <span class="hljs-number">1</span>),startX,startY,);}}<span class="hljs-built_in">this</span>.ctx.restore();<span class="hljs-built_in">this</span>.ctx.draw();</code></pre><h3 id="保存相册"><a href="#保存相册" class="headerlink" title="保存相册"></a>保存相册</h3><pre><code class="hljs javascript"><span class="hljs-keyword">const</span> scale = app.globalData.pixelRatio;wx.canvasToTempFilePath({x: <span class="hljs-number">0</span>,y: <span class="hljs-number">0</span>,width: <span class="hljs-number">200</span>,height: <span class="hljs-number">210</span>,destWidth: <span class="hljs-number">200</span> * scale,destHeight: <span class="hljs-number">210</span> * scale,canvasId: <span class="hljs-string">'miniCanvas'</span>,success: <span class="hljs-function">(<span class="hljs-params">res</span>) =></span> {<span class="hljs-built_in">console</span>.log(<span class="hljs-string">'onSave -> res.tempFilePath'</span>, res.tempFilePath);<span class="hljs-comment">// 获取到临时路径,可以保存相册了</span>wx.saveImageToPhotosAlbum({filePath: res.tempFilePath,success: <span class="hljs-function">() =></span> {wx.showToast({title: <span class="hljs-string">'保存成功,从相册中分享给朋友吧'</span>,icon: <span class="hljs-string">'none'</span>,duration: <span class="hljs-number">3000</span>,});},fail: <span class="hljs-function">() =></span> {wx.showToast({title: <span class="hljs-string">'图片保存失败,请稍候重试'</span>,icon: <span class="hljs-string">'none'</span>,duration: <span class="hljs-number">2000</span>,});},},<span class="hljs-built_in">this</span>,);},fail: <span class="hljs-function">() =></span> {wx.showToast({title: <span class="hljs-string">'图片保存失败,请稍候重试'</span>,icon: <span class="hljs-string">'none'</span>,duration: <span class="hljs-number">2000</span>,});},},<span class="hljs-built_in">this</span>,);</code></pre><h2 id="其他问题"><a href="#其他问题" class="headerlink" title="其他问题"></a>其他问题</h2><blockquote><p>因为保存系统相册是需要对应的权限的,第一次调用保存相册的时候,系统会自动弹出获取权限的弹窗,这里就存在两种情况:</p><ul><li>如果用户点击了同意,那么之后都会有权限了,这是正常情况</li><li>如果点击了拒绝,那么下次用户再次点击保存相册的时候,系统不会再次弹出获取权限的弹窗,这种情况需要我们来额外处理,比如自定义一个权限弹窗,引导用户去打开权限</li></ul></blockquote><pre><code class="hljs javascript"><span class="hljs-comment">// 相册权限判断</span>wx.getSetting({success: <span class="hljs-function">(<span class="hljs-params">res</span>) =></span> {<span class="hljs-keyword">if</span> (res.authSetting[<span class="hljs-string">'scope.writePhotosAlbum'</span>]) {<span class="hljs-comment">// 如果存在授权,可直接调用 canvas 绘制及保存相册的方法</span><span class="hljs-keyword">return</span>;}<span class="hljs-comment">// 不存在授权,提前授权</span>wx.authorize({scope: <span class="hljs-string">'scope.writePhotosAlbum'</span>,success: <span class="hljs-function">() =></span> {<span class="hljs-comment">// 授权成功,可直接调用 canvas 绘制及保存相册的方法</span>},fail: <span class="hljs-function">() =></span> {<span class="hljs-comment">// 对应相册授权被拒绝后的情况</span><span class="hljs-comment">// 自定义授权弹窗,引导去授权</span>},});},});<span class="hljs-comment">// wxml 简易版授权弹窗</span><view <span class="hljs-class"><span class="hljs-keyword">class</span></span>=<span class="hljs-string">'minicode-dialog'</span>><view <span class="hljs-class"><span class="hljs-keyword">class</span></span>=<span class="hljs-string">'minicode-dialog-header'</span>>尚未获取保存相册的权限,请先授权吧</view><view <span class="hljs-class"><span class="hljs-keyword">class</span></span>=<span class="hljs-string">'minicode-dialog-footer'</span>><button<span class="hljs-class"><span class="hljs-keyword">class</span></span>=<span class="hljs-string">'minicode-dialog-action'</span>open-type=<span class="hljs-string">'openSetting'</span>bindtap=<span class="hljs-string">'onConfirm'</span>>授权</button><button <span class="hljs-class"><span class="hljs-keyword">class</span></span>=<span class="hljs-string">'minicode-dialog-action'</span> bindtap=<span class="hljs-string">'onCancel'</span>>取消</button></view></view>;</code></pre><h2 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h2><p>总体来说,需求并不复杂,但由于第一次接触,也花费了一些时间。大部分时间都是在查找微信文档以及根据文档的内容来制定解决方案,果然还是带着需求的目的去学习是最快的,吹皮的资本又多了一个,哥也是搞过小程序的人~~~</p>]]></content>
<summary type="html"><p>兵来将挡,水来土掩</p></summary>
<category term="前端" scheme="https://floiges.github.io/categories/%E5%89%8D%E7%AB%AF/"/>
<category term="小程序" scheme="https://floiges.github.io/tags/%E5%B0%8F%E7%A8%8B%E5%BA%8F/"/>
</entry>
<entry>
<title>element-ui + vue-cropper 图片裁剪后上传</title>
<link href="https://floiges.github.io/2020/04/14/element-ui-vue-cropper-%E5%9B%BE%E7%89%87%E8%A3%81%E5%89%AA%E5%90%8E%E4%B8%8A%E4%BC%A0/"/>
<id>https://floiges.github.io/2020/04/14/element-ui-vue-cropper-%E5%9B%BE%E7%89%87%E8%A3%81%E5%89%AA%E5%90%8E%E4%B8%8A%E4%BC%A0/</id>
<published>2020-04-14T18:12:22.000Z</published>
<updated>2022-07-06T09:29:32.620Z</updated>
<content type="html"><![CDATA[<p>兵来将挡,水来土掩</p><a id="more"></a><h3 id="前提"><a href="#前提" class="headerlink" title="前提"></a>前提</h3><ul><li><a href="https://github.com/xyxiao001/vue-cropper">vue-cropper</a></li><li><a href="https://element.eleme.cn/#/zh-CN/component/upload">element-ui upload</a></li><li>整体分为两个组件来做<ul><li><code>cropper.vue</code> 主要负责图片裁剪,将裁剪之后的数据传递出来</li><li><code>crop-upload.vue</code>,引入 <code>cropper.vue</code> 作为子组件,将裁剪后的数据上传、显示上传列表等功能</li></ul></li></ul><h3 id="cropper-vue"><a href="#cropper-vue" class="headerlink" title="cropper.vue"></a><code>cropper.vue</code></h3><blockquote><p>这一步没什么难度,单独抽出来一个组件只是为了项目结构能清晰一点。<br>按照文档中的 demo 来设置即可,其中部分属性项目 demo 中没有提及,直接去看源码即可。</p></blockquote><h4 id="要注意的是,组件的外部一定要设置固定的宽高"><a href="#要注意的是,组件的外部一定要设置固定的宽高" class="headerlink" title="要注意的是,组件的外部一定要设置固定的宽高"></a>要注意的是,组件的外部一定要设置固定的宽高</h4><pre><code class="hljs html"><span class="hljs-comment"><!--crop-box 设置固定宽高--></span><span class="hljs-tag"><<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"crop-box"</span>></span><span class="hljs-tag"><<span class="hljs-name">vue-cropper</span></span><span class="hljs-tag"><span class="hljs-attr">:autoCrop</span>=<span class="hljs-string">"cropperOption.autoCrop"</span></span><span class="hljs-tag"><span class="hljs-attr">:autoCropHeight</span>=<span class="hljs-string">"cropperOption.autoCropHeight"</span></span><span class="hljs-tag"><span class="hljs-attr">:autoCropWidth</span>=<span class="hljs-string">"cropperOption.autoCropWidth"</span></span><span class="hljs-tag"><span class="hljs-attr">:canMove</span>=<span class="hljs-string">"cropperOption.canMove"</span></span><span class="hljs-tag"><span class="hljs-attr">:canMoveBox</span>=<span class="hljs-string">"cropperOption.canMoveBox"</span></span><span class="hljs-tag"><span class="hljs-attr">:canScale</span>=<span class="hljs-string">"cropperOption.canScale"</span></span><span class="hljs-tag"><span class="hljs-attr">:centerBox</span>=<span class="hljs-string">"cropperOption.centerBox"</span></span><span class="hljs-tag"><span class="hljs-attr">:enlarge</span>=<span class="hljs-string">"cropperOption.enlarge"</span></span><span class="hljs-tag"><span class="hljs-attr">:fixedBox</span>=<span class="hljs-string">"cropperOption.fixedBox"</span></span><span class="hljs-tag"><span class="hljs-attr">:fixed</span>=<span class="hljs-string">"cropperOption.fixed"</span></span><span class="hljs-tag"><span class="hljs-attr">:full</span>=<span class="hljs-string">"cropperOption.full"</span></span><span class="hljs-tag"><span class="hljs-attr">:high</span>=<span class="hljs-string">"cropperOption.high"</span></span><span class="hljs-tag"><span class="hljs-attr">:img</span>=<span class="hljs-string">"cropperOption.img"</span></span><span class="hljs-tag"><span class="hljs-attr">:info</span>=<span class="hljs-string">"true"</span></span><span class="hljs-tag"><span class="hljs-attr">:infoTrue</span>=<span class="hljs-string">"cropperOption.infoTrue"</span></span><span class="hljs-tag"><span class="hljs-attr">:limitMinSize</span>=<span class="hljs-string">"cropperOption.limitMinSize"</span></span><span class="hljs-tag"><span class="hljs-attr">:maxImgSize</span>=<span class="hljs-string">"cropperOption.maxImgSize"</span></span><span class="hljs-tag"><span class="hljs-attr">:mode</span>=<span class="hljs-string">"cropperOption.mode"</span></span><span class="hljs-tag"><span class="hljs-attr">:original</span>=<span class="hljs-string">"cropperOption.original"</span></span><span class="hljs-tag"><span class="hljs-attr">:outputSize</span>=<span class="hljs-string">"cropperOption.size"</span></span><span class="hljs-tag"><span class="hljs-attr">:outputType</span>=<span class="hljs-string">"cropperOption.outputType"</span></span><span class="hljs-tag">@<span class="hljs-attr">cropMoving</span>=<span class="hljs-string">"onCropMoving"</span></span><span class="hljs-tag">@<span class="hljs-attr">imgLoad</span>=<span class="hljs-string">"onImgLoad"</span></span><span class="hljs-tag">@<span class="hljs-attr">realTime</span>=<span class="hljs-string">"onRealTime"</span></span><span class="hljs-tag"><span class="hljs-attr">ref</span>=<span class="hljs-string">"cropper"</span></span><span class="hljs-tag">></span><span class="hljs-tag"></<span class="hljs-name">vue-cropper</span>></span><span class="hljs-tag"></<span class="hljs-name">div</span>></span></code></pre><h4 id="组件中各个属性的含义如下:"><a href="#组件中各个属性的含义如下:" class="headerlink" title="组件中各个属性的含义如下:"></a>组件中各个属性的含义如下:</h4><pre><code class="hljs javascript">cropperOption: {img: <span class="hljs-string">''</span>, <span class="hljs-comment">// 需要裁剪的图片</span>size: <span class="hljs-number">1</span>, <span class="hljs-comment">// 输出图片压缩比, 默认 1</span>full: <span class="hljs-literal">false</span>, <span class="hljs-comment">// 是否输出原图比例的截图</span>infoTrue: <span class="hljs-literal">false</span>, <span class="hljs-comment">// 截图信息展示是否时真实的输出宽高</span>outputType: <span class="hljs-string">'png'</span>, <span class="hljs-comment">// 输出的图片格式</span>canScale: <span class="hljs-literal">false</span>, <span class="hljs-comment">// 是否开启滚轮缩放大小</span>canMove: <span class="hljs-literal">false</span>, <span class="hljs-comment">// 能否拖动图片</span>canMoveBox: <span class="hljs-literal">true</span>, <span class="hljs-comment">// 能否拖动截图框</span>fixed: <span class="hljs-literal">true</span>, <span class="hljs-comment">// 项目要求方形裁剪,因此固定宽高比,默认宽高比是 1:1</span>fixedBox: <span class="hljs-literal">false</span>, <span class="hljs-comment">// 截图框固定大小</span>original: <span class="hljs-literal">false</span>, <span class="hljs-comment">// 上传图片时,是否显示原始宽高</span>autoCrop: <span class="hljs-literal">true</span>, <span class="hljs-comment">// 是否自动生成截图框</span><span class="hljs-comment">// 只有自动截图开启 宽度高度才生效</span>autoCropWidth: <span class="hljs-number">200</span>,autoCropHeight: <span class="hljs-number">200</span>,centerBox: <span class="hljs-literal">true</span>, <span class="hljs-comment">// 截图框是否限制在图片里(只有在自动生成截图框时才生效)</span>high: <span class="hljs-literal">false</span>, <span class="hljs-comment">// 是否根据 dpr 生成适合屏幕的高清图片</span>cropData: {},enlarge: <span class="hljs-number">1</span>, <span class="hljs-comment">// 按照截图框比例输出,默认 1</span>mode: <span class="hljs-string">'contain'</span>, <span class="hljs-comment">// 图片的默认渲染方式</span>maxImgSize: <span class="hljs-number">2000</span>, <span class="hljs-comment">// 上传图片时图片最大大小(默认会压缩尺寸到这个大小)</span>limitMinSize: [<span class="hljs-number">200</span>, <span class="hljs-number">200</span>] <span class="hljs-comment">// 截图框最小限制</span>}</code></pre><h4 id="最终确定裁剪时,调用下面的方法获取裁剪后的数据"><a href="#最终确定裁剪时,调用下面的方法获取裁剪后的数据" class="headerlink" title="最终确定裁剪时,调用下面的方法获取裁剪后的数据"></a>最终确定裁剪时,调用下面的方法获取裁剪后的数据</h4><pre><code class="hljs javascript"><span class="hljs-comment">// 获取 blob</span><span class="hljs-built_in">this</span>.$refs.cropper.getCropBlob(<span class="hljs-function">(<span class="hljs-params">blob</span>) =></span> {<span class="hljs-built_in">console</span>.log(<span class="hljs-string">'crop onConfirm -> blob'</span>, blob);});<span class="hljs-comment">// 获取 base64</span><span class="hljs-built_in">this</span>.$refs.cropper.getCropData(<span class="hljs-function">(<span class="hljs-params">blob</span>) =></span> {<span class="hljs-built_in">console</span>.log(<span class="hljs-string">'crop onConfirm -> blob'</span>, blob);});</code></pre><h4 id="cropper-vue-最终代码"><a href="#cropper-vue-最终代码" class="headerlink" title="cropper.vue 最终代码"></a><code>cropper.vue</code> 最终代码</h4><pre><code class="hljs javascript"><!--cropper.vue--><template><div><el-dialog :visible.sync=<span class="hljs-string">"visible"</span> title=<span class="hljs-string">"图片裁剪"</span> width=<span class="hljs-string">"800px"</span>><div <span class="hljs-class"><span class="hljs-keyword">class</span></span>=<span class="hljs-string">"crop-container"</span> v-show=<span class="hljs-string">"!showPreview"</span>><div <span class="hljs-class"><span class="hljs-keyword">class</span></span>=<span class="hljs-string">"crop-box"</span>><vue-cropper:autoCrop=<span class="hljs-string">"cropperOption.autoCrop"</span>:autoCropHeight=<span class="hljs-string">"cropperOption.autoCropHeight"</span>:autoCropWidth=<span class="hljs-string">"cropperOption.autoCropWidth"</span>:canMove=<span class="hljs-string">"cropperOption.canMove"</span>:canMoveBox=<span class="hljs-string">"cropperOption.canMoveBox"</span>:canScale=<span class="hljs-string">"cropperOption.canScale"</span>:centerBox=<span class="hljs-string">"cropperOption.centerBox"</span>:enlarge=<span class="hljs-string">"cropperOption.enlarge"</span>:fixedBox=<span class="hljs-string">"cropperOption.fixedBox"</span>:fixed=<span class="hljs-string">"cropperOption.fixed"</span>:full=<span class="hljs-string">"cropperOption.full"</span>:high=<span class="hljs-string">"cropperOption.high"</span>:img=<span class="hljs-string">"cropperOption.img"</span>:info=<span class="hljs-string">"true"</span>:infoTrue=<span class="hljs-string">"cropperOption.infoTrue"</span>:limitMinSize=<span class="hljs-string">"cropperOption.limitMinSize"</span>:maxImgSize=<span class="hljs-string">"cropperOption.maxImgSize"</span>:mode=<span class="hljs-string">"cropperOption.mode"</span>:original=<span class="hljs-string">"cropperOption.original"</span>:outputSize=<span class="hljs-string">"cropperOption.size"</span>:outputType=<span class="hljs-string">"cropperOption.outputType"</span>@cropMoving=<span class="hljs-string">"onCropMoving"</span>@imgLoad=<span class="hljs-string">"onImgLoad"</span>@realTime=<span class="hljs-string">"onRealTime"</span>ref=<span class="hljs-string">"cropper"</span>></vue-cropper></div><div <span class="hljs-class"><span class="hljs-keyword">class</span></span>=<span class="hljs-string">"crop-action"</span>> <el-button @click=<span class="hljs-string">"onConfirm"</span> type=<span class="hljs-string">"primary"</span>>确 定</el-button><el-button @click=<span class="hljs-string">"showPreview = true"</span>>预 览</el-button><el-button @click=<span class="hljs-string">"onCancel"</span>>取 消</el-button></div></div><div <span class="hljs-class"><span class="hljs-keyword">class</span></span>=<span class="hljs-string">"crop-container"</span> v-show=<span class="hljs-string">"showPreview"</span>><div :style=<span class="hljs-string">"previews.div"</span> <span class="hljs-class"><span class="hljs-keyword">class</span></span>=<span class="hljs-string">"crop-preview"</span>><img :src=<span class="hljs-string">"previews.url"</span> :style=<span class="hljs-string">"previews.img"</span> alt /></div><div <span class="hljs-class"><span class="hljs-keyword">class</span></span>=<span class="hljs-string">"crop-action"</span>><el-button @click=<span class="hljs-string">"onConfirm"</span> type=<span class="hljs-string">"primary"</span>>确 定</el-button><el-button @click=<span class="hljs-string">"showPreview = false"</span>>取消预览</el-button></div></div></el-dialog></div></template><script><span class="hljs-keyword">import</span> { VueCropper } <span class="hljs-keyword">from</span> <span class="hljs-string">'vue-cropper'</span>;<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> {name: <span class="hljs-string">'cropper-upload'</span>,data() {<span class="hljs-keyword">return</span> {visible: <span class="hljs-literal">false</span>,previews: {},showPreview: <span class="hljs-literal">false</span>,crap: <span class="hljs-literal">false</span>,cropperOption: {img: <span class="hljs-string">''</span>,size: <span class="hljs-number">1</span>, <span class="hljs-comment">// 输出图片压缩比, 默认 1</span>full: <span class="hljs-literal">false</span>, <span class="hljs-comment">// 是否输出原图比例的截图</span>infoTrue: <span class="hljs-literal">false</span>, <span class="hljs-comment">// 截图信息展示是否时真实的输出宽高</span>outputType: <span class="hljs-string">'png'</span>,canScale: <span class="hljs-literal">false</span>, <span class="hljs-comment">// 是否开启滚轮缩放大小</span>canMove: <span class="hljs-literal">false</span>, <span class="hljs-comment">// 能否拖动图片</span>canMoveBox: <span class="hljs-literal">true</span>, <span class="hljs-comment">// 能否拖动截图框</span>fixed: <span class="hljs-literal">true</span>, <span class="hljs-comment">// 固定宽高比</span>fixedBox: <span class="hljs-literal">false</span>, <span class="hljs-comment">// 截图框固定大小</span>original: <span class="hljs-literal">false</span>, <span class="hljs-comment">// 上传图片时,是否显示原始宽高</span>autoCrop: <span class="hljs-literal">true</span>, <span class="hljs-comment">// 是否自动生成截图框</span><span class="hljs-comment">// 只有自动截图开启 宽度高度才生效</span>autoCropWidth: <span class="hljs-number">200</span>,autoCropHeight: <span class="hljs-number">200</span>,centerBox: <span class="hljs-literal">true</span>, <span class="hljs-comment">// 截图框是否限制在图片里(只有在自动生成截图框时才生效)</span>high: <span class="hljs-literal">false</span>, <span class="hljs-comment">// 是否根据 dpr 生成适合屏幕的高清图片</span>cropData: {},enlarge: <span class="hljs-number">1</span>, <span class="hljs-comment">// 按照截图框比例输出,默认 1</span>mode: <span class="hljs-string">'contain'</span>, <span class="hljs-comment">// 图片的默认渲染方式</span>maxImgSize: <span class="hljs-number">2000</span>, <span class="hljs-comment">// 上传图片时图片最大大小(默认会压缩尺寸到这个大小)</span>limitMinSize: [<span class="hljs-number">200</span>, <span class="hljs-number">200</span>] <span class="hljs-comment">// 截图框最小限制</span>}}; }, computed: { cropper() { <span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>.$refs.cropper; }, },methods: {show(file) {<span class="hljs-built_in">this</span>.cropperOption.img = file.url;<span class="hljs-built_in">this</span>.$nextTick(<span class="hljs-function">() =></span> {<span class="hljs-built_in">this</span>.visible = <span class="hljs-literal">true</span>;});},hide() {<span class="hljs-built_in">this</span>.visible = <span class="hljs-literal">false</span>;},<span class="hljs-comment">// 实时预览函数</span><span class="hljs-comment">// data 中保存了需要预览的样式及 url,直接用就行了</span>onRealTime(data) {<span class="hljs-comment">// console.log('onRealTime -> data', data);</span><span class="hljs-built_in">this</span>.previews = data;},onImgLoad(msg) { <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'onImgLoad -> msg'</span>, msg);<span class="hljs-comment">// 图片加载完成后,获取图片的真实宽高</span><span class="hljs-comment">// 以最小的那个值作为裁剪框默认大小</span> <span class="hljs-keyword">const</span> { trueWidth, trueHeight } = <span class="hljs-built_in">this</span>.cropper; <span class="hljs-keyword">const</span> width = <span class="hljs-built_in">Math</span>.min(trueWidth, trueHeight); <span class="hljs-built_in">this</span>.cropperOption.autoCropWidth = width; <span class="hljs-built_in">this</span>.cropperOption.autoCropHeight = width;},onCropMoving(data) {<span class="hljs-built_in">this</span>.cropperOption.cropData = data;},onConfirm() {<span class="hljs-comment">// 获取裁剪后的 blob 数据,传递到外部</span><span class="hljs-built_in">this</span>.$refs.cropper.getCropBlob(<span class="hljs-function"><span class="hljs-params">blob</span> =></span> { <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'crop onConfirm -> blob'</span>, blob); <span class="hljs-built_in">this</span>.hide(); <span class="hljs-built_in">this</span>.$emit(<span class="hljs-string">'on-finish'</span>, blob);});},onCancel() {<span class="hljs-built_in">this</span>.hide();<span class="hljs-built_in">this</span>.$emit(<span class="hljs-string">'on-cancel'</span>);}},components: {VueCropper}};</script><style lang=<span class="hljs-string">"stylus"</span> scoped>.crop-container { display: flex; align-items: center;}.crop-box { margin: <span class="hljs-number">0</span> auto; width: <span class="hljs-number">700</span>px; height: <span class="hljs-number">600</span>px;}.crop-preview { margin: auto; border: 1px dotted #e4e4e4; overflow: hidden;}.crop-action { width: <span class="hljs-number">100</span>px; display: flex; flex-direction: column; align-items: center;}.el-button { width: <span class="hljs-number">98</span>px; margin-bottom: <span class="hljs-number">20</span>px; margin-left: <span class="hljs-number">10</span>px;}</style></code></pre><h3 id="crop-upload-vue"><a href="#crop-upload-vue" class="headerlink" title="crop-upload.vue"></a><code>crop-upload.vue</code></h3><h4 id="思路"><a href="#思路" class="headerlink" title="思路"></a>思路</h4><ul><li>因为需要先裁剪再上传,因此需要关闭自动上传设置:<code>auto-upload</code> 设置为 false</li><li>之后,利用上一步裁剪后的数据进行 <code>FormData</code> 上传即可</li><li>还有就是,没有用 el-upload 自带的 <code>file-list</code>,主要是为了能获取到当前裁剪的是哪个图片,方便进行对应的更新</li></ul><h4 id="最终代码"><a href="#最终代码" class="headerlink" title="最终代码"></a>最终代码</h4><pre><code class="hljs javascript"><template><div <span class="hljs-class"><span class="hljs-keyword">class</span></span>=<span class="hljs-string">"crop-upload"</span>><div <span class="hljs-class"><span class="hljs-keyword">class</span></span>=<span class="hljs-string">"crop-upload-list"</span>><ul <span class="hljs-class"><span class="hljs-keyword">class</span></span>=<span class="hljs-string">"el-upload-list el-upload-list--picture-card"</span>><li:key=<span class="hljs-string">"item.url"</span>:tabindex=<span class="hljs-string">"index"</span><span class="hljs-class"><span class="hljs-keyword">class</span></span>=<span class="hljs-string">"el-upload-list__item is-success"</span>v-<span class="hljs-keyword">for</span>=<span class="hljs-string">"(item, index) in fileList"</span>><img :src=<span class="hljs-string">"item.url"</span> alt <span class="hljs-class"><span class="hljs-keyword">class</span></span>=<span class="hljs-string">"el-upload-list__item-thumbnail"</span> /><a <span class="hljs-class"><span class="hljs-keyword">class</span></span>=<span class="hljs-string">"el-upload-list__item-name"</span>><i <span class="hljs-class"><span class="hljs-keyword">class</span></span>=<span class="hljs-string">"el-icon-document"</span>></i></a><label <span class="hljs-class"><span class="hljs-keyword">class</span></span>=<span class="hljs-string">"el-upload-list__item-status-label"</span>><i <span class="hljs-class"><span class="hljs-keyword">class</span></span>=<span class="hljs-string">"el-icon-upload-success el-icon-check"</span>></i></label><i <span class="hljs-class"><span class="hljs-keyword">class</span></span>=<span class="hljs-string">"el-icon-close"</span>></i><i <span class="hljs-class"><span class="hljs-keyword">class</span></span>=<span class="hljs-string">"el-icon-close-tip"</span>>按 <span class="hljs-keyword">delete</span> 键可删除</i><!----><span <span class="hljs-class"><span class="hljs-keyword">class</span></span>=<span class="hljs-string">"el-upload-list__item-actions"</span>><span @click=<span class="hljs-string">"onEdit(index)"</span> <span class="hljs-class"><span class="hljs-keyword">class</span></span>=<span class="hljs-string">"el-upload-list__item-preview"</span>><i <span class="hljs-class"><span class="hljs-keyword">class</span></span>=<span class="hljs-string">"el-icon-edit"</span>></i></span><span @click=<span class="hljs-string">"onPreview(item)"</span> <span class="hljs-class"><span class="hljs-keyword">class</span></span>=<span class="hljs-string">"el-upload-list__item-preview"</span>><i <span class="hljs-class"><span class="hljs-keyword">class</span></span>=<span class="hljs-string">"el-icon-zoom-in"</span>></i></span><span @click=<span class="hljs-string">"onRemove(index)"</span> <span class="hljs-class"><span class="hljs-keyword">class</span></span>=<span class="hljs-string">"el-upload-list__item-delete"</span>><i <span class="hljs-class"><span class="hljs-keyword">class</span></span>=<span class="hljs-string">"el-icon-delete"</span>></i></span></span></li></ul><el-upload:action=<span class="hljs-string">"uploadUrl"</span>:auto-upload=<span class="hljs-string">"false"</span>:data=<span class="hljs-string">"uploadData"</span>:headers=<span class="hljs-string">"headers"</span>:limit=<span class="hljs-string">"limit"</span>:on-change=<span class="hljs-string">"onChange"</span>:on-exceed=<span class="hljs-string">"onExceed"</span>:show-file-list=<span class="hljs-string">"false"</span>list-type=<span class="hljs-string">"picture-card"</span>ref=<span class="hljs-string">"upload"</span>><i <span class="hljs-class"><span class="hljs-keyword">class</span></span>=<span class="hljs-string">"el-icon-plus"</span>></i></el-upload></div><cropper:visible.sync=<span class="hljs-string">"cropperVisible"</span>@on-cancel=<span class="hljs-string">"onCropCancel"</span>@on-finish=<span class="hljs-string">"onCropFinish"</span>ref=<span class="hljs-string">"cropper"</span>></cropper><el-dialog :visible.sync=<span class="hljs-string">"dialogVisible"</span>><img :src=<span class="hljs-string">"dialogImageUrl"</span> alt width=<span class="hljs-string">"100%"</span> /></el-dialog></div></template><script><span class="hljs-keyword">import</span> Cropper <span class="hljs-keyword">from</span> <span class="hljs-string">'./cropper.vue'</span>;<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> {props: {limit: {type: <span class="hljs-built_in">Number</span>,<span class="hljs-keyword">default</span>: <span class="hljs-number">10</span>},fileList: {type: <span class="hljs-built_in">Array</span>,<span class="hljs-keyword">default</span>: <span class="hljs-function">() =></span> []}},data() {<span class="hljs-keyword">return</span> {headers: {<span class="hljs-comment">// your headers</span>},uploadUrl: <span class="hljs-string">'upload url'</span>,uploadData: {},dialogVisible: <span class="hljs-literal">false</span>,dialogImageUrl: <span class="hljs-string">''</span>,cropperVisible: <span class="hljs-literal">false</span>,selectedCropIndex: <span class="hljs-number">-1</span>};},computed: {upload() {<span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>.$refs.upload;},cropper() {<span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>.$refs.cropper;}},created() {},methods: { <span class="hljs-comment">// 删除</span>onRemove(index) {<span class="hljs-keyword">const</span> newFileList = <span class="hljs-built_in">this</span>.fileList;newFileList.splice(index, <span class="hljs-number">1</span>);<span class="hljs-built_in">this</span>.$emit(<span class="hljs-string">'update:fileList'</span>, newFileList);}, <span class="hljs-comment">// 预览</span>onPreview(item) {<span class="hljs-built_in">this</span>.dialogImageUrl = item.url;<span class="hljs-built_in">this</span>.dialogVisible = <span class="hljs-literal">true</span>;}, <span class="hljs-comment">// 弹出裁剪组件</span>onEdit(index) {<span class="hljs-built_in">this</span>.selectedCropIndex = index;<span class="hljs-keyword">const</span> file = <span class="hljs-built_in">this</span>.fileList[index];<span class="hljs-built_in">this</span>.cropper.show(file);},onExceed() {<span class="hljs-built_in">this</span>.$message({type: <span class="hljs-string">'error'</span>,message: <span class="hljs-string">'超出上传数量限制,无法继续上传'</span>});},<span class="hljs-comment">// 文件状态改变时的钩子,添加文件,弹出裁剪组件</span>onChange(file, fileList) {<span class="hljs-built_in">this</span>.cropper.show(file);}, <span class="hljs-comment">// 监听裁剪结束,进行上传</span>onCropFinish(data) {<span class="hljs-keyword">const</span> loading = <span class="hljs-built_in">this</span>.$loading({lock: <span class="hljs-literal">true</span>,text: <span class="hljs-string">'Loading'</span>,spinner: <span class="hljs-string">'el-icon-loading'</span>,background: <span class="hljs-string">'rgba(0, 0, 0, 0.7)'</span>});<span class="hljs-built_in">this</span>.doUpload(data).then(<span class="hljs-function"><span class="hljs-params">url</span> =></span> {<span class="hljs-comment">// 更新对应 index 的 url</span><span class="hljs-keyword">const</span> newFileList = <span class="hljs-built_in">this</span>.fileList;<span class="hljs-keyword">const</span> item = { url, };<span class="hljs-keyword">if</span> (<span class="hljs-built_in">this</span>.selectedCropIndex === <span class="hljs-number">-1</span>) {newFileList.push(item);} <span class="hljs-keyword">else</span> {newFileList[<span class="hljs-built_in">this</span>.selectedCropIndex] = item;}<span class="hljs-built_in">this</span>.$emit(<span class="hljs-string">'update:fileList'</span>, newFileList);}).finally(<span class="hljs-function">() =></span> {<span class="hljs-built_in">this</span>.reset();loading.close();});}, <span class="hljs-comment">// 取消裁剪</span>onCropCancel() {<span class="hljs-built_in">this</span>.reset();},doUpload(data) {<span class="hljs-comment">// your custom upload</span>},reset() {<span class="hljs-built_in">this</span>.selectedCropIndex = <span class="hljs-number">-1</span>;}},components: {Cropper}};</script><style lang=<span class="hljs-string">"stylus"</span> scoped>.crop-upload-list { display: flex;}</style></code></pre>]]></content>
<summary type="html"><p>兵来将挡,水来土掩</p></summary>
<category term="前端" scheme="https://floiges.github.io/categories/%E5%89%8D%E7%AB%AF/"/>
<category term="vue" scheme="https://floiges.github.io/tags/vue/"/>
</entry>
<entry>
<title>我又学了几条 Git 哦</title>
<link href="https://floiges.github.io/2020/03/22/%E6%88%91%E5%8F%88%E5%AD%A6%E4%BA%86%E5%87%A0%E6%9D%A1-Git-%E5%93%A6/"/>
<id>https://floiges.github.io/2020/03/22/%E6%88%91%E5%8F%88%E5%AD%A6%E4%BA%86%E5%87%A0%E6%9D%A1-Git-%E5%93%A6/</id>
<published>2020-03-22T15:03:52.000Z</published>
<updated>2022-07-06T09:29:32.620Z</updated>
<content type="html"><![CDATA[<p>感觉我又学到了好多的姿势。。。</p><a id="more"></a><blockquote><p>记得多用</p></blockquote><h3 id="获取所有操作历史"><a href="#获取所有操作历史" class="headerlink" title="获取所有操作历史"></a>获取所有操作历史</h3><pre><code class="hljs bash">git reflog</code></pre><h3 id="重置相应提交"><a href="#重置相应提交" class="headerlink" title="重置相应提交"></a>重置相应提交</h3><blockquote><p>这个命令我经常用。。。</p></blockquote><pre><code class="hljs bash">git reset --hard <相应提交的哈希值>/<相应的分支></code></pre><h3 id="查看当前分支和master分支的不同"><a href="#查看当前分支和master分支的不同" class="headerlink" title="查看当前分支和master分支的不同"></a>查看当前分支和<code>master</code>分支的不同</h3><blockquote><p>偶尔会用到,大部分时候我都用 <code>tig</code></p></blockquote><pre><code class="hljs bash">git diff master..my-branch</code></pre><h3 id="编辑上次提交"><a href="#编辑上次提交" class="headerlink" title="编辑上次提交"></a>编辑上次提交</h3><pre><code class="hljs bash">git commit --amend -m <span class="hljs-string">"更好的提交说明"</span><span class="hljs-comment"># 保持提交日志不变的办法</span>git add . && git commit --amend --no-edit</code></pre><h3 id="搜索代码库内容"><a href="#搜索代码库内容" class="headerlink" title="搜索代码库内容"></a>搜索代码库内容</h3><pre><code class="hljs bash"><span class="hljs-comment"># 查询代码中是否曾经出现过 search keyword</span>git <span class="hljs-built_in">log</span> -S[search keyword]<span class="hljs-comment">#例如</span>git <span class="hljs-built_in">log</span> -SsecurityKey <span class="hljs-comment"># 列出所有修改内容中包含 securityKey 的 commits</span>git <span class="hljs-built_in">log</span> -SsecurityKey -p <span class="hljs-comment"># -p 选项可以查看每个 commit 具体的内容</span></code></pre>]]></content>
<summary type="html"><p>感觉我又学到了好多的姿势。。。</p></summary>
<category term="工具" scheme="https://floiges.github.io/categories/%E5%B7%A5%E5%85%B7/"/>
<category term="git" scheme="https://floiges.github.io/tags/git/"/>
</entry>
<entry>
<title>在 VSCode 中整合 Prettier、ESLint、Airbnb</title>
<link href="https://floiges.github.io/2020/03/17/%E5%9C%A8-VSCode-%E4%B8%AD%E6%95%B4%E5%90%88-Prettier%E3%80%81ESLint%E3%80%81Airbnb/"/>
<id>https://floiges.github.io/2020/03/17/%E5%9C%A8-VSCode-%E4%B8%AD%E6%95%B4%E5%90%88-Prettier%E3%80%81ESLint%E3%80%81Airbnb/</id>
<published>2020-03-17T10:07:50.000Z</published>
<updated>2022-07-06T09:29:32.620Z</updated>
<content type="html"><![CDATA[<p>谁不想愉快的编码呢???</p><a id="more"></a><blockquote><p>格式化代码和坚持风格指南是一项细致且耗时的任务。真的要纯靠人力去做的话,光是在检查分号和尾逗号这两建件工作就让人望而却步了。幸运的是,现在我们有很好的工具来帮助我们去实现,省时、省力、省心。<br>Update:</p><p>说一下用了大概一周的感觉,如果是新项目的话确实很舒服。但如果是老项目,集成之后,哇,满屏的错误提示,各种提示格式不合法阿之类的。。。。。</p><p>所以在老项目里面,我暂时把 <code>eslint-plugin-prettier</code> 的配置注释掉了</p><pre><code class="hljs json"><span class="hljs-comment">// .eslintrc</span>{<span class="hljs-attr">"extends"</span>: [<span class="hljs-string">"airbnb"</span>, <span class="hljs-string">"prettier"</span>],<span class="hljs-comment">// "plugins": ["prettier"],</span><span class="hljs-attr">"rules"</span>: {<span class="hljs-attr">"prettier/prettier"</span>: [<span class="hljs-string">"error"</span>]}}</code></pre></blockquote><h2 id="Step-1"><a href="#Step-1" class="headerlink" title="Step 1"></a>Step 1</h2><p><code>VSCode</code> 中安装 <code>ESLint</code> 和 <code>Prettier</code> 两款插件</p><h2 id="Step-2"><a href="#Step-2" class="headerlink" title="Step 2"></a>Step 2</h2><p>项目中安装开发环境依赖:</p><pre><code class="hljs bash">npm install eslint prettier -D</code></pre><h2 id="Step-3"><a href="#Step-3" class="headerlink" title="Step 3"></a>Step 3</h2><p>安装<a href="https://github.com/airbnb/javascript/tree/master/packages/eslint-config-airbnb"> Airbnb config</a>,如果使用的是 <code>npm 5+</code> 的版本,运行如下命令安装 config 及其所有的依赖:</p><pre><code class="hljs bash">npx install-peerdeps --dev eslint-config-airbnb</code></pre><h2 id="Step-4"><a href="#Step-4" class="headerlink" title="Step 4"></a>Step 4</h2><ul><li>安装 <code>eslint-config-prettier</code>,禁用 <code>ESLint</code> 的格式化,避免和 <code>Prettier</code> 冲突</li><li>安装 <code>eslint-plugin-prettier</code>,当代码格式存在问题的时候,<code>ESLint</code> 会有相应的错误提示</li></ul><pre><code class="hljs bash">npm install eslint-config-prettier eslint-plugin-prettier -D</code></pre><h2 id="Step-5"><a href="#Step-5" class="headerlink" title="Step 5"></a>Step 5</h2><p>在项目根目录下,新建 <code>.eslintrc</code> 文件,文件内容如下:</p><pre><code class="hljs json">{<span class="hljs-attr">"extends"</span>: [<span class="hljs-string">"airbnb"</span>, <span class="hljs-string">"prettier"</span>],<span class="hljs-attr">"plugins"</span>: [<span class="hljs-string">"prettier"</span>],<span class="hljs-attr">"rules"</span>: {<span class="hljs-attr">"prettier/prettier"</span>: [<span class="hljs-string">"error"</span>]}}</code></pre><h2 id="Step-6"><a href="#Step-6" class="headerlink" title="Step 6"></a>Step 6</h2><p>在项目根目录下,新建 <code>.prettierrc</code> 文件,输入一些控制代码格式化的相关设置,文件内容如下:</p><pre><code class="hljs json">{ <span class="hljs-attr">"printWidth"</span>: <span class="hljs-number">100</span>, <span class="hljs-attr">"singleQuote"</span>: <span class="hljs-literal">true</span>, <span class="hljs-string">"tabWidth"</span>: <span class="hljs-number">2</span>}</code></pre><h2 id="Step-7"><a href="#Step-7" class="headerlink" title="Step 7"></a>Step 7</h2><p>设置 <code>VSCode</code> 在保存的时候进行格式化,在 <code>VSCode</code> 的配置文件中输入:</p><pre><code class="hljs json">"editor.formatOnSave": true</code></pre><h2 id="参考链接"><a href="#参考链接" class="headerlink" title="参考链接"></a>参考链接</h2><ul><li><a href="https://blog.echobind.com/integrating-prettier-eslint-airbnb-style-guide-in-vscode-47f07b5d7d6a">Integrating Prettier + ESLint + Airbnb Style Guide in VSCode</a></li></ul>]]></content>
<summary type="html"><p>谁不想愉快的编码呢???</p></summary>
<category term="工具" scheme="https://floiges.github.io/categories/%E5%B7%A5%E5%85%B7/"/>
<category term="VSCode" scheme="https://floiges.github.io/tags/VSCode/"/>
</entry>
<entry>
<title>npm 与 cnpm 打包踩坑小记</title>
<link href="https://floiges.github.io/2020/03/12/npm-%E4%B8%8E-cnpm-%E6%89%93%E5%8C%85%E8%B8%A9%E5%9D%91%E5%B0%8F%E8%AE%B0/"/>
<id>https://floiges.github.io/2020/03/12/npm-%E4%B8%8E-cnpm-%E6%89%93%E5%8C%85%E8%B8%A9%E5%9D%91%E5%B0%8F%E8%AE%B0/</id>
<published>2020-03-12T17:12:47.000Z</published>
<updated>2022-07-06T09:29:32.620Z</updated>
<content type="html"><![CDATA[<p>有的时候掉头发就是这么简单。。。</p><a id="more"></a><h2 id="故事就这么长"><a href="#故事就这么长" class="headerlink" title="故事就这么长"></a>故事就这么长</h2><p>大家都知道,使用 <code>npm scripts</code> 运行命令 的时候,是可以用 <code>process.env.npm_config_argv</code> 来获取命令行参数的,尤其是存在多环境的时候。</p><pre><code class="hljs bash">npm run build --test6</code></pre><p>当我们运行上述命令的时候,我们可以打印一下此时的 <code>process.env.npm_config_argv</code>:</p><pre><code class="hljs bash"><span class="hljs-string">'{"remain":[],"cooked":["run","build:test","--test6"],"original":["run","build:test","--test6"]}'</span></code></pre><p>没错,它的值是一个字符串,因此我们可以先解析一下再取对应的环境变量:</p><pre><code class="hljs javascript"><span class="hljs-comment">// 读取命令行参数确实是哪个 test 环境</span><span class="hljs-keyword">const</span> configArgv = <span class="hljs-built_in">JSON</span>.parse(process.env.npm_config_argv).original;<span class="hljs-built_in">console</span>.log(configArgv);<span class="hljs-comment">// 打印结果</span><span class="hljs-comment">// ["run", "build:test", "--test6"]</span></code></pre><p>一看这是个数组阿,数组第三项就是我们需要的环境信息,简直完美,撸袖子干起来:</p><pre><code class="hljs javascript"><span class="hljs-comment">// 读取命令行参数确实是哪个 test 环境</span><span class="hljs-keyword">const</span> configArgv = <span class="hljs-built_in">JSON</span>.parse(process.env.npm_config_argv).original;<span class="hljs-keyword">const</span> argv = configArgv[<span class="hljs-number">2</span>];<span class="hljs-keyword">const</span> env = argv.substring(<span class="hljs-number">2</span>);</code></pre><p>齐活了,获取到环境变量信息了。打包、测试、发布一套带走。这样一直用了半年多,没出过什么问题,直到。。。。</p><p>公司开搞 <code>k8s</code> 之后,所有项目的打包、发布都要在 <code>Rancher</code> 上操作了,经过运维人员一顿犀利操作之后,我们惊喜的发现打包出现问题了。</p><p>问题就是每次打的包都是线上包,也就是说打包的时候没有获取到环境变量信息,所以就默认打成线上包了。</p><p>经过定位之后发现,部署到 <code>k8s</code> 后,使用的是 <code>cnpm</code> 命令打包,而 <code>cnpm</code> 获取到的命令行参数与 <code>npm</code> 有一些不同的地方:</p><pre><code class="hljs javascript"><span class="hljs-comment">// 读取命令行参数确实是哪个 test 环境</span><span class="hljs-keyword">const</span> configArgv = <span class="hljs-built_in">JSON</span>.parse(process.env.npm_config_argv).original;<span class="hljs-built_in">console</span>.log(configArgv);<span class="hljs-comment">// 打印结果</span><span class="hljs-comment">// ["run", "build:test", ..., ..., "--test6"]</span></code></pre><p>中间的省略号就不表了,闹心,总之我们取数组的第三项肯定不是环境信息了。</p><p>但是我们可以发现 <code>cnpm</code> 和 <code>npm</code> 二者的命令行参数有个共同的地方:环境变量都在数组最后一项,于是我们可以这样:</p><pre><code class="hljs javascript"><span class="hljs-comment">// 读取命令行参数确实是哪个 test 环境</span><span class="hljs-keyword">const</span> configArgv = <span class="hljs-built_in">JSON</span>.parse(process.env.npm_config_argv).original;<span class="hljs-keyword">const</span> argv = configArgv.pop(); <span class="hljs-comment">// 取最后一项</span><span class="hljs-keyword">const</span> env = argv.substring(<span class="hljs-number">2</span>);</code></pre><p>现在又完美啦。。。</p><h2 id="结尾"><a href="#结尾" class="headerlink" title="结尾"></a>结尾</h2><p>现在看来,这个问题并不大,也很好排查。只是在特定时间、特定地点的时候,一个小 <code>bug</code> 也会让你焦头烂额,只能慢慢经历了呗。</p>]]></content>
<summary type="html"><p>有的时候掉头发就是这么简单。。。</p></summary>
<category term="踩坑" scheme="https://floiges.github.io/categories/%E8%B8%A9%E5%9D%91/"/>
</entry>
<entry>
<title>VSCode 插件: Code Spell Checker</title>
<link href="https://floiges.github.io/2020/03/12/VSCode-%E6%8F%92%E4%BB%B6-Code-Spell-Checker/"/>
<id>https://floiges.github.io/2020/03/12/VSCode-%E6%8F%92%E4%BB%B6-Code-Spell-Checker/</id>
<published>2020-03-12T11:02:35.000Z</published>
<updated>2022-07-06T09:29:32.620Z</updated>
<content type="html"><![CDATA[<p>闲来无事,再次折腾一下 VSCode 的配置吧,这次安装了 <code>Code Spell Checker</code>,感觉美滋滋</p><a id="more"></a><p><strong>安装环境为 MacOS</strong></p><h2 id="安装-Code-Spell-Checker"><a href="#安装-Code-Spell-Checker" class="headerlink" title="安装 Code Spell Checker"></a>安装 <code>Code Spell Checker</code></h2><p>首先要声明的是,本人并不是手残党,但难免有打错字符的时候,比如把 <code>transition</code> 打成 <code>tranistion</code>。说实话这种低级错误写代码的时候感觉不到,但是在查找 bug 的时候还是会浪费一定的时间的。</p><p>在开发过程中,我们声明的变量阿、属性名之类的都是英文的,而 <code>Code Spell Checker</code> 不但可以对此拼写检查,还可以让我们养成良好命名的习惯。</p><p>VSCode 插件市场搜素 <code>Code Spell Checker</code>,搜索结果第一个就是了,直接安装即可。</p><h2 id="配置"><a href="#配置" class="headerlink" title="配置"></a>配置</h2><p>VSCode 配置分为用户配置、工作区配置还有当前文件夹配置。</p><ul><li>用户配置</li></ul><p>用户配置的路径一搬为(<code>~/Library/ApplicationSupport/Code/User/settings.json</code>),全局的、通用的配置都可以放在里面。</p><p>例如 <code>mixins</code>,这个拼写对于 <code>Code Spell Checker</code> 来说是不正确的,但是我们在很多工程里都会用到这个,<br>那我们就可以在用户级别的配置文件里添加如下配置:</p><pre><code class="hljs json">"cSpell.userWords": [ <span class="hljs-string">"mixins"</span>]</code></pre><p>这样,工程里所有用到 <code>mixins</code> 的地方就都是合法的了。</p><ul><li>工作区、folder 级别配置</li></ul><p>工作区配置文件是以 <code>.code-workspace</code> 的文件,folder 级别的设置会在项目根文件夹内生成 <code>.vscode/settings.json</code> 文件。</p><p>如果某些变量命名(例如:<code>endcq</code>)只在某个工作区或 folder 生效,则可以在对应的配置文件中添加:</p><pre><code class="hljs json">"cSpell.words": [ <span class="hljs-string">"endcq"</span>]</code></pre><p>如果只想对某些文件类型进行检查呢,比如说只想检查 <code>javascript、css</code>,但不想检查 <code>html</code>,则可以这样配置:</p><pre><code class="hljs json">"cSpell.enableFiletypes": ["javascript", "css", "!html"],</code></pre><h2 id="参考"><a href="#参考" class="headerlink" title="参考"></a>参考</h2><ul><li><a href="https://github.com/streetsidesoftware/vscode-spell-checker/blob/master/packages/client/README.md">更详细的 Code Spell Checker 配置</a></li></ul>]]></content>
<summary type="html"><p>闲来无事,再次折腾一下 VSCode 的配置吧,这次安装了 <code>Code Spell Checker</code>,感觉美滋滋</p></summary>
<category term="工具" scheme="https://floiges.github.io/categories/%E5%B7%A5%E5%85%B7/"/>
<category term="VSCode" scheme="https://floiges.github.io/tags/VSCode/"/>
</entry>
<entry>
<title>Mac 下使用 locate 命令</title>
<link href="https://floiges.github.io/2020/02/27/Mac-%E4%B8%8B%E4%BD%BF%E7%94%A8-locate-%E5%91%BD%E4%BB%A4/"/>
<id>https://floiges.github.io/2020/02/27/Mac-%E4%B8%8B%E4%BD%BF%E7%94%A8-locate-%E5%91%BD%E4%BB%A4/</id>
<published>2020-02-27T19:07:06.000Z</published>
<updated>2022-07-06T09:29:32.620Z</updated>
<content type="html"><![CDATA[<p><code>locate</code> 命令是非常有用的,如果你正在寻找一个隐藏在系统文件夹深处的文件、文件类型、应用程序、扩展,尤其是在<code>Spotlight</code>不能处理的时候。。。</p><a id="more"></a><h3 id="安装"><a href="#安装" class="headerlink" title="安装"></a>安装</h3><p>为了使用 <code>locate</code>,我们需要先创建数据库,当第一次使用此命令时,命令行会有如下提示:</p><pre><code class="hljs bash">WARNING: The locate database (/var/db/locate.database) does not exist.To create the database, run the following <span class="hljs-built_in">command</span>: sudo launchctl load -w /System/Library/LaunchDaemons/com.apple.locate.plistPlease be aware that the database can take some time to generate; oncethe database has been created, this message will no longer appear.</code></pre><p>根据提示,输入如下命令:</p><pre><code class="hljs bash">sudo launchctl load -w /System/Library/LaunchDaemons/com.apple.locate.plist</code></pre><p>或者使用如下命令创建也是可以的:</p><pre><code class="hljs bash">sudo /usr/libexec/locate.updatedb</code></pre><p><code>locate</code> 数据库创建需要一些时间,我大概是等了三分钟左右的样子就创建好了,当然,也可以根据参考链接里面的方法,使用 Mac 自带的<code>活动监视器</code>来观察创建的进度。</p><h3 id="使用方法"><a href="#使用方法" class="headerlink" title="使用方法"></a>使用方法</h3><p><code>locate</code> 跟其他命令行工具一样,也支持通配符和正则表达式:</p><pre><code class="hljs bash"><span class="hljs-comment"># 查找 mysql 配置文件</span>locate my.inf<span class="hljs-comment"># 查找所有以 jpg 结尾的图片文件</span>locate *.jpg<span class="hljs-comment"># 忽略扩展名大小写</span>locate -i *.jpg</code></pre><p>更多用法则可以使用 <code>man locate</code> 来查看。</p><h3 id="参考"><a href="#参考" class="headerlink" title="参考"></a>参考</h3><ul><li><a href="https://osxdaily.com/2011/11/02/enable-and-use-the-locate-command-in-the-mac-os-x-terminal/">Enable and Use the ‘locate’ Command in the Mac OS X Terminal</a></li></ul>]]></content>
<summary type="html"><p><code>locate</code> 命令是非常有用的,如果你正在寻找一个隐藏在系统文件夹深处的文件、文件类型、应用程序、扩展,尤其是在<code>Spotlight</code>不能处理的时候。。。</p></summary>
<category term="工具" scheme="https://floiges.github.io/categories/%E5%B7%A5%E5%85%B7/"/>
<category term="locate" scheme="https://floiges.github.io/tags/locate/"/>
</entry>
<entry>
<title>Mac 下安装 MySQL8</title>
<link href="https://floiges.github.io/2020/02/27/Mac-%E4%B8%8B%E5%AE%89%E8%A3%85-MySQL8/"/>
<id>https://floiges.github.io/2020/02/27/Mac-%E4%B8%8B%E5%AE%89%E8%A3%85-MySQL8/</id>
<published>2020-02-27T17:08:21.000Z</published>
<updated>2022-07-06T09:29:32.620Z</updated>
<content type="html"><![CDATA[<p>MySQL 断断续续的安装了 3、4 次了,每次都是各种 google。还是记录一下比较好,省的日后再去找了</p><a id="more"></a><h3 id="准备工作"><a href="#准备工作" class="headerlink" title="准备工作"></a>准备工作</h3><p>我是用 <code>homebrew</code> 的方式安装的。如果没有安装过,可直接用如下命令安装:</p><pre><code class="hljs bash">/usr/bin/ruby -e <span class="hljs-string">"<span class="hljs-subst">$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)</span>"</span></code></pre><p>安装之后,再更新一下,确保接下来安装的 MySQL 是 8 版本的</p><pre><code class="hljs bash">brew update</code></pre><h3 id="来吧,MySQL"><a href="#来吧,MySQL" class="headerlink" title="来吧,MySQL"></a>来吧,MySQL</h3><pre><code class="hljs bash">brew install mysql</code></pre><p>等待安装结束…结束之后,命令行会有如下提示:</p><pre><code class="hljs bash">We<span class="hljs-string">'ve installed your MySQL database without a root password. To secure it run:</span><span class="hljs-string"> mysql_secure_installation</span><span class="hljs-string"></span><span class="hljs-string">MySQL is configured to only allow connections from localhost by default</span><span class="hljs-string"></span><span class="hljs-string">To connect run:</span><span class="hljs-string"> mysql -uroot</span><span class="hljs-string"></span><span class="hljs-string">To have launchd start mysql now and restart at login:</span><span class="hljs-string"> brew services start mysql</span><span class="hljs-string">Or, if you don'</span>t want/need a background service you can just run: mysql.server start</code></pre><p>按照提示中的命令启动 MySQL 服务即可,相关命令如下:</p><pre><code class="hljs bash"><span class="hljs-comment"># 启动 mysql</span>brew services start mysql<span class="hljs-comment"># 重启 mysql</span>brew services restart mysql<span class="hljs-comment"># 关闭 mysql</span>brew services stop mysql<span class="hljs-comment"># 查看所有 Homebrew 管理的服务</span>brew services list</code></pre><p>如果忘记了服务启动命令也没关系,则可以通过如下命令找回:</p><pre><code class="hljs bash">brew info mysql</code></pre><h3 id="稍稍配置一下"><a href="#稍稍配置一下" class="headerlink" title="稍稍配置一下"></a>稍稍配置一下</h3><p>默认情况下,root 用户是没有密码的,</p><pre><code class="hljs bash">mysql -uroot</code></pre><p>输入此命令即可直接 MySQL 了</p><h4 id="设置-root-密码"><a href="#设置-root-密码" class="headerlink" title="设置 root 密码"></a>设置 root 密码</h4><p>MySQL 安装完成之后,会提示运行 <code>mysql_secure_installation</code> 命令来启用 <code>Valid Password</code> 组件,此组件包含一些密码策略的设置。<br>退出登录 MySQL,在命令行输入</p><pre><code class="hljs bash">mysql_secure_installation</code></pre><p>根据提示,一步步完成,记住我们自己设置的密码。</p><p>然后,登录 MySQL:</p><pre><code class="hljs bash">mysql -uroot -p</code></pre><p>回车之后,输入刚才命令行里设置的密码,登录成功之后,在 MySQL 下可输入如下命令可查看当前设置的 <code>Valid Password</code> 策略:</p><pre><code class="hljs sql"><span class="hljs-keyword">SHOW</span> <span class="hljs-keyword">VARIABLES</span> <span class="hljs-keyword">LIKE</span> <span class="hljs-string">'validate_password%'</span>;</code></pre><p>返回如下:</p><pre><code class="hljs sql">mysql> SHOW VARIABLES LIKE 'validate_password.%';+<span class="hljs-comment">--------------------------------------+-------+</span>| Variable_name | Value |+<span class="hljs-comment">--------------------------------------+-------+</span>| validate_password.check_user_name | ON || validate_password.dictionary_file | || validate_password.length | 8 || validate_password.mixed_case_count | 1 || validate_password.number_count | 1 || validate_password.policy | LOW || validate_password.special_char_count | 1 |+<span class="hljs-comment">--------------------------------------+-------+</span>7 rows in <span class="hljs-keyword">set</span> (<span class="hljs-number">0.01</span> sec)</code></pre><p>其中每个策略值得含义如下:</p><table><thead><tr><th align="center">名称</th><th align="center">含义</th></tr></thead><tbody><tr><td align="center">validate_password_check_user_name</td><td align="center">设为 ON 时,密码中不允许包含用户名</td></tr><tr><td align="center">validate_password_dictionary_file</td><td align="center">用于密码验证的字典文件路径,仅在密码验证级别为 STRONG 时生效</td></tr><tr><td align="center">validate_password_length</td><td align="center">限制密码长度不得少于 8 位</td></tr><tr><td align="center">validate_password_mixed_case_count</td><td align="center">密码中大小写字母的最少个数</td></tr><tr><td align="center">validate_password_number_count</td><td align="center">密码中数字的最少个数</td></tr><tr><td align="center">validate_password_policy</td><td align="center">设置密码验证级别</td></tr><tr><td align="center">validate_password_special_char_count</td><td align="center">密码中特殊符号的最少个数</td></tr></tbody></table><p>如果想要更改对应的策略值,例如,我当前设置的密码是 8 位的,但我只想改成 6 位,那么可以这样设置:</p><pre><code class="hljs sql">mysql> set global validate_password.length=6;</code></pre><p>这句的意思是把密码长度改成 6 位,再次查看密码策略相关值,可以看到密码长度已经设置成功了:</p><pre><code class="hljs sql">mysql> SHOW VARIABLES LIKE 'validate_password.%';+<span class="hljs-comment">--------------------------------------+-------+</span>| Variable_name | Value |+<span class="hljs-comment">--------------------------------------+-------+</span>| validate_password.check_user_name | ON || validate_password.dictionary_file | || validate_password.length | 6 || validate_password.mixed_case_count | 1 || validate_password.number_count | 1 || validate_password.policy | LOW || validate_password.special_char_count | 1 |+<span class="hljs-comment">--------------------------------------+-------+</span>7 rows in <span class="hljs-keyword">set</span> (<span class="hljs-number">0.01</span> sec)</code></pre><p>接下来退出 MySQL,再次运行 <code>mysql_secure_installation</code>, 重新设置密码就好了。</p><h3 id="参考链接"><a href="#参考链接" class="headerlink" title="参考链接"></a>参考链接</h3><ul><li><a href="https://dev.mysql.com/doc/refman/8.0/en/validate-password-options-variables.html">Password Validation Options and Variables</a></li></ul>]]></content>
<summary type="html"><p>MySQL 断断续续的安装了 3、4 次了,每次都是各种 google。还是记录一下比较好,省的日后再去找了</p></summary>
<category term="工具" scheme="https://floiges.github.io/categories/%E5%B7%A5%E5%85%B7/"/>
<category term="MySQL" scheme="https://floiges.github.io/tags/MySQL/"/>
</entry>
<entry>
<title>读书的故事</title>
<link href="https://floiges.github.io/2020/02/21/%E8%AF%BB%E4%B9%A6%E7%9A%84%E6%95%85%E4%BA%8B/"/>
<id>https://floiges.github.io/2020/02/21/%E8%AF%BB%E4%B9%A6%E7%9A%84%E6%95%85%E4%BA%8B/</id>
<published>2020-02-21T15:06:09.000Z</published>
<updated>2022-07-06T09:29:32.620Z</updated>
<content type="html"><![CDATA[<p>读书的故事有起点,但不会有终点…..</p><a id="more"></a><h4 id="缘起-▼"><a href="#缘起-▼" class="headerlink" title="缘起 ▼"></a>缘起 ▼</h4><p>在我上小学的时候,家里有半本百科全书,虽说是半本,但足有 300 多页。里面的内容包罗万象,古今中外名人名事均有。</p><p>书里的内容很吸引我,几乎成了我每天必看的读物。我第一次知道工业革命,知道文艺复兴,就是从这本书里了解的。平时跟同学们讲述一些书里的故事,竟颇受欢迎,这使我更愿意去读书了。</p><p>这本书陪伴了我小学六年的时光,六年里我看了一遍又一遍。后来搬家的时候,书找不到了,为此也难过了很长时间。不过,正是这段经历,打开了我徜徉书海的大门。</p><h4 id="第一本书-▼"><a href="#第一本书-▼" class="headerlink" title="第一本书 ▼"></a>第一本书 ▼</h4><p>初中的时候,课文里有一篇文章是讲述鲁滨逊漂流记的。我很喜欢这个故事,想要读完整个故事,那是我第一次决定去买书。就这样,鲁滨逊漂流记是我买的第一本书。</p><p>离学校 500 米左右的距离有一家小型的书店,叫三味书屋。第一次进店的时候,就仿佛置身于一片宁静之中,周围是一排排琳琅满目的书,散发着浓郁的独属于书的味道。整个人的心瞬间就静下来了,从此我就有了逛书店的爱好。</p><p>书屋虽小,书却不少。那个年代风靡的读者与青年文摘经常在同学们的手中互相传阅。</p><p>想起当年半夜翻墙出去,溜达到三味书屋的时候,居然还在营业中。书架显眼的位置上摆放了各种各样的恐怖故事,与外面漆黑的夜色搭配起来,非常应景。</p><p>再然后,恐怖故事成了另外一种更为风靡的课外读物,当然是偷偷读的,不过也会有失败的时候。三年初中下来,老师的准头已经有一摞没收上来的书了。</p><h4 id="技术书-▼"><a href="#技术书-▼" class="headerlink" title="技术书 ▼"></a>技术书 ▼</h4><p>看技术书纯粹是爱好,当然这个爱好后来变成了我的职业。因为喜欢,所以至今我仍保有对技术的热情,案头上也总是会有一两本技术类的书籍。</p><p>技术类的书籍的难啃的骨头,是需要理论与实践互相结合的产物。与此同时,英语是阅读国外技术类的书籍最好的帮手。庆幸的是,在整个求学生涯中,英语是我唯一有学习兴趣的科目。</p><p>所以说,兴趣很重要,尤其是在做自己喜欢的事情,成就感与幸福感都是加倍的。</p><h4 id="现在-▼"><a href="#现在-▼" class="headerlink" title="现在 ▼"></a>现在 ▼</h4><p>我有一个小书架,最上面一排是我的技术类书籍,第二、三排是我和老婆都感兴趣的书籍,散文和人物传记偏多,还包括一整套高晓松的鱼羊野史,这是目前我老婆最喜欢看的书。</p><p>最下面的一排摆满了小猪佩奇、小兔朱利奥等图画书,他们是我儿子的书。我儿子两岁半,已经开始喜欢读书了,每天都会把他的图画书一本一本的看过去,并且能咿咿呀呀的说出来,很是让我们欣喜。</p><p>我们为什么要读书。世上之事,没有万全和统一的答案。也许我读过的书堪堪能记住个大概,其余的都忘记了,但是我知道它们都已经融入到了我的骨肉,融入到了我的一言一行之中。</p><p>这即是我读书的故事,也可能是很多人读书的故事。读书的故事有起点,但不会有终点…..</p>]]></content>
<summary type="html"><p>读书的故事有起点,但不会有终点…..</p></summary>
<category term="杂谈" scheme="https://floiges.github.io/categories/%E6%9D%82%E8%B0%88/"/>
</entry>
<entry>
<title>Hello Hexo</title>
<link href="https://floiges.github.io/2020/02/18/hello-world/"/>
<id>https://floiges.github.io/2020/02/18/hello-world/</id>
<published>2020-02-18T17:22:06.000Z</published>
<updated>2022-07-06T09:29:32.620Z</updated>
<content type="html"><![CDATA[<p>Welcome to <a href="https://hexo.io/">Hexo</a>! This is your very first post. Check <a href="https://hexo.io/docs/">documentation</a> for more info. If you get any problems when using Hexo, you can find the answer in <a href="https://hexo.io/docs/troubleshooting.html">troubleshooting</a> or you can ask me on <a href="https://github.com/hexojs/hexo/issues">GitHub</a>.</p><a id="more"></a><h2 id="配置"><a href="#配置" class="headerlink" title="配置"></a>配置</h2><ul><li>需要的 npm 包见 package.json</li><li>主题选用 <a href="https://github.com/iissnan/hexo-theme-next">hexo-theme-next</a></li><li>配置文件分整体配置文件((_config.yml)及主题配置文件(themes/next/_config.yml)</li></ul><h2 id="Quick-Start"><a href="#Quick-Start" class="headerlink" title="Quick Start"></a>Quick Start</h2><h3 id="Create-a-new-post"><a href="#Create-a-new-post" class="headerlink" title="Create a new post"></a>Create a new post</h3><pre><code class="hljs bash">hexo new <span class="hljs-string">"My New Post"</span></code></pre><p>More info: <a href="https://hexo.io/docs/writing.html">Writing</a></p><h3 id="Run-server"><a href="#Run-server" class="headerlink" title="Run server"></a>Run server</h3><pre><code class="hljs bash">hexo server</code></pre><p>More info: <a href="https://hexo.io/docs/server.html">Server</a></p><h3 id="Generate-static-files"><a href="#Generate-static-files" class="headerlink" title="Generate static files"></a>Generate static files</h3><pre><code class="hljs bash">hexo generate</code></pre><p>More info: <a href="https://hexo.io/docs/generating.html">Generating</a></p><h3 id="Deploy-to-remote-sites"><a href="#Deploy-to-remote-sites" class="headerlink" title="Deploy to remote sites"></a>Deploy to remote sites</h3><pre><code class="hljs bash">hexo deploy</code></pre><p>More info: <a href="https://hexo.io/docs/deployment.html">Deployment</a></p>]]></content>
<summary type="html"><p>Welcome to <a href="https://hexo.io/">Hexo</a>! This is your very first post. Check <a href="https://hexo.io/docs/">documentation</a> for more info. If you get any problems when using Hexo, you can find the answer in <a href="https://hexo.io/docs/troubleshooting.html">troubleshooting</a> or you can ask me on <a href="https://github.com/hexojs/hexo/issues">GitHub</a>.</p></summary>
<category term="工具" scheme="https://floiges.github.io/categories/%E5%B7%A5%E5%85%B7/"/>
<category term="hexo" scheme="https://floiges.github.io/tags/hexo/"/>
</entry>
<entry>
<title>使用 github action 发布 hexo</title>
<link href="https://floiges.github.io/2020/02/18/%E4%BD%BF%E7%94%A8-github-action-%E5%8F%91%E5%B8%83-hexo/"/>
<id>https://floiges.github.io/2020/02/18/%E4%BD%BF%E7%94%A8-github-action-%E5%8F%91%E5%B8%83-hexo/</id>
<published>2020-02-18T17:22:06.000Z</published>
<updated>2022-07-06T09:29:32.620Z</updated>
<content type="html"><![CDATA[<p>最近想着搞一下 github action,体验一下自动化的威力。我可真是完完全全的零基础,搞了半天才搞定,记录一下吧</p><a id="more"></a><h3 id="准备工作"><a href="#准备工作" class="headerlink" title="准备工作"></a>准备工作</h3><p>准备两个仓库,如下:</p><table><thead><tr><th align="center">仓库</th><th align="center">说明</th></tr></thead><tbody><tr><td align="center">blog</td><td align="center">hexo 项目,存放博客源码的地方</td></tr><tr><td align="center">floiges.gitub.io</td><td align="center">hexo 编译后的静态文件,即博客</td></tr></tbody></table><h3 id="配置密钥"><a href="#配置密钥" class="headerlink" title="配置密钥"></a>配置密钥</h3><pre><code class="hljs bash">ssh-keygen -f github-hexo-deploy-key</code></pre><p>此命令会生成 <strong>github-hexo-deploy-key</strong> 私钥 和 <strong>github-hexo-deploy-key.pub</strong> 公钥。</p><h4 id="配置-blog-项目"><a href="#配置-blog-项目" class="headerlink" title="配置 blog 项目"></a>配置 blog 项目</h4><p>github 打开 blog 仓库 => settings => secrets => add new secrets</p><ul><li>Name 名字随便起,但是要记住,后面有用,例如:HEXO_DEPLOY_SECRETS</li><li>Value 输入 <code>github-hexo-deploy-key</code> 私钥的内容</li></ul><h4 id="配置-flogies-gitub-io-项目"><a href="#配置-flogies-gitub-io-项目" class="headerlink" title="配置 flogies.gitub.io 项目"></a>配置 flogies.gitub.io 项目</h4><p>github 打开 floiges.gitub.io 仓库 => settings => keys => add deploy key</p><ul><li>Title 名字随便起,但是要记住,例如: HEXO_DEPLOY_PUB</li><li>Key 输入 <code>github-hexo-deploy-key.pub</code> 公钥的内容</li></ul><h3 id="github-action"><a href="#github-action" class="headerlink" title="github action"></a>github action</h3><p>打开 blog 仓库 => Actions => Set up this workflow,内容如下,可做参考:</p><pre><code class="hljs yaml"><span class="hljs-attr">name:</span> <span class="hljs-string">HEXO</span> <span class="hljs-string">CI</span><span class="hljs-attr">on:</span> [<span class="hljs-string">push</span>] <span class="hljs-comment"># 有提交时触发</span><span class="hljs-attr">jobs:</span> <span class="hljs-attr">build:</span> <span class="hljs-attr">runs-on:</span> <span class="hljs-string">ubuntu-latest</span> <span class="hljs-attr">strategy:</span> <span class="hljs-attr">matrix:</span> <span class="hljs-attr">node-version:</span> [<span class="hljs-number">10.</span><span class="hljs-string">x</span>] <span class="hljs-attr">steps:</span> <span class="hljs-bullet">-</span> <span class="hljs-attr">uses:</span> <span class="hljs-string">actions/checkout@v1</span> <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Use</span> <span class="hljs-string">Node.js</span> <span class="hljs-string">${{</span> <span class="hljs-string">matrix.node-version</span> <span class="hljs-string">}}</span> <span class="hljs-attr">uses:</span> <span class="hljs-string">actions/setup-node@v1</span> <span class="hljs-attr">with:</span> <span class="hljs-attr">node-version:</span> <span class="hljs-string">${{</span> <span class="hljs-string">matrix.node-version</span> <span class="hljs-string">}}</span> <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Configuration</span> <span class="hljs-string">environment</span> <span class="hljs-attr">env:</span> <span class="hljs-attr">HEXO_DEPLOY_SECRETS:</span> <span class="hljs-string">${{secrets.HEXO_DEPLOY_SECRETS}}</span> <span class="hljs-comment"># blog 项目内新增的 secrets key</span> <span class="hljs-attr">run:</span> <span class="hljs-string">|</span> <span class="hljs-string">mkdir</span> <span class="hljs-string">-p</span> <span class="hljs-string">~/.ssh/</span> <span class="hljs-string">echo</span> <span class="hljs-string">"$HEXO_DEPLOY_SECRETS"</span> <span class="hljs-string">></span> <span class="hljs-string">~/.ssh/id_rsa</span> <span class="hljs-string">chmod</span> <span class="hljs-number">600</span> <span class="hljs-string">~/.ssh/id_rsa</span> <span class="hljs-string">ssh-keyscan</span> <span class="hljs-string">github.com</span> <span class="hljs-string">>></span> <span class="hljs-string">~/.ssh/known_hosts</span> <span class="hljs-string">git</span> <span class="hljs-string">config</span> <span class="hljs-string">--global</span> <span class="hljs-string">user.name</span> <span class="hljs-string">"floiges"</span> <span class="hljs-string">git</span> <span class="hljs-string">config</span> <span class="hljs-string">--global</span> <span class="hljs-string">user.email</span> <span class="hljs-string">"[email protected]"</span> <span class="hljs-string">git</span> <span class="hljs-string">clone</span> <span class="hljs-string">--branch</span> <span class="hljs-string">yadong_custom</span> <span class="hljs-string">--depth=10</span> <span class="hljs-string">[email protected]:floiges/hexo-theme-next.git</span> <span class="hljs-string">themes/next</span> <span class="hljs-string">git</span> <span class="hljs-string">checkout</span> <span class="hljs-string">-b</span> <span class="hljs-string">yadong_custom</span> <span class="hljs-string">git</span> <span class="hljs-string">clone</span> <span class="hljs-string">[email protected]:floiges/theme-next-three</span> <span class="hljs-string">--depth=1</span> <span class="hljs-string">themes/next/source/lib/three</span> <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Install</span> <span class="hljs-string">dependencies</span> <span class="hljs-attr">run:</span> <span class="hljs-string">|</span> <span class="hljs-string">npm</span> <span class="hljs-string">i</span> <span class="hljs-string">-g</span> <span class="hljs-string">hexo-cli</span> <span class="hljs-string">npm</span> <span class="hljs-string">i</span> <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Deploy</span> <span class="hljs-string">hexo</span> <span class="hljs-attr">run:</span> <span class="hljs-string">|</span> <span class="hljs-string">hexo</span> <span class="hljs-string">g</span> <span class="hljs-string">-d</span></code></pre><h3 id="End"><a href="#End" class="headerlink" title="End"></a>End</h3><p>现在 blog 项目里有提交时,就会触发自动构建了<del>~</del>。</p>]]></content>
<summary type="html"><p>最近想着搞一下 github action,体验一下自动化的威力。我可真是完完全全的零基础,搞了半天才搞定,记录一下吧</p></summary>
<category term="工具" scheme="https://floiges.github.io/categories/%E5%B7%A5%E5%85%B7/"/>
<category term="hexo" scheme="https://floiges.github.io/tags/hexo/"/>
</entry>
</feed>