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

  1. dark 模式下在网络不畅的情况下会存在刷新出现短暂闪烁的问题(页面加载时先渲染 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用于指定这个块下面设置的是适用于 dark 模式的规则,定义了一个变量--background-main设定 dark 模式下的背景颜色。

@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

更新下拉菜单

更新前,下拉菜单依赖 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,放到一个容易找的位置,比如C盘根目录,这时它的路径是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多本儿童故事书。正如简介所述,她的这些故事总能深深打动孩子们的心,这次抓鱼我的孩子对《逃家小兔》的引用就是印象深刻的表现。