测试版本: vue@3.2.31 https://github.com/vuejs/core...
我们来看这样一个vue单文件组件的文件App.vue
:
<template>
<pre data-type="js">
<code v-html="'<span>show-it.</span>'"/>
</pre>
<div class><span class></span><span class></span></div>
</template>
<script>
import { defineComponent } from 'vue';
export default defineComponent({
name: 'App',
});
</script>
完整案例可以在这里在线查看:https://stackblitz.com/edit/vue3-v-html-render-error
或者查看https://codesandbox.io/s/eager-paper-prv33s
该案例中,show-it
是可以正常显示的,但如果我们去掉v-html
中的英文点号.
,则当前代码是无法正常显示的。经过测试,发现还有以下几种情况显示有问题:
- 【无法显示】去掉那个英文点号
<template>
<pre data-type="js">
<code v-html="'<span>show-it</span>'"/>
</pre>
<div class><span class></span><span class></span></div>
</template>
- 【正常显示】
pre
标签增加非html原生标签属性
<template>
<pre a data-type="js">
<code v-html="'<span>show-it</span>'"/>
</pre>
<div class><span class></span><span class></span></div>
</template>
3.【正常显示】去掉pre
后面的兄弟标签,或者移除某个class
属性
<template>
<pre data-type="js">
<code v-html="'<span>show-it</span>'"/>
</pre>
<div><span class></span><span class></span></div>
</template>
<template>
<pre data-type="js">
<code v-html="'<span>show-it</span>'"/>
</pre>
</template>
4.【无法显示】div
标签内增加第三个带class
(html原生标签属性)的子元素
<template>
<pre data-type="js">
<code v-html="'<span>show-it</span>'"/>
</pre>
<div class><span class></span><span class></span><span class></span></div>
</template>
5.【正常显示】div
标签内增加第三个带a
(非html原生标签属性)的子元素
<template>
<pre data-type="js">
<code v-html="'<span>show-it</span>'"/>
</pre>
<div class><span class></span><span class></span><span a></span></div>
</template>
6.【正常显示】外部包裹一层带非html原生标签属性的元素
<template>
<div a>
<pre data-type="js">
<code v-html="'<span>show-it</span>'"/>
</pre>
<div class><span class></span><span class></span></div>
</div>
</template>
这就很奇怪了:
- 如果他的显示和非html原生标签属性有关,那么例子1、3、4说不过去
- 如果他的显示和某些特殊符号
.
有关系,那么除了例子1以外的都说不过去
查了很久,不知道究竟错在了哪里,还是vue3
本身解析语法树的问题,请求网络上的各位大神帮忙看看,也请各位帮我献计献策找找原因吧。
简单看了下,感觉是bug,可以尝试去github上提个issue
我这边简单研究了下编译产物,基本可以确定是vue3在做静态树提升(Static Tree Hoisting)优化时在某些条件下错误的把v-html里的东西优化没了,导致表现出问题
在生成静态节点代码时,如果节点比较简单,就会用createTextVNode和createElementVNode去拼这个静态节点
如果静态节点比较复杂且满足一些其他不知道什么的条件时,vue3就会去调用createStaticVNode去生成静态节点(createStaticVNode接受一个字符串,字符串内容是html字符串)
产生问题的case就是命中了vue3使用createStaticVNode去生成静态节点的优化,而vue3生成的createStaticVNode的参数,即这个静态节点生成的html字符串有问题(此时其实因为有v-html接收参数不应该使用createStaticVNode去生成静态节点,而应该用createTextVNode和createElementVNode手动拼,官方的修复方案也是改了判断条件)
github上已经有人给出了workaround
https://github.com/vuejs/core...
就是在传给v-html的静态字符串外面加个括号,避免静态树提升优化