去年给网站加了 暗黑模式,使用 js + css 的方式实现,不过当时有两个地方一直没搞清楚,导致存在以下两个问题:

  1. 暗黑模式下在网络不畅的情况下会存在刷新出现短暂闪烁的问题(页面加载时先渲染 css,再执行 js);
  2. 系统切换到另一种模式时界面不能自动切换的(无法触发事件)。

如何设置

这次改用 css 实现,只需要两步,连 js 都用不到,在着手处理前有以下几个关键要素需要了解一下。

  1. @media 关键字

    用于设置 css 规则。

  2. prefers-color-scheme 特性

    用于检测用户是否有将系统的主题色设置为亮色或者暗色。

  3. :root

    它是一个伪类,表示元素,与 html 选择器相同,但优先级更高,这里我们要用到它的高优先级特性。

  4. css 的 var()函数

    用于动态设置 css 属性值。

第一步

先在样式文件 style.css 里先设置 dark 模式的 css 规则:prefers-color-scheme:dark 这里设置的是适用于暗黑模式的规则,定义了一个变量--background-main 设定暗黑模式下的背景颜色。

@media (prefers-color-scheme:dark) {
body{background: var(--background-main: #181819)}
}

第二步

在第一步的代码下追加下面这段样式:
:root{}用于指定在正常模式下的背景样式,并给变量--background-main 设置正常模式下的背景颜色;给 body{}定义属性 background-color,属性值就是刚刚设置的变量--background-main

:root {--background-main: #fff}
body {background-color: var(--background-main)}

这样就完成了,就这么简单。这种方式的优势是设置非常简单,不涉及 js 编程,局限性也很明显,只能实现跟随系统的设置,无法实现手动切换,对于一般的博客来说这已经足够了。

参考:prefers-color-scheme

周末给网站做了若干调整,脱离了 jQuery,拥抱原生 JavaScript,主要调整如下:

更新到 infinite ajax scroll 3.0

自2015年以来,一直使用 infinite ajax scroll实现网站的滚动加载,去年 infinite ajax scroll 更新到了 3.0,与 2.x 版本最直接的区别是 3.0 舍弃了对 jQuery 的依赖,改用现代 JavaScript 技术构建。

以下是我使用的2.x版本的代码,通过自定义配置实现了前3页自动加载,后续页面手动加载的需求
infinite ajax scroll

以下是切换到 3.0 后的代码,同样实现了前3页自动加载,后续页面手动加载的加载方式。去年就想着更新到 3.0了,囿于自动加载后转手动加载一直没搞定,这次终于搞定了。

var optionElement = document.querySelector('.content');
var iasHtml = '<div class="ias-spinner more"><span class="animation"></span></div><div class="ias-trigger more"><a>加载更多</a></div>';
optionElement.insertAdjacentHTML('beforeend', iasHtml);

var ias = new InfiniteAjaxScroll('.content', {
    item: '.item',
    next: '.next a',
    pagination: '.next',
    spinner: {
        element: '.ias-spinner',
        delay: 600,
        show: function (element) {
            element.style.display = 'block';
        },
        hide: function (element) {
            element.style.display = 'none';
        }
    },
    trigger: {
        element: '.ias-trigger',
        // 控制什么时候显示加载更多按钮,目前的配置是自动加载前3页
        when: function (pageIndex) {
            return pageIndex > 2;
        },
        show: function (element) {
            element.style.display = 'block';
        },
        hide: function (element) {
            element.style.display = 'none';
        }
    }
});

ias.on('last', function () {
    // 删除 content 元素下的含有 more 元素的节点, 并插入新节点(直接设置 className, 点击标签会报错)
    while (document.querySelector('.content .more')) {
        var deleteNode = document.querySelector('.content .more');
        deleteNode.parentNode.removeChild(deleteNode);
    }
    iasHtml = '<div class="ias-noneleft more">已到结尾</div>';
    optionElement.insertAdjacentHTML('beforeend', iasHtml);
});

在 infinite ajax scroll 中集成 Prism

本次更新还给网站加了代码高亮插件 Prism 来实现代码高亮,并将之整合到 infinite ajax scroll 中:在 infinite ajax scroll 中集成 Prism

更新下拉菜单

更新前,下拉菜单依赖 jQuery 的 toggle 方法,通过切换 CSS 的 display 属性值(block/none)来实现。本次对此处的改造发现了以往一直存在的 bug:iOS 下浏览器文本框在发生点击(focus 事件)弹出虚拟键盘时,若页面不在初始位置(就是向上滑动了),系统会自动产生向上弹一下(scroll 事件)的动画效果,这跟我这里预设的页面向上滑动自动隐藏菜单的功能相冲突,导致刚一点搜索框菜单就被隐藏了。记得之前有朋友提醒给我,问题是我一直没法重现这个问题,这次无意间发现了,他很细心!
解决办法是监听到搜索框元素的点击事件(focus)时阻止执行自动隐藏菜单的操作。

更新 like 功能

更新前,like 依赖 jQuery 的 ajax,更新后使用了 XMLHttpRequest(XHR)对象以替代 ajax。

下面是一个简单的使用 XMLHttpRequest 发送异步请求的 JavaScript 示例:

var request = new XMLHttpRequest();
var requestUrl = '...';
var data = '...';
request.open('POST', requestUrl, true);
request.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded; charset=UTF-8');
// 发送请求
request.send(data);
// onload
request.onload = function () {
    if (this.status === 200) {
        // 获取到返回的数据
        e = JSON.parse(this.responseText);
        console.log(e);
    } else {
    }
};

兼容 Safari 9

更新第一版后发现 js 在家里的老 iPad (Safari 9)上不能工作,排查发现问题由以下几个问题造成:

  • Safari 9 不支持函数形参默认值;
  • Safari 9 支持严格模式,但 Safari 9 在严格模式下对setTimeout()作用域的处理好像跟更高版本有不一致行为(不确定,仅猜测),由于没有办法调试,只是简单地把setTimeout调用的函数放到外层来避免问题。

如何从 jQuery 迁移到 JavaScript

关于从 jQuery 迁移到 JavaScript 的若干建议或指南,除了事无巨细的 MDN JavaScript 在线文档,还有 You might not need jQuery 这个项目,它对 jQuery 转 JavaScript 的介绍详细到指明了各种方案的浏览器兼容性,感谢他们:

  1. You might not need jQuery
  2. MDN JavaScript 在线文档
  3. Essential Cheat Sheet: Convert jQuery to JavaScript

以下是重置 Windows 环境下 MySQL root 密码的方法:

能使用 Navicat 等工具链接到当前数据库,且有权限

直接执行以下命令,更新密码并刷新权限,PASSWORD 后面的字符串是新密码。

UPDATE mysql.user 
    SET authentication_string = PASSWORD('root123'), password_expired = 'N' 
    WHERE User = 'root' AND Host = 'localhost'; 
FLUSH PRIVILEGES;

无法链接数据库,或能链数据库但没权限的

  1. 增加重置密码的配置文件:
    新建记事本,放入以下命令

    ALTER USER 'root'@'localhost' IDENTIFIED BY 'root123';
    

    随便保存一个文件名,比如 reset_pwd.txt,放到一个容易找的位置,比如 D 盘根目录,此时它的路径是 D:\\reset_pwd.txt
    IDENTIFIED BY 后面的字符串将被用作新密码

  2. 进入服务管理器,停用 MySQL 服务:
    Win + R,输入 services.msc 并回车,打开服务窗口,找到 MySQL 服务,右击,【属性】,点【停止 (T)】
  3. 配置启动参数,启动服务重置密码:
    点完上一步的【停止 (T)】,下面的【启动参数 (M)】处于可编辑状态,输入启动参数--init-file=D:\\reset_pwd.txt,点【启动 (S)】,服务启动后密码就重置成功了。
  4. 请使用新密码,记得删除本地的 reset_pwd.txt 文件。

来源:https://dev.mysql.com/doc/mysql-windows-excerpt/5.7/en/resetting-permissions-windows.html

周一中午下楼吃饭,电梯里另外两个人的对话吸引了我,年长者说“我本身是审计员,审计了100多个实验室,我发现国内的这些实验室的成长很有限,原因是他们很难有机会见识那些更高水平的实验室,不知道高水平的实验室是什么样子的。”

当时我就意识到对普通个人来说何尝不是如此,长期拘泥在固定的环境,特别是做着重复性较高的工作,人的思维就容易僵化;若见不到更高水平的工作,则难以找到追赶目标和方向。

当天我就想着要总结一下,今天中午前同事在群里分享现同事的工作成果,感叹一起工作过的上家公司工作太粗糙了。我说之所以有这种感觉应该是因为之前没机会遇到行业专家,没接触行业规范,现在遇到更高水平的人意识到差距,很自然,无意中找到了一个改进的突破口,是好事。

其实这类道理古人给出了很多总结,特别有感“读万卷书,行万里路”一句。我想读万卷书是让自己有资格去从事某项工作,获得准入资格;行万里路是要在实践中发现问题,学习别人的长处,积累经验,获得进一步的成长。

上周天傍晚带孩子去大学城抓鱼,那里的水塘不深很适合孩子们抓鱼,正是抓鱼的孩子和家长太多了,那里的鱼被抓的警惕性很高,见人就跑,根本抓不到。

好在我有一些生活常识:等到天黑下来,开灯就好抓了。那天运气不错,抓到一条小黑鱼。黑鱼是肉食动物,体格健壮,劲儿很大,落到网子里就拼命挣扎,放到塑料小桶里也能蹦出来,孩子一边抓它回桶一边责怪说就算你是逃家小兔…

《逃家小兔》是几年前给孩子买的绘本故事,今天下午在豆瓣读书上看到《逃家小兔》作者是一位出生于1910年代的美国女性,她一生没结过婚,也没有自己的孩子,却对孩子的心理、情绪有着深刻的认识。1950年代初作者于欧洲旅行途中不幸去世,她的一生创作了10多本儿童故事书。正如简介所述,她的这些故事总能深深打动孩子们的心,这次抓鱼我的孩子对《逃家小兔》的引用就是印象深刻的表现。