无限·领域 - JavaScript https://ucw.moe/tag/JavaScript zh-CN Sun, 07 Jun 2020 18:51:00 +0800 Sun, 07 Jun 2020 18:51:00 +0800 twemoji:优化全站全平台 emoji 表情展现 https://ucw.moe/archives/import-twemoji.html https://ucw.moe/archives/import-twemoji.html Sun, 07 Jun 2020 18:51:00 +0800 无限UCW 封面:アスナ(Pixiv ID:29328488)


介绍

emoji 即表情符号,来自日语词汇“絵文字”(假名为“えもじ”,读音即 emoji),最初由栗田穰崇创作,目前已被纳入 Unicode 编码并得到广泛支持。⭐

Emojipedia 收录了目前所有的 emoji。🎈

尽管如此,emoji 在部分老设备、旧系统的支持性并不好,甚至可能显示为类似“□”的无法显示字符。这当然是不好的。为了优化展现,目前常用的做法是渲染时用图片替换 emoji 字符。相关的项目有 GitHub 正在使用的 g-emoji-element 以及 Twitter 的 twemoji 等。

本文将要介绍的就是引入 twemoji 来优化展现。🍻

使用方法

引入 twemoji.js

twemoji 官方默认提供 MaxCDN 作为加载源,但该 CDN 在国内似乎可用性并不好。因此,笔者还是一贯地选择 jsDelivr。当然,你也可以从官方仓库下载并制作你自己的源。

twemoji.js 从 NPM 拉取,使用:

<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/twemoji.min.js"></script>

将上述代码插入到网页中适当的位置,即可引入 twemoji。此时 window 下会有 twemoji 对象以便调用。💡

调用 parse 方法

twemoji.parse() 方法的详细用法在 README 中有很科学💎的说明,所以笔者在这里只介绍整体替换的思路。

这个方法接受两个参数:第一个参数是解析的对象,直接使用 document.body 即可;第二个参数是一个 Object,包含一些选项:

{
    callback: Function,   // default the common replacer
    attributes: Function, // default returns {}
    base: string,         // default MaxCDN
    ext: string,          // default ".png"
    className: string,    // default "emoji"
    size: string|number,  // default "72x72"
    folder: string        // in case it's specified
                          // it replaces .size info, if any
}
  • callback 是每次替换的回调,返回值将作为 <img>src 属性,即对应替换图片的 URL。
  • attributes 是另一个回调,返回值应该是一个 Object,这个 Object 将被整合到 imgattributes,例如返回 {test: 'test'} 就会使 <img> 多出一个 test="test" 的属性。
  • base 是 emoji 替换图片的加载源,默认是 MaxCDN,稍后笔者将会给出 jsDelivr 的对应参数值。⚠️
  • ext 指定 emoji 替换图片的扩展名,默认是 .png,也可以使用 .svg 或其他类型(需要 sizefolder 配合)。
  • className 指定 <img>class 属性,默认是 emoji,如果与现有 class 有冲突则需要改变。
  • size 指定“图片尺寸”,实质上是指定一个目录名。不建议修改。
  • folder 指定 emoji 替换图片的目录名,将会覆盖 size 的设置。

⚠️ 使用 jsDelivr 时,emoji 替换图片不能直接从 NPM 拉取,而是要从 GitHub 拉取,应该把 base 设置为 https://cdn.jsdelivr.net/gh/twitter/[email protected]/assets/(末尾的 / 不可省略,原因后述)。

如果没有指定 callback,组装 URL 的规则默认是 {base}{size|folder}/{icon}{ext},其中 icon 作为 callback 的第一个参数传入。所以,当使用默认 callback 时,如果 base 的末尾缺少 /,会直接导致 URL 拼接非法。同理,ext 也一定要以 . 开头。👌

综上,解析的代码如下:

twemoji.parse(document.body, {
    base: 'https://cdn.jsdelivr.net/gh/twitter/[email protected]/assets/'
});

handsome 主题

handsome 是 Typecho 主题,所以首先需要确保 Typecho 已经开启 emoji 支持,即数据库编码已经调整至 utf8mb4,否则可能会出现数据损坏的严重后果。调整的方法可以参考:使 Typecho 支持 emoji 的显示😂😂😂 以及 如何让Typecho支持emoji的存储。调整完毕后,可以发送几条包含 emoji 的评论测试配置是否有效。

handsome 主题配置中可以直接加入 twemoji 的设定:

第一步,依次展开 开发者设置 -> 自定义输出body 尾部的HTML代码,在末尾加入:

<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/twemoji.min.js"></script>

第二步,依次展开 开发者设置 -> 自定义 JavaScript,同样在末尾加入:

$(function() {
    twemoji.parse(document.body, {
        attributes() {return {nogallery: 'nogallery'};},
        base: 'https://cdn.jsdelivr.net/gh/twitter/[email protected]/assets/'
    });
});

第三步,依次展开 开发者设置 -> 自定义 CSS,还是在末尾加入:

img.emoji {
    height: 1em !important;
    width: 1em !important;
    margin: 0 .05em 0 .1em !important;
    vertical-align: -0.1em !important;
    border-radius: 0 !important;
    border: 0 !important;
    display: inline-block !important;
    padding: 0 !important;
}

为了处理样式冲突,不得不加了很多 !important(话说这也太多了吧😂)

如果你还开启了 PJAX,那么在 PJAX -> PJAX回调函数 末尾也需要加入第二步中的代码。

这样,我们就成功引入了 twemoji,emoji 在旧设备、旧系统也能很漂亮了~💯

]]>
9 https://ucw.moe/archives/import-twemoji.html#comments https://ucw.moe/feed/archives/import-twemoji.html
更新 Mathjax 至 v3 版本 https://ucw.moe/archives/upgrade-mathjax-to-v3.html https://ucw.moe/archives/upgrade-mathjax-to-v3.html Sat, 11 Apr 2020 08:39:00 +0800 无限UCW MathJax 目前已经推出了全新的 v3 版本,使用现代化的编程技巧重写了整个代码,包括 TS、ES6、Promises 等,同时全面采用 jsDelivr 作为默认 CDN 取代原先的 cdn.mathjax.org,在速度上有较大提升(国内尤为明显)。咕咕咕了很久之后我终于下定决心将其更新到了 v3 版本。这篇笔记就来讲解一下从 v2 升级到 v3 的一些快捷方法和注意事项。

[scode type="blue"]这篇笔记针对 Typecho 的 handsome 主题编写,对于其他程序/主题的 MathJax 更新可能仅仅只有启发作用。[/scode]

生成 v3 配置

MathJax 有一个配置选项,在 v2 系列版本中书写在 <script type="text/x-mathjax-config"> 标记中,例如 handsome 的默认配置是:

MathJax.Hub.Config({messageStyle: "none",tex2jax: {inlineMath: [['$','$'], ['\\(','\\)']]}});

但在 v3 版本中,上述配置格式不再被支持。好在我们可以使用 MathJax 官方推出的工具 MathJax Configuration Converter 来快速生成对应的 v3 配置。

我生成的配置是:

window.MathJax = {
    tex: {
        inlineMath: [['$','$'], ['\\(','\\)']],
        autoload: {
            color: [],
            colorV2: ['color']
        },
        packages: {'[+]': ['noerrors']}
    },
    svg: {
        fontCache: 'global'
    },
    options: {
        ignoreHtmlClass: 'tex2jax_ignore',
        processHtmlClass: 'tex2jax_process'
    },
    loader: {
        load: ['[tex]/noerrors']
    }
};

用 Promises 重写部分内容

笔者使用的 handsome 主题在 pjax 时有一次 MathJax.Hub.Queue(["Typeset",MathJax.Hub,"body"]); 的操作,这种写法不再被 MathJax 支持了,于是笔者参考 Typesetting and Converting Mathematics — MathJax 3.0 documentation 将其重写。重写后实际上更短了:

MathJax.typeset();

简单直接,暴力美学。

如果你的调用更加复杂,请尽可能详细阅读文档再对应作出修改。

替换调用地址

Converter 生成的整个配置是可以直接复制并插入 body 的末尾的,例如一个类似这样的东西:

<script src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-svg.js" id="MathJax-script"></script>

我的写法是:

<script src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-svg.js" async></script>

并没有什么明显的区别。插入部署完毕后,来到前端页面 F12 并在 Console 中运行 MathJax.version,就可以看到 3.x.x 的返回值咯 ~

参考

]]>
5 https://ucw.moe/archives/upgrade-mathjax-to-v3.html#comments https://ucw.moe/feed/archives/upgrade-mathjax-to-v3.html
CSS+JS轻松实现自定义黑幕效果 https://ucw.moe/archives/js-with-css-implements-heimu.html https://ucw.moe/archives/js-with-css-implements-heimu.html Sat, 07 Dec 2019 10:23:10 +0800 无限UCW 引入

什么是“黑幕效果”呢?

[heimu]像这样[/heimu],正常状态下被一个黑条遮挡,只有当鼠标放在上面(移动端是长按)后才显示出内容的,富有交互性的有趣功能样式,就被成为“黑幕效果”。它可以让文章更加活泼,内容更加有趣,[heimu]以及表达一些特殊的语气~[/heimu]

这样,你就对黑幕效果有了一个基本的认知[heimu],阅读气氛也活跃起来了[/heimu],下面我们就来看一看小黑条的背后有哪些核心技术。 ::majsoul:028::

CSS部分

虽然大家都知道了,但还是简单提一句,CSS(Cascading Style Sheets,层叠样式表)是现代互联网技术中一个重要的组成部分,在前端开发中有着至关重要的地位。通过这种东西,我们可以方便地为网页中的内容添加丰富多彩的样式。

黑幕效果需要哪些样式呢? ::majsoul:034::

我们再来看一下黑幕效果的呈现:[heimu]我是小黑条~[/heimu]

它的背景是黑色的,文字颜色与背景相同,所以正常状态下看不见文字内容。背景颜色在CSS中通过background-color属性控制,而前景色(也就是文字颜色啦)通过color属性控制,为了方便,我们定义一个.heimu类,这样所有class="heimu"的元素都可以自动获得我们规定的这些属性。就像这样:(现在请暂时不要记笔记,需要记笔记的时候我会提醒你哦)

.heimu {
    background-color: #000;
    color: #000;
}

这个东西怎么用呢?我们写一个测试页面看看:

<!doctype html>
<html>
<head>
<title>heimu test</title>
<style>
.heimu {
    background-color: #000;
    color: #000;
}
</style>
</head>
<body>
<p>This is <span class="heimu">heimu text</span>.</p>
</body>
</html>

测试页面的结果

(蓝色部分是我用鼠标选中造成的)还行,有那种感觉了,但是黑幕效果怎么变成了刮刮乐啊?

这是因为我们还没有处理鼠标移入(或移动端长按)时这个样式的变化。这部分我们使用:hover伪类实现,这个伪类将会在鼠标放上去的时候起作用,改变样式。

.heimu:hover, .heimu:active {
    color: #FFF;
}

实际使用时,我还使用了:active伪类,但它在此处作用不明显[heimu],仅仅是我出于心理安慰加上的[/heimu]。在测试页面中加入这部分内容,我们就基本完成啦~

实际使用时,不一定要用完完全全的黑色,只需要前景色与背景色一致即可;我们还可以加入渐变(用transition实现)。下面放出我使用的CSS部分内容,同学们可以记笔记啦~

.heimu:active, .heimu:hover {
    color: #fff
}

.heimu {
    background-color: #252525;
    color: #252525;
    text-shadow: none;
    transition: color 0.3s;
}

JS部分

通过前面的样式准备工作,我们已经可以通过<span class="heimu" title="你知道的太多了">小黑条~</span>这样的方式来调用我们的黑幕效果了,但是这样未免冗长,而且大部分都是重复内容。

我们规定一个自定义语法[heimu]xxx[/heimu],把一对这样的闭合标记解析为<span class="heimu" title="你知道的太多了">xxx</span>,中间内容不变,这样就可以大大降低我们调用时的工作量。这个工作可以交给插件实现,也可以交给js实现。出于性能考虑,我用js写了一个不算完整的实现。

用js进行替换的原理是正则匹配,在整个文章内容中按照DOM树遍历一次,完成整个替换。之所以没有直接替换是因为要规避一些特殊标记内的关键文本,例如数学公式和<code>元素。这样同时带来了一个缺陷,即黑幕效果只能覆盖简单文本,复杂文本(例如有链接的情况)当前版本是无法解析的。这里直接给出代码如下:

function icore_init() {
    var t = new RegExp("\\[heimu\\](.*?)\\[/heimu\\]","g");
    $("div.entry-content,div#morphing-content>div.page").children("p,blockquote,div.tip").each(function() {
        var n = "";
        $(this).contents().each(function() {
            var i = this.outerHTML;
            null == i && (i = $(this).text()),
            null != i && ((1 === this.nodeType || 3 === this.nodeType) && "IMG" != this.tagName && "PRE" != this.tagName && "CODE" != this.tagName && "SCRIPT" != this.tagName && "BR" != this.tagName ? -1 != $.inArray("light-link", this.classList) || function(t=this.classList) {
                if (null == t || null == t)
                    return !1;
                for (var n = 0; n < t.length; n++)
                    if (-1 != t[n].indexOf("MathJax"))
                        return !0;
                return !1
            }() ? n += i : (i = i.replace(t, function() {
                return '<span class="heimu" title="\u4f60\u77e5\u9053\u7684\u592a\u591a\u4e86">' + arguments[1] + "</span>"
            }),
            n += i) : n += i)
        }),
        $(this).html(n)
    });
}
icore_init();

[heimu]可以看到内容极其紊乱,其实是我混淆后找不到原文件了(悲[/heimu]

只对handsome主题5.x系列版本做了适配,不保证不出现未知问题,如有情况可以评论联系我,但不保证解决。

如果开启pjax,请在pjax回调函数中加入icore_init();,否则无刷新加载后不会进行解析。(handsome主题的该配置项位于“PJAX->PJAX回调函数”中,如果其中已经有代码,加入在末尾即可)

title属性可以自定义,该属性规定的是鼠标放上去后显示的文本。

至此,黑幕效果背后的黑科技已经完全呈现在你眼前了~ ::majsoul:077::

顺便说一句,这部分内容也包括在我的自定义增强效果iCore(不过暂时没有开源,因为内容太少了)中哦~ ::majsoul:102::

]]>
6 https://ucw.moe/archives/js-with-css-implements-heimu.html#comments https://ucw.moe/feed/archives/js-with-css-implements-heimu.html
自动生成OwO.json,快速扩展OwO表情 https://ucw.moe/archives/owojson-generator.html https://ucw.moe/archives/owojson-generator.html Wed, 25 Sep 2019 14:42:00 +0800 无限UCW 最近给博客增加了船新的雀魂表情包,由于从导出表情到重新配置OwO.json都是完全由自己来完成,不像上次扩展贴吧表情的时候有现成的东西可以直接拿来用,所以记录一下以便之后需要时留作参考。 ::majsoul:001::

并没有尝试一组表情中能否多种格式图片并存,这次统一采用了png格式,避免给自己找锅。

本次新增的一组表情共计151张,需要在OwO.json中对它们一一进行声明。手写是不太可能的,因为是大量的重复工作,懒惰如我显然是宁可写一个Generator也不会去一条条加。gen.py的内容如下:

#!/usr/bin/python3
OWO_NAME='雀魂'
OWO_SLUG='majsoul'
PICTURE_COUNT=151

f=open("OwO.json","w",encoding='utf-8')
f.write('''  "%s": {
    "name": "%s",
    "type": "image",
    "container": [
'''%(OWO_NAME,OWO_SLUG))
for i in range(1,PICTURE_COUNT+1):
    f.write('''      {
        "icon": "%03d",
        "text": "%03d"
      }'''%(i,i))
    if i<PICTURE_COUNT:
        f.write(',')
    f.write('\n')
f.write('''    ]
  }''')
f.close()

其中OWO_NAME为这组表情的显示名称,OWO_SLUG为表情的内部别名,PICTURE_COUNT为图片总数。若需要生成其他表情包声明,改动这些值即可。

执行后将在当前目录下生成一个OwO.json,内容是需要插入到完整OwO.json中的这个表情包的声明。 ::majsoul:029::

[scode type="yellow"]这里生成的并不是完整的json文件,需要手动将其插入完整的OwO.json中。[/scode]

如果执行正确,将会生成形如下方代码块中所示的一段文本:

  "雀魂": {
    "name": "majsoul",
    "type": "image",
    "container": [
      {
        "icon": "001",
        "text": "001"
      },
      {
        "icon": "002",
        "text": "002"
      }
    ]
  }

为方便起见,我只列出了PICTURE_COUNT=2的情况。

插入位置如下图所示,需要视情况在后方补一个半角逗号。

插入位置举例

应用json检测工具检测通过后即可部署。


由于上述代码是针对Python3编写的,考虑到有时并不方便获取Python3执行环境,补充一个JavaScript版本:

(function(){
    'use strict';
    const OWO_NAME="雀魂";
    const OWO_SLUG="majsoul";
    const PICTURE_COUNT=151;
    
    const html_encode=str=>{
        let s="";
        if (str.length==0)return""; 
        s=str.replace(/&/g,"&amp;");
        s=s.replace(/</g,"&lt;");
        s=s.replace(/>/g,"&gt;");
        s=s.replace(/ /g,"&nbsp;");
        s=s.replace(/\'/g,"&#39;");
        s=s.replace(/\"/g,"&quot;");
        s=s.replace(/\n/g,"<br/>");
        return s; 
    }
    let output=`  "${OWO_NAME}": {
    "name": "${OWO_SLUG}",
    "type": "image",
    "container": [
`;
    for(let i=1,num;i<=PICTURE_COUNT;i++){
        num=(Array(3).join('0')+i).slice(-3);
        output+=`      {
        "icon": "${num}",
        "text": "${num}"
      }`;
        if(i<PICTURE_COUNT)output+=',';
        output+='\n';
    }
    output+=`    ]
  }`;
    document.write(`<code>${html_encode(output)}</code>`);
})();

在浏览器中新建标签页,按下F12键,在开发人员工具的Console选项卡中粘贴并执行上述代码即可生成在网页上,复制后插入即可。

JS版本

]]>
4 https://ucw.moe/archives/owojson-generator.html#comments https://ucw.moe/feed/archives/owojson-generator.html
魔改Lazyload前台调用代码实现异步加载图片 https://ucw.moe/archives/call-image-lazyload.html https://ucw.moe/archives/call-image-lazyload.html Fri, 13 Sep 2019 08:30:00 +0800 无限UCW 图片传输效率又是一大性能瓶颈,有钱人们选择用对象储存解决,我就没法解决。

当然是不可能的。

我使用的handsome主题自带lazyload功能,但是默认关闭,且作者并不推荐使用,称或将带来卡顿(?)。
当然,即使你的网站没有lazyload,你也可以自行引入,这里不再赘述。

什么是Lazyload

一个可以实现图片懒加载的插件。所谓图片懒加载,即“你不看我就不加载”,最经典的操作便是监听一个scroll事件,当『快要看到这张图片』时,开始一个异步请求进行图片的加载。不难发现,其中最重要,也最微妙的就是对于『快要看到这张图片』时机的把握。

大部分经典的实例,是通过一个距离来控制,也就是lazyload中的threshold参数。它用于设置一个临界值,当屏幕下端距离屏幕外的图片距离小于等于这个值的时候,lazyload开始load。大概类似于早自习犯困的你拜托同桌当老师来的时候提醒你一下(addEventListener),当负责任又好心的同桌提醒你时(trigger),你就赶紧爬起来认真早读。

为何使用Lazyload

我注意到,当网络状况差,图片无法立即加载时,大部分关键的js都处于蓄势待发状态,需等待图片加载完成(此时才会触发document的ready)才会开始执行,极大地影响了用户[heimu]我自己[/heimu]体验。事实上,图片加不加载好对我js的执行并没有影响,完全可以让图片加载自个在后面慢慢拖,而让document的ready提前,从而尽可能缩短js不执行的糟糕真空期。

这时,就轮到lazyload大显身手啦~

使用handsome主题的typecho用户可以通过打开“后台->控制台->外观->设置外观->主题增强功能->增强功能开关”中的“延迟加载图片(lazyload)”选项来打开lazyload。

handsome中启用lazyload

通用的方法是在body结束前、jQuery加载后手动引入lazyload.js

<script src="https://cdn.jsdelivr.net/npm/[email protected]/jquery.lazyload.min.js"></script>

同时对需要进行lazyload的元素属性作一定的调整,设置data-original为实际加载地址,并设置一个占位图片,在这里不再赘述。

问题与改进

在使用过程中,我发现了新的问题,即我的图片加载实在是太 慢 了,以至于根本无法在滚动到图片位置时完成加载。就好像虽然你的同桌提醒了你,但你实在是太困,一直磨蹭到老师站在你面前了也没把书拿出来。

事实上,我们也不是真的希望这个图片“懒”,只是希望它不要给大家拖后腿,别卡住document的ready事件。

那么我们就完全可以跳出常规思路,不再使用默认的scroll作为触发事件。lazyload提供了一个参数event允许我们自定义触发事件。只需要给这个参数随便传一个不冲突的事件名字,在设置完成lazyload之后立即trigger我们的自定义事件,即可瞬间开始图片的异步请求,而不必等待滚动,如此一来就能进一步优化体验。

栗子:

$("img").lazyload({
    effect: "fadeIn",
    event: "display" // 替换默认的触发事件
});
$("img").trigger("display"); // 立即触发

仅仅是这样似乎还不够,lazyload似乎仍然是滚动优先触发。虽然做到这个程度已经差不多了,但我不想让它的触发机制复杂起来,不妨设想有时需要点击后再开始加载,这时滚动触发就没法让它按照预期去呈现。所以我们再给它补一个threshold参数混淆视听,设置一个绝对值很大的负数,滚动触发基本上就没什么戏了。这里我选择了-0x7fffffff,下面是我最终使用的代码:

$("img").lazyload({
    threshold: -0x7fffffff, // 让不需要的部分见鬼去
    effect: "fadeIn",
    event: "display" // 替换默认的触发事件
});
$("img").trigger("display"); // 立即触发
]]>
3 https://ucw.moe/archives/call-image-lazyload.html#comments https://ucw.moe/feed/archives/call-image-lazyload.html