💣 事情经过
在某个中秋节, 心血来潮的我咔嚓咔嚓写起了 Yondaime (一个没什么人用的博客框架) 的一个 Feature, 具体功能是这样的, 小T同学说要在网站底部加上网站的备案号, 但思来想去, 直接在配置加上一个备案号的专属配置实在是不太通用, 毕竟下次他可能就这么要求:
"废物, 我要在底部加外链"
^_^ : 滚
因此解决方案是这样的, 在配置中加多一个底部栏的拓展, 允许用户自定义底部栏的文案, 具体 api 如下:
config.js 配置文件
{
// ...省略好多配置
footers: ['备案号: xxxxxx'],
}基于以上配置, 在项目中进行功能点开发:
<template>
<div v-for="(footer, index) of footers" :key="index">
<span>{{ footer }}</span>
</div>
</template>
<script>
export default {
data() {
return {
footers: ['备案号: xxxxxx'],
};
}
};
</script></code></pre><p>嗯嗯, 大概就这样了, 很简单的一个功能</p><p>但是! 得兼容一下外链的场景, 因此 footers 格式修改一下:</p><pre><code class="ts">type Footer = string | { label: string, link: string }</code></pre><p>这种格式进可支持支持带链接的文本, 退可支持纯文本展示, 简称 "全 能"</p><p>啊? 你问我为什么不直接改成这样:</p><pre><code class="ts">type Footer = { label: string, link?: string }</code></pre><p>那是考虑到灵活性, 怎么扭都可以~ 🕶 墨镜一戴, 谁都不爱</p><p>于是乎, 根据上面的配置修改一下代码:</p><pre><code class="html"><template>
<div v-for="(footer, index) of footers" :key="index">
<a v-if="footer.link" :href="footer.link">{{ footer.label }}</a>
<span v-else>{{ footer }}</span>
</div>
</template>
<script>
export default {
data() {
return {
footers: ['备案号: xxxxxx', { label: 'Ruofee\'s blog', link: 'http://ruofee.cn' }],
};
}
};
</script></code></pre><p>这么简单的改动, 爷测都不用测 - . -</p><h2 id="item-0-2">💥 终究还是出问题了</h2><p>小T同学用了以下的配置去添加网站的备案号:</p><pre><code class="js">{
// ...省略好多配置
footers: ['备案号: xxxxxx'],
}</code></pre><p>但展示的结果却出乎我的意料, 底部栏什么文本都没出现...</p><p>爷震惊了!</p><h2 id="item-0-3">💊 发现原因</h2><p>经过一番查找, 我发现原因在于:</p><p>当 footer 为"备案号: xxxxxx"时, v-if="footer.link" 竟然判定为 true 了, 也就是 footer.link 是存在的</p><p>我人都傻了</p><p>先把 footer.link 打印出来瞅瞅:</p><pre><code class="js">"function link() { [native code] }"</code></pre><p>诶, 竟然是个函数, 那看看函数执行会返回什么:</p><pre><code class="js">"<a href="undefined">备案号: xxxxxx</a>"</code></pre><p>footer.link 返回了一个超链接, 链接的 href 为 函数的第一个参数, 看到这里我更懵了, 难道是 vue 封装的时候把这个方法写在变量的原型链上吗, 作为一个通用的方法方便用户生成一个超链接? </p><p>那确实也有可能</p><p>...</p><p>吧?</p><p>A Long Time Later...</p><p>好吧我翻了 vue 和 vue-router 的源码, 还是没能找到, 该不会是 vue 的依赖库修改到了吧, 一想到我就脑壳痛, 阿西吧!</p><p>突然灵光一现, 该不会是 String 类型本身就有这个方法吧!</p><p>一试, 果然是这样, 一切都在我的掌控之中 ⭐️</p><blockquote><p><strong><code>link()</code></strong> 方法创建一个 HTML 元素 <a href="https://link.segmentfault.com/?enc=0RhkQfvxdwZp4VLmcxq3cg%3D%3D.2jPlspZGOojqdoOiakqDK2CdGZubQZbTc2Ly%2BApX61l4QvZu7HQzVDcLog5rJ3wV469ctJPYOcQxVBHbAkm7Kw%3D%3D" rel="nofollow" target="_blank"><code><a></code></a> ,用该字符串作为超链接的显示文本,参数作为指向另一个 URL 的超链接。</p><p><strong>已废弃:</strong> 该特性已经从 Web 标准中删除,虽然一些浏览器目前仍然支持它,但也许会在未来的某个时间停止支持,请尽量不要使用该特性。</p><p>From <a href="https://link.segmentfault.com/?enc=uYeySbpu3EZ0wv0fXBkOVQ%3D%3D.7jA3zYrHida%2BXh2Tp8jy%2B3tVF8TF5VQyJwAuHAxIN%2FH8Dauiwgu%2FLL0PSa9gCEX%2B9Qa6LCOXEjIdWUhNbp8YhSGzrVw2JkWMvnZZaPxBfp53GFDpLDbPafdLGgGHcQBg" rel="nofollow" target="_blank">MDN</a>.</p></blockquote><p>是我无知了 =.= 还一度以为是我的 vue 和其他人的不一样, 但这确实是个踩坑点</p><p>虽然是我不测试导致的后果 (删掉)</p><p>啊? 你问我为什么通过判断 footer 的类型来进行区分? 像这样:</p><pre><code class="html"><template>
<div v-for="(footer, index) of footers" :key="index">
<span v-if="typeof footer === 'string'">{{ footer }}</span>
<a v-else :href="footer.link">{{ footer.label }}</a>
</div>
</template></code></pre><p>那肯定是因为<code>v-if="footer.link"</code>比 v-if=<code>"typeof footer === 'string'"</code>短一些 (逃</p><h2 id="item-0-4">🍔 后续</h2><p>我改成用类型进行判断了 @.@</p><p>嘻嘻</p>