【问题标题】:Vue replaces "open" attribute to value "open" in any tagVue 将任何标签中的“open”属性替换为“open”值
【发布时间】:2021-08-06 19:56:37
【问题描述】:

我在 laravel 刀片模板中使用 vue.js (v2.6.12) 组件。 对于该项目,我还使用了 MathML,其中我需要使用 <mfenced> 标签的 open 属性将其设置为一些自定义值。这是用 mathml 表示的数学示例。

<math xmlns="http://www.w3.org/1998/Math/MathML">
    <mi>f</mi>
    <mfenced close="]" open="[">
        <mrow><mi>a</mi><mo>,</mo><mi>b</mi></mrow>
    </mfenced>
</math>

但是一旦页面呈现,open 属性就会转换成这个open="open"。我 100% 确定没有其他库或脚本加载像这样更新,只是普通的 vue。这实际上破坏了数学表达式。所以它看起来像这样:

<math xmlns="http://www.w3.org/1998/Math/MathML">
    <mi>f</mi>
    <mfenced close="]" open="open">
        <mrow><mi>a</mi><mo>,</mo><mi>b</mi></mrow>
    </mfenced>
</math>

后来我意识到,不仅在数学表达式中,任何标签,无论是&lt;div open="anything"&gt;...&lt;/div&gt;&lt;span open="anything"&gt;...&lt;/span&gt;&lt;custom-element open="something"&gt;...&lt;/custom-element&gt;,具有open 属性的行为都是相同的。即使我使用v-pre 属性将其从 vue js 模板编译器中排除。

这不会发生,只要我禁用 vue 应用程序初始化。


这里的问题是:

  1. 为什么 vue 会这样改变 open 属性?
  2. 我怎样才能停止这种行为,到 vue 应用程序区域内的整个页面,或者至少在我选择的地方(比如使用 v-pre),是否有 ary config 或任何其他方式?

【问题讨论】:

  • 您听起来好像已经在这里进行了调试研究,但我想不出仅在 Vue 中会导致这种行为的任何东西......这真的很奇怪。我知道您说您确定这里没有其他库在起作用,但我倾向于相信其他东西必须在这里起作用。您是否在项目的其他地方使用任何其他 Vue 库?

标签: vue.js vuejs2 attributes mathml


【解决方案1】:

我找到了一个简单的技巧来解决这个问题。

为什么要破解?

因为正如@Michal 所指出的,它最终会在即将发布的版本中得到修复,所以现在只需一个快速而肮脏的 hack 就足够了。

我所做的是将数学内容放在内容中,并将其添加到数据属性中,并在 vue 完成糟糕的工作后替换原始内容(抱歉这里只使用刀片语法,但它会有意义)。我把它放在这两个地方只是为了 SEO 的目的。

我需要显示数学表达式的模板。

...
<div class="proxy-content" data-proxy-content="{{ $article->content }}">
    {!! $article->content !!}
</div>
...

我将它与 jQuery 一起使用,但您可以轻松地替换为 vue.js 的$el。这就是它在我的app.js 文件中的样子。

...
const app = new Vue({
    el: '#app',

    methods: {

        proxyContent() {
            // Set Proxy Content.
            jQuery('.proxy-content').each((i, el) => {
                const $el = jQuery(el);
                $el.html( jQuery('<textarea />').html( $el.data('proxy-content')).text() );
            });
        }
        
        loadMathJax() {
            // Load & Initialize MathJax Library.
            const script = document.createElement("script");
            script.type = "text/javascript";
            script.src  = "https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js";
            document.getElementsByTagName("head")[0].appendChild(script);
        }

    }

    mounted(){
        // Enable proxy content after mount, so we are sure no more rendering issue for templates.
        this.proxyContent();

        // Load MathJax library with a little delay to make sure everything is ready before loading the library.
        setTimeout(() => this.loadMathJax(), 10);
    }
});
...

有人可能会争辩说,我正在混淆 vue 应用程序范围之外的内容。对我来说这不是问题,因为整个页面都在使用vue.js,而且即使有另一个使用mathml 的范围也不会造成任何伤害(尽管它取决于实际实现)。

在这种情况下,如果你想很好地确定它的范围,只需使用 vue 的$el

【讨论】:

    【解决方案2】:

    一种解决方法是创建一个设置属性的directive(名为"attr"):

    Vue.directive('attr', (el, binding) => el.setAttribute(binding.arg, binding.value || ''))
    

    然后在您的模板中使用它,例如v-bind,但使用v-attr

    <mfenced v-attr:open="'['">
    

    Vue.directive('attr', (el, binding) => el.setAttribute(binding.arg, binding.value || ''))
    
    new Vue({ el: '#app' })
    <script src="https://unpkg.com/vue@2.6.12"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.7/MathJax.js?config=TeX-MML-AM_CHTML"></script>
    
    <div id="app">
      <math xmlns="http://www.w3.org/1998/Math/MathML">
        <mi>f</mi>
        <mfenced close="]" v-attr:open="'['">
          <mrow><mi>a</mi><mo>,</mo><mi>b</mi></mrow>
        </mfenced>
      </math>
    </div>

    【讨论】:

    • 谢谢,这个解决方案很好,但有时我们没有机会修改/挂钩到编辑器,我们首先使用它来创建数学表达式。我为这个问题找到了一个 KISS 出路,并解释了我的答案。
    【解决方案3】:

    为什么

    在 HTML 规范中有一些属性称为boolean attributes。规范规定了此类属性的值:

    如果该属性存在,其值必须是空字符串或与属性的规范名称匹配的不区分大小写的 ASCII 值,并且没有前导或尾随空格。

    布尔属性不允许使用值“true”和“false”。要表示假值,必须完全省略该属性。

    open 是布尔属性之一 - 它是为 &lt;details&gt; element 定义的

    Vue 2 的问题在于,它将大部分 boolean attributes 视为全局 - 而不考虑它所在的元素。结果是open 属性总是以值“open”呈现,或者如果值是假的(当v-binding 时)被删除。这在 Vue 3 中已修复,如第二个示例所示...

    如何

    使用v-pre 是可行的方法,但不幸的是,有一个错误。
    this issue。该错误已通过commit(2020 年 9 月 21 日)修复,但尚未发布...

    1. 示例 - “With v-pre”应该在 Vue 版本 > 2.6.12 中工作

      const vm = new Vue({
        el: '#app',
        data() {
          return {
            message: 'Hi!',
            html: `<div open="[" close="]">Hi from html</div>`
          }
        },
      })
      <script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.6.12/vue.js"></script>
      <div id="app">
        <div open="[" close="]">{{ message }}</div>
        <div v-html="html"></div>
        <div v-pre>
          <p open="[" close="]">With v-pre</p>
        </div>
      </div>
    2. 示例 - 它适用于 Vue 3 - open 仅在放置在 &lt;details&gt; 上时才被视为布尔属性

      const app = Vue.createApp({
        data() {
          return {
            message: 'This works in Vue 3!',
          }
        },
      })
      
      app.mount('#app')
      <script src="https://cdnjs.cloudflare.com/ajax/libs/vue/3.0.11/vue.global.js" integrity="sha512-1gHWIGJfX0pBsPJHfyoAV4NiZ0wjjE1regXVSwglTejjna0/x/XG8tg+i3ZAsDtuci24LLxW8azhp1+VYE5daw==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
      
      <div id="app">
        <div open="[" close="]">{{ message }}</div>
        <details open="[">
          <summary>Details</summary>
          open attribute on details element is treated as boolean (renders empty value)
        </details>
      </div>

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-01-29
      • 1970-01-01
      • 2014-03-12
      • 2018-10-16
      • 1970-01-01
      • 2013-01-09
      • 2013-01-23
      • 2018-03-03
      相关资源
      最近更新 更多