prismjs 是一个语法高亮工具,当需要在日志中贴上一些代码块时它会对读者阅读这些代码非常友好。最近给博客引入了 prismjs,发现对于异步载入的内容无法高亮显示,花了点事间弄清楚了原因:由于 prismjs 只在 html 页面载入时运行,那些通过类似 infinite ajax scroll 异步载入的内容则超出了它的控制范围,这就导致了异步载入的代码块无法高亮显示。

对于以上问题,prismjs 提供了三个方法作为解决方案供用户选择:Prism.highlightAll()Prism.highlightElement()Prism.highlightAllUnder()。同时,infinite ajax scroll 也提供了一些有用的与页面载入有关的事件,可以利用其中的appendednexted事件来执行 prismjs 提供的方法,以便使异步载入的代码块高亮显示。
appended事件为例,它的代码将是类似这样的:

ias.on('appended', function () {
	Prism.highlightAll();	
});

区别

Prism.highlightElement()用于直接处理包含.language-***的元素,以便高亮显示其中的代码。

Prism.highlightAll()Prism.highlightAllUnder()两者的作用仅限于查找目标元素下所有包含.language-***样式的元素,区别是查找范围不同,前者查找整个 DOM 文档,后者需要指定一个具体的目标元素,在这两个方法内部,最终都会将找到的元素交给Prism.highlightElement()逐个处理。

参考:
Prism.highlightAll()
Prism.highlightElement()
Prism.highlightAllUnder()
infinite ajax scroll appended 事件
infinite ajax scroll nexted 事件

本篇不涉及表的各种连接关联关系,仅仅记录关联的几种写法。

创建表

学校表

CREATE TABLE school (
school_id integer NOT NULL,
school_code varchar(10),
school_name varchar(50)
);

班级表

CREATE TABLE class (
class_id integer NOT NULL,
class_grade varchar(10),
class_class varchar(10),
school_id integer NOT NULL
);

学生表

CREATE TABLE student (
student_id integer NOT NULL,
student_code varchar(10),
student_name varchar(10),
class_id integer NOT NULL
);

写数据

学校表

INSERT INTO school (school_id, school_code, school_name)
VALUES
(1, 'A001', '理想中学'),
(2, 'A002', '红旗试验中学'),
(3, 'A003', '外国语学校')

班级表

INSERT INTO class (class_id, class_grade, class_class, school_id)
VALUES
(1, '2', '1', 1),
(2, '2', '2', 1),
(3, '2', '1', 2),
(4, '1', '1', 2),
(5, '3', '1', 3)

学生表

INSERT INTO student ("student_id", "student_code", "student_name", "class_id")
VALUES
(1, '1', '石头', 1),
(2, '2', '王强', 1),
(3, '3', '张建国', 1),
(4, '1', '李国华', 2),
(5, '1', '赵铁', 3),
(6, '2', '高亮', 4)

第一种写法

SELECT
a.school_id,
a.school_code,
a.school_name,
b.class_grade,
b.class_class,
c.student_code,
c.student_name
FROM
school a,
class b,
student c
WHERE
a.school_id = b.school_id
AND b.class_id = c.class_id

以上写法所有的表都被放在from关键字后面,实现的是三个表的innner jion查询关系,关联条件写在where子句里,当表多的时候逻辑混杂,不便阅读和理解。
这种写法不应该被推荐的原因,还在于它所能实现的关联关系少之又少,但也不是一无是处。(有些数据库在此基础上通过*==*(+)(取决与其所处位置)符号能够实现left joinright join关系)

第二种写法

SELECT
a.school_id,
a.school_code,
a.school_name,
b.class_grade,
b.class_class,
c.student_code,
c.student_name
FROM school a
INNER JOIN class b ON a.school_id = b.school_id
INNER JOIN student c ON b.class_id = c.class_id

第三种写法

SELECT
a.school_id,
a.school_code,
a.school_name,
b.class_grade,
b.class_class,
c.student_code,
c.student_name
FROM
(
( school a INNER JOIN class b ON ( a.school_id = b.school_id ) )
INNER JOIN student c ON ( b.class_id = c.class_id )
)

去年给网站加了 暗黑模式,使用 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