全部文章

<h1>京东京造 K2</h1> <p>今年 618 美其名曰“送自己一个生日礼物”,本想买游戏机,无奈太贵,不舍得,所以折中了买了个机械键盘。之前有关注过 Keychron,无奈购买麻烦,只能舍弃。最终选择了京东京造 K2,和 Keychron 长好像,或许就是同一个。我也不关心它们两者的关系的,399 这个价,还可以接受就入手了。 先来看看它的样子。<img src="https://img14.360buyimg.com/n0/jfs/t1/117592/2/8272/295270/5ecdfe18E91d776dd/3218d27f408325d1.jpg" alt="" /> 拿到手,首先就是开蓝牙,连上笔记本。 “模式切换”切换拔到 BT 位置,然后按 Fn + 1,然后打开笔记本蓝牙,选择 Keychron K2 瞬间连上。之后就来愉快地敲打吧。</p> <p>感觉,太高了。得买个键盘托,不然肩很容易累。 跟同事一千的多键盘比起来还是有很大差距的,但足够我用了,毕竟可以装一下,它的颜值还是可以滴。 好了,玩几天之后再来更新。我去发朋友圈了。</p>
详情
<h1></h1> <p>从今天开始,开始整理以前做过的项目,把一些自己认为做得不错的项目一一总结。</p> <h2>悦阅 app</h2> <p><a href="https://www.pcdeng.com/yueyue-apk.html">https://www.pcdeng.com/yueyue-apk.html</a></p>
详情
<h1>Isotope</h1> <p>Isotope 是一个布局、排序、过滤带有很牛的动画效果的 js 库。最近有一个项目,老板要求用它的动画效果。一时半会用 angular 也没办法模拟出同样的效果,所以就研究了一下 isotope,并顺手写一个小例子来学一下怎样使用 isotope。</p> <p>以下是项目需要实现的效果:</p> <p><img src="//www.pcdeng.com/uploads/isotope-demo.gif" alt="Isotope" /></p> <p><a href="https://pcdeng.github.io/components/isotope/isotope-demo.html">demo 地址</a></p> <h2>参考</h2> <p><a href="https://isotope.metafizzy.co/">Isotope</a></p>
详情
<h2>需求</h2> <p>最近工作遇到要实现纯的背景色的长度要按百分比算。 如图:<img src="//www.pcdeng.com/uploads/task.svg" alt="task" /></p> <pre><code class="language-html"><!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Task item</title> <style> .task { width: 100%; height: 50px; background: linear-gradient(90deg, #e7791e 90%, transparent 0%); border: 1px solid #000; display: flex; justify-content: space-between; align-items: center; padding: 2px 4px; box-sizing: border-box; } .l1 { color: #fff; } </style> </head> <body> <div class="task"> <div> <h3 class="l1"> <span>4306</span> <span>VD</span> <span>Arr</span> </h3> </div> <div>actions</div> </div> </body> </html></code></pre> <p>关键的点是</p> <pre><code class="language-css">background: linear-gradient(90deg, #e7791e 90%, transparent 0%);</code></pre> <h2>参考</h2> <p><a href="https://developer.mozilla.org/zh-CN/docs/Web/CSS/linear-gradient">linear-gradient</a></p>
详情
<p>背景: Ionic 项目,要实现通知栏常驻,就是只要 app 活着,顶部通知栏就要显示“XXX 正在运行中”。 其中涉及 Android 中的两个主要概念。 <code>Service</code> 和 <code>Notification</code> 修改的文件涉及三个</p> <h2>一、应用的清单文件(<code>AndroidManifest.xml</code>)</h2> <p>要用 service 必须要在 <code>AndroidManifest.xml</code> 中声明,我就踩进这个坑了,半天才爬出来。总结:给点耐心多看官方文档。</p> <pre><code class="language-xml"><manifest ... > ... <application ... > <service android:name=".MyService" /> ... </application> </manifest></code></pre> <h2>二、MyService</h2> <p>不知道说啥好,直接看代码,引入的就不放上来了,用 IDE 解决,缺少什么就引入什么。特别注意的是 Android 8 之后增加 NotificationChannel,要注意兼容,详情请看<a href="https://developer.android.google.cn/guide/topics/ui/notifiers/notifications">通知概览</a></p> <pre><code>public class MyService extends Service { private NotificationManager notificationManager; private String notificationId = "stickyChannelId"; private String notificationName = "Sticky Channel"; @Nullable @Override public IBinder onBind(Intent intent) { return null; } @Override public void onCreate() { super.onCreate(); notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); // 创建NotificationChannel if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { NotificationChannel channel = new NotificationChannel(notificationId, notificationName, NotificationManager.IMPORTANCE_HIGH); notificationManager.createNotificationChannel(channel); } startForeground(1, getNotification()); } private Notification getNotification() { Notification.Builder builder = new Notification.Builder(this) .setSmallIcon(R.mipmap.ic_launcher) .setContentTitle("测试服务") .setOngoing(true) .setContentText("我正在运行"); // 设置Notification的ChannelID,否则不能正常显示 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { builder.setChannelId(notificationId); } Notification notification = builder.build(); return notification; } }</code></pre> <h2>三、使用</h2> <p>还是直接上代码吧,注释也做了说明了。 简单来说就是 <code>onCreate</code> 中调用 <code>startService</code> 或者 <code>startForegroundService</code> 把这个 <code>service</code> 进入前台服务(保活)。 在 <code>onDestroy</code> 回调停止服务</p> <pre><code class="language-java">public class MainActivity extends CordovaActivity { private Intent mServiceIntent; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // enable Cordova apps to be started in the background Bundle extras = getIntent().getExtras(); if (extras != null && extras.getBoolean("cdvStartInBackground", false)) { moveTaskToBack(true); } // Set by <content src="index.html" /> in config.xml loadUrl(launchUrl); if (mServiceIntent == null) { mServiceIntent = new Intent(MainActivity.this, MyService.class); } if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { // android8.0 以上通过 startForegroundService 启动 service startForegroundService(mServiceIntent); } else { startService(mServiceIntent); } } /** * The final call you receive before your activity is destroyed. */ @Override public void onDestroy() { if (mServiceIntent != null) { this.stopService(mServiceIntent); } super.onDestroy(); } }</code></pre> <h2>注意:</h2> <pre><code>defaultBuildToolsVersion="28.0.3" defaultMinSdkVersion=19 defaultTargetSdkVersion=23 // 如果设为 26,常驻通知栏就不显示了。原因不明。 defaultCompileSdkVersion=28</code></pre> <h2>参考:</h2> <ul> <li><a href="https://blog.csdn.net/huaheshangxo/article/details/82856388">Android 8.0中Service和Notification</a></li> <li><a href="https://developer.android.google.cn/guide/components/services">Service服务概览</a></li> <li><a href="https://blog.csdn.net/xy_nyle/article/details/19853591">Android 弹无虚发之第四弹</a></li> </ul>
详情
<h2>一、下载你需要的 SVG 图标</h2> <p>去<a href="https://www.iconfont.cn/search">Iconfont</a>搜索你想要的图标。例如,我搜索 <code>download</code> 并下载了 <code>download.svg</code></p> <h2>二、放到 /src/assets/abc/下</h2> <p>把下载好的 <code>download.svg</code> 放到 <code>/src/assets/abc</code> 注意 <code>abc</code> 就是一个命名空间。</p> <blockquote> <p>动态引入,只需要保证 SVG 资源文件放到了相应的目录,即 assets/${namespace} 即可。例如你在 zoo 命名空间下有一个 panda 图标,你需要做的就是将 panda.svg 放到 assets/zoo 目录底下。</p> </blockquote> <h2>三、使用图标</h2> <pre><code class="language-html"><i nz-icon nzType="abc:download"></i> <!-- abc是命名空间,download 对应 download.svg --></code></pre> <h2>四、参考</h2> <p><a href="https://ng.ant.design/components/icon/zh">图标 Icon</a></p>
详情
<h1>Git 常用命令汇总</h1> <h2>一、Git 工作原理图</h2> <p><img src="//www.pcdeng.com/uploads/git-flow.png" alt="Git工作原理图" /></p> <h2>二、常用命令</h2> <ul> <li> <p>查看远程分支</p> <pre><code class="language-sh">git branch -a</code></pre> </li> <li> <p>查看本地分支</p> <pre><code class="language-sh">git branch</code></pre> </li> <li> <p>切换到<code>test</code>分支</p> <pre><code class="language-sh">git checkout test</code></pre> </li> <li> <p>创建<code>test</code>分支</p> <pre><code>git branch test</code></pre> </li> <li> <p>删除本地<code>test</code>分支</p> <pre><code class="language-sh">git branch -d test</code></pre> </li> <li> <p>推送<code>test</code>分支到远程服务器</p> <pre><code>git push origin test</code></pre> </li> <li> <p>添加<code>db</code>文件夹</p> <pre><code class="language-sh">git add db</code></pre> </li> <li> <p>提交信息</p> <pre><code class="language-sh">git commit -m '添加db文件夹'</code></pre> </li> <li> <p>将提交推送到远程<code>test</code>分支</p> <pre><code class="language-sh">git push --set-upstream origin test</code></pre> </li> <li> <p>查看当前的origin</p> <pre><code class="language-sh">git remote -v</code></pre> </li> <li> <p>删除远程分支</p> <pre><code class="language-sh">git push origin --delete <branchName> git push origin :<branchName></code></pre> </li> <li> <p>查看状态</p> <pre><code class="language-sh">git remote show origin</code></pre> </li> <li> <p>删除不存在对应远程分支的本地分支</p> <pre><code class="language-sh">git remote prune origin # stale不新鲜的;prune修剪,削减 git fetch -p</code></pre> </li> <li> <p>重命名本地分支(devel -> develop)</p> <pre><code class="language-sh">git branch -m devel develop</code></pre> </li> <li> <p>推送本地分支</p> <pre><code class="language-sh">git push origin develop</code></pre> </li> </ul>
详情
<h2>一、关于Google AdSense</h2> <p>上个星期我为自己的博客开通了Google Adsense。一方面是想学学Google AdSense;另一方面看看能有多少收入。 一共为了两个网站开通Google Adsense,一个已经顺利通过了;一个没有审核通过。没有通过的原因是<code>We’ve found some policy violations on your site which means your site isn’t ready to show ads yet. Make sure your site follows the AdSense Program Policies.</code> 现在还没有时间去修改网站。</p> <h2>二、注册 Google AdSense</h2> <p>注册 Google AdSense 是很容易的。前提是需一个你自己的网站和一个 Google 邮箱。按照注册页面提示填写所需信息即可。注册地址:<a href="https://www.google.com/adsense/signup/new/lead">https://www.google.com/adsense/signup/new/lead</a> 注册帮助文档:<a href="https://support.google.com/adsense/answer/7402253">https://support.google.com/adsense/answer/7402253</a></p> <h2>三、连接网站和 Google AdSense</h2> <ol> <li>上传 <code>ads.txt</code> 到网站根目录。帮助文档 <a href="https://support.google.com/adsense/answer/7532444?hl=zh-Hans">https://support.google.com/adsense/answer/7532444?hl=zh-Hans</a></li> <li>创建广告。 AdSense 提供了两种方式的广告。一种Auto ads(自动广告),一般是要复制一段JavaScript代码放置页面的 head 标签之间,AdSense 会分析你页面,在页面合适的位置放置广告。另一种是Ad unit(广告单元),你可以创建多个不同的广告单元,然后应用到网站的不同页面,推荐这种方式,这种方式更容易适应你的网站风格(不会破坏网页布局)。</li> </ol> <p>一开始,我用的是Auto ads,发现它撑破了页面的布局,极度不好看。Ad unit 有三种类型,分别为Square,Horizontal 和 Vertical。要按照网站布局方式选择。我选择了Horizontal的,因为它适合我的网页布局。 <img src="//www.pcdeng.com/uploads/ad-unit1.png" alt="Adunit1" /></p> <p>创建好 Ad unit 后就可以复制代码到你想要放置的地方。 <img src="//www.pcdeng.com/uploads/adunit2.png" alt="Adunit2" /></p> <p>例如我的</p> <pre><code class="language-javascript"><script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js"></script> <!-- horizontal --> <ins class="adsbygoogle" style="display:block" data-ad-client="ca-pub-2862993259615109" data-ad-slot="6046279191" data-ad-format="auto" data-full-width-responsive="true"></ins> <script> (adsbygoogle = window.adsbygoogle || []).push({}); </script></code></pre> <h2>四、运行效果</h2> <p>经过两周的运行后,收益如下: <img src="//www.pcdeng.com/uploads/earnings.png" alt="收益" /> 注意:收益要满100刀才可以提现。</p> <h2>五、总结</h2> <p>通过开通Google AdSense 账户,我对它有了初步的认识。对其它网站提供的广告也没有那么反感了,希望看到这篇文章的你也不要反感这个网站的广告。</p>
详情
<h1>Laravel 5.2 实现浏览文章统计次数</h1> <h2>一、安装 weboAp/Visitor</h2> <p>先按官方提供的<a href="https://github.com/weboAp/Visitor">文档</a>安装好,并测试。 测试方法:</p> <pre><code class="language-php">// app/Http/Controllers/ArticleController.php use Weboap\Visitor\Facades\VisitorFacade; // 使用切面 class ArticleController extends Controller { /** * 文章详情页 * * @return \Illuminate\Http\Response */ public function show($id) { VisitorFacade::log(); } }</code></pre> <p>浏览器访问:<code>http://localhost/article/1</code> 看数据库表 <code>visitor_registry</code> 是否插入了一条数据。有则表明安装 <code>weboAp/Visitor</code> 成功,如果没有,请按官方文档再跑一遍。</p> <h2>二、定制</h2> <h3>改表名</h3> <p>官方预定的表名是 <code>visitor_registry</code>,我要改为的是 <code>article_clicks</code>.</p> <ol> <li> <p>改 <code>migration</code> 文件内容如下:</p> <pre><code class="language-php">// database/migrations/2014_02_09_225721_create_article_clicks.php <?php use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; class CreateArticleClicks extends Migration { /** * Run the migrations. * * @return void */ public function up() { Schema::create('article_clicks', function (Blueprint $table) { $table->increments('id'); $table->string('ip', 32); $table->string('country', 4)->nullable(); $table->string('city', 20)->nullable(); // 新增 $table->integer('article_id'); // 新增 $table->integer('clicks')->unsigned()->default(0); $table->timestamps(); }); } /** * Reverse the migrations. * * @return void */ public function down() { Schema::drop('article_clicks'); } }</code></pre> <p>改完之后,手动去数据库删除 <code>visitor_registry</code> 表。重新执行 <code>php artisan migrate</code>。</p> </li> <li> <p>config/visitor.php</p> <pre><code class="language-php"><?php return [ 'table' => 'article_clicks', // 改这里 ]; </code></pre> </li> </ol> <h3>覆盖 <code>Visitor</code> 类的 <code>log</code> 方法,使其支持传入文章 id。改动后的使用方法为:<code>VisitorFacade::log($article->id)</code>;</h3> <ol> <li> <p>新建自定义 <code>Visitor</code> 类且继承 <code>Visitor</code></p> <pre><code class="language-php"><?php namespace App\Visitor; use Weboap\Visitor\Visitor as WeVisitor; use Carbon\Carbon as c; use App\ArticleClick; class Visitor extends WeVisitor { public function log($articleId = NULL) { $ip = $this->ip->get(); if (!$this->ip->isValid($ip)) { return; } if ($this->has($ip) && $this->hasArticle($articleId, $ip)) { $visitor = ArticleClick::where('ip', $ip) ->where('article_id', $articleId) ->whereDate('updated_at', '!=', c::today()) ->first(); if ($visitor) { $visitor->update(['clicks'=>$visitor->clicks + 1]); } return; } else { $geo = $this->geo->locate($ip); $country = array_key_exists('country_code', $geo) ? $geo['country_code'] : null; $city = array_key_exists('city', $geo) ? $geo['city'] : null; // ip doesnt exist in db $data = [ 'ip' => $ip, 'country' => $country, 'city' => $city, 'clicks' => 1, 'article_id' => $articleId, 'updated_at' => c::now(), 'created_at' => c::now(), ]; $this->storage->create($data); } // Clear the database cache $this->cache->destroy('weboap.visitor'); } public function hasArticle($id, $ip) { return count(ArticleClick::where('article_id', $id)->where('ip', $ip)->get()) > 0; } }</code></pre> </li> <li> <p>新建 <code>VisitorServiceProvider</code> 并继承 <code>VisitorServiceProvider</code></p> <pre><code class="language-php">// app/Providers/VisitorServiceProvider.php <?php namespace App\Providers; use Illuminate\Support\ServiceProvider; use Weboap\Visitor\VisitorServiceProvider as VS; use App\Visitor\Visitor; class VisitorServiceProvider extends VS { public function register() { parent::register(); } public function RegisterVisitor() { $this->app->singleton('visitor', function ($app) { return new Visitor( // 这是替换后的类 $app['Weboap\Visitor\Storage\VisitorInterface'], $app['Weboap\Visitor\Services\Geo\GeoInterface'], $app['ip'], $app['Weboap\Visitor\Services\Cache\CacheInterface'] ); }); $this->app->bind('App\Visitor\Visitor', function ($app) { // 关键在这里,狸猫换太子。 return $app['visitor']; }); } }</code></pre> </li> <li> <p>注册两个自定义的类。</p> <pre><code class="language-php">// composer.json "autoload": { "classmap": [ "database", "app/Visitor/Visitor.php" // 增加这行 ], "psr-4": { "App\\": "app/" } },</code></pre> <pre><code class="language-php"> // config/app.php providers: [ ... App\Providers\VisitorServiceProvider::class // 增加这行 ]</code></pre> <h3>最终结果</h3> <p><img src="//www.pcdeng.com/uploads/article-clicks.png" alt="统计结果" /></p> </li> </ol> <h2>参考</h2> <p><a href="https://learnku.com/articles/7637/statistics-of-the-number-of-times-in-laravel">Laravel 实现文章浏览量次数统计</a> <a href="https://stackoverflow.com/questions/47925618/laravel-5-5-override-vendor-class">Laravel 重写第三方类的方法</a></p>
详情
<h1>React Chat</h1> <h2>一共四个页面:</h2> <ol> <li>home 主页,也就是默认页。</li> <li>login 登录页</li> <li>register 注册页</li> <li>chat 聊天页</li> </ol> <h2>主要的功能有</h2> <ol> <li>注册</li> <li>登录</li> <li>聊天(可以换头像)</li> </ol> <h2>其中聊天的流程</h2> <ol> <li>登录成后,把 <code>accessToken</code> 和当前登录的用户信息()存在 <code>localstorage</code></li> <li>初始化 <code>websocket</code> 把 <code>accessToken</code> 通过查询参数(<code>queryString</code>) 传递到 <code>API</code>,<code>API</code> 根据 <code>accessToken</code> 认证用户。</li> <li>认证成功后,<code>websocket</code> 已经连接成功,然后服务器端通过 <code>websocket</code> 发送了三个事件到客户端。 <ol> <li><code>userin</code> 用户登入通知,事件的内容(数据)是登入的用户 <code>user</code>,这是广播事件(所有客户端都收到)</li> <li><code>onlineusers</code> 当前在线的所有用户,这是广播事件。</li> <li><code>groups</code> 当前用户所加入的群聊。单播(这个词或许用的不够准确。只有该用户自己收到)。</li> </ol></li> <li>当用户在输入框打字时,广播 <code>typing</code> 事件,事件内容(数据)为当前打字的用户,客户端收到该事件后,<code>显示 xxx 正在输入中...</code>,然后 <code>1.5s</code> 后隐藏该提示。</li> <li>输入完毕,按下回车键,发送 <code>message</code> 事件到服务端,服务端收到后,把这信息广播到所有客户端,客户端收到后把该信息压入 <code>messages</code> 数组,然后滚动条(如果有)滚动到底部。</li> </ol> <p>千言万语还不如一张图,还是直接上图吧。 <img src="//www.pcdeng.com/uploads/chat.png" alt="React Chat" /></p> <h2>主要依赖有</h2> <ul> <li><code>react</code> 前端框架,包括路由处理。</li> <li><code>axios</code> http 请求。</li> <li><code>date-fns</code> 日期、时间处理。</li> <li><code>lodash-es</code> 工具类。</li> <li><code>socket.io-client</code> websocket 客户端。</li> </ul> <h2>还没解决的问题有:</h2> <ol> <li>用户随意加入群聊(或者申请加入某个群聊)。</li> <li>用户创建群聊。</li> <li>用户切换群聊。</li> <li>单聊,怎样设计表结构?和群聊一样,群里只有两个人,如果采用这设计,群聊的名称和最后一条信息就要动态算了,有点麻烦?</li> <li>接收每个群新的信息包括最后一条和还有多少条未读。</li> <li>换头像后,要重新登录才能生效。</li> </ol> <p>有兴趣的朋友可以看 </p> <ul> <li><a href="https://github.com/paytondeng/chat">github</a> </li> <li><a href="http://chat.pcdeng.com">Live demo</a></li> </ul>
详情
<h1>MySQL</h1> <h2>历史与现状</h2> <p><code>MySQL</code> 是一个关系型数据库管理系统,由瑞典 <code>MySQL AB</code> 公司开发,2008 年被 <code>SUN</code> 公司收购,2009年 <code>SUN</code> 公司被 <code>Oracle</code> 收购,现它属于 <code>Oracle</code> 旗下产品。</p> <h2>个人的一些习惯</h2> <ul> <li>数据命名。数据库一般用项目的名字,如 <code>mini_clubs</code>,用 <code>_</code> 连接单词。</li> <li>表名。一般加前缀且单词用复数,如 <code>mc_users</code>,其中 <code>mc</code> 是由 <code>mini clubs</code> 的首字母组成。</li> <li>字符编码与字符集。字符编码一般使用 <code>utf8mb4</code>,字符集一般使用<code>utf8mb4_general_ci</code>。<code>utf8mb4</code> 是 <code>MySQL 5.5.3</code> 增加的,<code>mb4</code> 就是 <code>most bytes 4</code> 的意思,专门用来兼容四字节的<code>unicode</code></li> </ul> <h2>实例</h2> <p>以下实例都是我在做项目<a href="https://book.quest.ink">悦阅</a> 和 小咔吧微信小程序时总结下来的。</p> <ol> <li> <p>更新同表内的字段为另一字段 语法 <code>UPDATE 表名 SET 字段名=值</code></p> <pre><code class="language-sql">UPDATE book_borrowers SET created_at = (expire_at - 30 * 24 * 60 * 60); UPDATE books SET remark = REPLACE(remark, 'A', 'B'); UPDATE mc_users SET email = lower(email);</code></pre> </li> <li> <p>查询活动成员</p> <pre><code class="language-sql">SELECT u.NAME, u.email, DATE_FORMAT( FROM_UNIXTIME( m.joined_at ), '%Y-%m-%d %H:%i:%s' ) AS joinedAt FROM mc_activity_members AS m LEFT JOIN mc_users AS u ON u.id = m.user_id WHERE activity_id = 26 ORDER BY m.joined_at DESC;</code></pre> </li> <li> <p>导出数据库</p> <pre><code class="language-sql">mysqldump -uroot -p --databases clubs > clubs.backup20190825.sql</code></pre> </li> <li> <p>创建数据库</p> <pre><code class="language-sql">CREATE DATABASE IF NOT EXISTS clubs_backup DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_unicode_ci;</code></pre> </li> <li> <p>借阅书 7 天后将过期</p> <pre><code class="language-sql">SELECT users.name AS '用户', books.title AS '图书', FROM_UNIXTIME( book_borrowers.created_at ) AS '借书日', FROM_UNIXTIME( book_borrowers.expire_at ) AS '最后还书日', TIMESTAMPDIFF( DAY, FROM_UNIXTIME( UNIX_TIMESTAMP( NOW())), FROM_UNIXTIME( book_borrowers.expire_at ) ) AS '还有几天到期', books.state AS '图书状态' FROM book_borrowers, books, users WHERE books.id = book_borrowers.book_id AND book_borrowers.user_id = users.id AND book_borrowers.deleted_at IS NULL AND book_borrowers.send_email_at IS NULL /*AND books.state = 2*/ AND book_borrowers.expire_at <= ( UNIX_TIMESTAMP( NOW()) + 7 * 24 * 60 * 60 ) ORDER BY expire_at ASC;</code></pre> </li> </ol> <p><img src="//www.pcdeng.com/uploads/MySQL.png" alt="MySQL基础" /></p> <h2>参考</h2> <p><a href="https://blog.csdn.net/zyj66666/article/details/74003041">MySQL的发展历程</a></p>
详情
<h2>for in 和 for of</h2> <h3>定义</h3> <pre><code>for (variable of iterable) { // statements }</code></pre> <p>其中 <code>iterable</code> 可以是 <code>Array</code>,<code>Map</code>,<code>Set</code>,<code>String</code>,<code>TypedArray</code>,<code>arguments</code> 包括显式实现可迭代协议的对象等等</p> <h3>for...of 和 for...in 的区别</h3> <pre><code class="language-javascript">Object.prototype.objCustom = function() {}; Array.prototype.arrCustom = function() {}; let iterable = [3, 5, 7]; iterable.foo = 'hello'; for (let i in iterable) { console.log(i); // logs 0, 1, 2, "foo", "arrCustom", "objCustom" } for (let i in iterable) { if (iterable.hasOwnProperty(i)) { console.log(i); // logs 0, 1, 2, "foo" } } for (let i of iterable) { console.log(i); // logs 3, 5, 7 }</code></pre> <h2>结论:</h2> <ol> <li><code>for key in obj</code> 会遍历可枚举属性,包括继承下来的属性;</li> <li><code>for item of iterable</code> 会遍历 <code>iterable</code> 可迭代的值,这些是数组元素,而不是任何对象的属性。</li> </ol> <p>参考 <a href="https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Statements/for...of">for...of</a></p>
详情