Vue.js无法切换字体Awesome图标。

12

我试图根据布尔值切换Font Awesome图标,但似乎在绘制后,Font Awesome图标仍然停留在屏幕上:

https://jsfiddle.net/50wL7mdz/200312/

HTML:

<script src="https://unpkg.com/vue"></script>
<script defer src="https://use.fontawesome.com/releases/v5.0.8/js/all.js" integrity="sha384-SlE991lGASHoBfWbelyBPLsUlwY1GwNDJo3jSJO04KZ33K2bwfV9YBauFfnzvynJ" crossorigin="anonymous"></script><div id="app">
  <input v-model="marked" type="checkbox"/>
  <i v-if="marked" class="far fa-check-square"></i>
</div>

JS:

new Vue({
  el: '#app',
  data: {
    marked: false
  }
})

我做错了什么还是font-awesome或vue.js有bug?


有时候会出现,有时候又不会。你也看到这种情况了吗? - acdcjunior
1
由我所写,一旦出现就会一直存在。 - TheOne
https://github.com/vuetifyjs/vuetify/issues/3058 - TheOne
当我正在教别人时,我讨厌这种事情发生。它会使我的思维混乱。 - chickens
这篇帖子帮助我解决了一个非常相似的问题:Font Awesome在vue中无法正确更新简而言之:将其包装在<span>或其他组件中,并在包装器上应用“key”属性,以便告诉Vue不要重用组件。 - Efonzie
6个回答

17

最近我在使用Vue.js 2.5.x和FontAwesome 5.5.x时遇到了这个问题 - 图标类没有按预期更新。

在从FontAwesome Web Fonts + CSS实现切换到SVG + JS之后,以下代码不再起作用:

<i :class="[sortByFirstNameAsc ? 'fa-chevron-up' : 'fa-chevron-down', 'fa']"></i>

FontAwesome JavaScript会被触发并包装<i>标签,并将其替换为SVG元素,如下面简化的示例所示:

<span data-v-2614dbd6="">
  <svg data-v-2614dbd6="" class="svg-inline--fa fa-caret-up" ...">
    ...
  </svg>
  
  <!-- <i data-v-2614dbd6="" class="fa fa-caret-up"></i> -->
</span>

不幸的是,活动类被切换到了内部隐藏的 <i> 标签上,而不是外部可见的 SVG 元素上。

恢复了动态活动类的切换的解决方法是将FontAwesome图标包装在span中,并使用v-show指令,如下面的代码片段所示:

<span v-show="sortByFirstNameAsc"><i class="fa fa-caret-up"></i></span>
<span v-show="sortByFirstNameDesc"><i class="fa fa-caret-down"></i></span>

FontAwesome文档现在建议使用他们的Vue组件来避免DOM冲突:

兼容性注意! 如果您正在使用Vue,则需要使用vue-fontawesome包或具有CSS Web字体。

以下情况下,SVG核心包是有用且被推荐的:

  • 将大量图标子集化为您正在使用的图标
  • 作为基本库用于与React、Angular、Vue或Ember等工具的较大集成(实际上我们自己的组件使用这些包)
  • 作为CommonJS/ES6模块打包工具,如Webpack、Rollup或Parcel
  • 作为UMD-style加载器库,如RequireJS
  • 直接在服务器上使用CommonJS (请参阅我们的Server Side Rendering文档

完美!对我有用。使用v-show而不是v-if来更改fontawesome图标。 谢谢。 - Jadson Santos
1
这个解决方案在尝试动态更改图标时无效。这篇其他帖子的选定答案提供了一个可以在更多情况下使用的解决方案。简而言之:将您的图标包装起来并为包装器应用一个键。例如:<span :key="myIconClass" ><i :class="myIconClass"></i></span>。 - Efonzie
@Efonzie 给包含元素添加 :key 对我很有帮助。完美地解决了问题,谢谢你。我的朋友,我一定要请你喝一杯啤酒! - Adam K Dean

14

在将火转换为SVG后,使用一些包装来注释标记<span v-if="marked"><i class="far fa-check-square"></i></span>


2
这在这种情况下没有帮助:https://jsfiddle.net/50wL7mdz/201741/ 我按照上面链接中提到的从js切换到css,问题得到了解决。 - TheOne
谢谢!我一直想不通为什么我的SVG无法从DOM中移除。 - Ettore Raimondi

5

本答案适用于使用SVG的Font Awesome。

由于某些原因,您需要两次包装i标签。例如,不要写成:

<div v-if="condition">
  <i class="fal fa-caret-left"></i>
</div>
<div v-else>
  <i class="fas fa-caret-left"></i>
</div>

请执行以下操作:

<template v-if="condition">
  <div>
    <i class="fal fa-caret-left"></i>
  </div>
</template>
<template v-else>
  <div>
    <i class="fas fa-caret-left"></i>
  </div>
</template>

我不完全确定为什么需要两次包装,因为我认为只包装一次可以足够地解耦标签,但是以这种方式处理对我有效,因此显然还有其他事情在进行中。

另外,请记住,由于明显的原因(模板标签不会被呈现),内部div不能被替换为template


4
您使用的 Font Awesome 库不支持 Vue。它会获取您编写的 <i> 并将其转换为 <svg>,此时已从 Vue 中删除,Vue 不再控制它。Dialog 给出的答案是一个好方法:用 <span> 包装它。但是您指出了另一种无法解决的情况。
为解决由于包装 <span> 仍然无法解决的情况,请使用 key="fa-sort-up"。这将强制 Vue 重新渲染包装器,此时 Font Awesome 将更新图标。以下是您示例的更新 jsFiddle
<span key="fa-sort-up" v-if="sort && descending"><i class="fas fa-sort-up"></i></span>
<span key="fa-sort-down" v-else-if="sort"><i class="fas fa-sort-down"></i></span>
<span key="fa-sort" v-else><i class="fas fa-sort"></i></span>

只要key值是唯一的,你可以使用任何想用的内容。


1

使用FontAwesome在Vue中切换复选框

<style>
  .fa-check-square::before {
    color: green; 
  }
</style>

<script>
  Vue.component('some',
    {
      data: 
        function() {
          return{
            isclick: false
          }
        },
      methods: {
        isClicked: function() {
          this.isclick = !this.isclick;
        }
      },
      template: '<div id="test" v-on:click="isClicked">' +
        '<i v-if="isclick" class="fa fa-check-square" style="font-size: 40px;"></i>' +
        '<i v-if="!isclick" class="far fa-square" style="font-size: 40px;"></i>' +
        '</div>'
    });

</script>

<div id="componentsDemo">
  <some></some>
  <some></some>
  <some></some>
  <some></some>
</div>

<script>
  new Vue({ el: '#componentsDemo' });
</script>

0

我通过为每个图标创建一个模板来解决了这个问题,然后根据布尔值有条件地加载模板。

这是我的主要模板:

 <div v-if="minimised">

                        <maximise-icon>
                            
                        </maximise-icon>

                    </div>

                    <div v-if="!minimised">

                        <minimise-icon>
                        
                        </minimise-icon>
                     </div>

然后就像这样创建图标:

FontAwesomeConfig = { autoReplaceSvg: 'nest' }//important addition!

Vue.component('minimise-icon', {

    template:
    `
        <i class="fas fa-minus "></i>

    `

})


Vue.component('maximise-icon', {

    template:
    `
        <i class="fas fa-plus "></i>

    `

})

如果有更优雅的方式,我全听你的!


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接