博客园在Markdown中使用JS
如果能在博客园的 Markdown 中使用 JS,那将是一件十分方便的事情(类似于jupyter notebook)。但是,经过测试发现,我们无法在 Markdown 中直接写 JS,比如我写了如下随笔
## 标题
- foo
- bar
<script>
console.log('hello?')
</script>
进入博客园后发现控制台并没有输出 hello?
,CTRL+U 观察源代码发现<script>
被博客园去掉了,即
<div id="cnblogs_post_body" class="blogpost-body cnblogs-markdown">
<h2 id="标题">标题</h2>
<ul>
<li>foo</li>
<li>bar</li>
</ul>
</div>
<!-- script不见了 -->
<div id="MySignature"></div>
... 其他代码
针对上面的问题,下面介绍在博客园Mardown中使JS生效的两种方式。
借助eval
函数
考虑到博客园的页脚 HTML 处是可以运行任何 JS 的。浏览器在解析到我们在页脚 HTML 处的 JS 之前,已经拥有了 Dom 树。一个思路是某个 Dom 节点的文本写上 JS,然后再在页脚 HTML 处的 JS 通过 eval 调用该文本。
那么如何选择 Dom 节点呢?
我们可以将其写在一个非标准的标签中,如
但是这样在 Markdown 中没有代码高亮且不能自动缩进。为了不容易写错,这里选择了
这段代码会被博客园在后台处理成
<pre id="copy_target_2">
<code class="language-es6">
console.log('run')
function foo(){
console.log('foo')
}
foo()
</code>
</pre>
因此我们只要在页脚 HTML 代码处增加这样的脚本
/**
* 在Markdown中运行脚本,为了有高亮和提示效果,这里用了es6
*/
$('code.language-es6').each(function () {
window.eval($(this).text())
$(this).parent().remove()
})
奏效。
借助body标签的onload
属性
另一个思路将代码写在body的onload属性中。向onload传递一个函数调用。该函数需要在自定义页脚HTML代码
处定义。
<body
onload="invokeMyFunction(function bar(){
console.log('load')
function foo(){
console.log('foo')
}
foo()
})"
></body>
自定义页脚HTML代码 处配置如下JS
window.invokeMyFunction = function(cb) {
cb()
}
奏效。你也可以参考这篇文章的Markdown博客园调用网易新闻接口实现动态网页
进一步测试
经过简单测试,两种方式均能奏效,那么选哪一种呢?我们需要进一步的测试
首先故意写错JS,如下
console.log('run')
function foo() {
console.log('foo')
+ 不存在的函数()
}
foo()
同时使用两种方式,并观察控制台的输出结果
点进栈顶的定位
发现eval并不能定位到HTML的哪一行,只是定位到了我们的全局JS,并不能定位到随笔页。但是onload的方式就很明细了(注意要webpack要配置成调试模式inline-source-map
)
module.exports = {
devtool: process.env.NODE_ENV === 'production' ? 'source-map' : 'inline-source-map',
}
接下来测试运行效率,在自定义页脚HTML代码处增加记时逻辑
$('code.language-es6').each(function() {
const start = new Date().getTime()
window.eval($(this).text())
const end = new Date().getTime()
console.log('debug: eval耗时' + (end - start) + '毫秒')
$(this).parent().remove()
})
window.invokeMyFunction = function(cb) {
const start = new Date().getTime()
cb()
const end = new Date().getTime()
console.log('debug: onload耗时' + (end - start) + '毫秒')
}
在Markdonw中加入测试程序
发现对于这种运算,eval慢的并不明显
总结
对于onload
方法
优点:
- 效率高那么一点点
- 方便调试
缺点:
- 只能用一次
- 不够优雅,可读性差
对于eval
方法
优点:
- 看起来更为优雅,可读性更好
- 可以使用多次
缺点:
效率低(低频使用时影响不大)不安全(有方法防范就安全了)- 不方便调试
综合比较还是使用eval
方法更好些,对于无法定位这个问题,可以先用eval方法,报错后如果不能一眼找到原因,再改用onload方法,最后切换为eval方法。