You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Vue响应式视图中用Font Awesome切换导航栏bars/xmark图标

实现Bootstrap导航栏图标切换(无需v-if/v-show)

针对你的需求,这里提供两种可行方案,均不依赖Vue的v-if/v-show指令,适配你当前的Vue.js + Bootstrap环境:


方案一:CSS原生实现(推荐)

利用Bootstrap折叠组件的原生状态属性,通过CSS控制图标显示隐藏:

1. 修改导航按钮模板

在按钮内同时放置bars和xmark图标,分别添加类名用于区分:

<button
    class="navbar-toggler d-flex d-lg-none flex-column justify-content-around"
    type="button"
    data-bs-toggle="collapse"
    data-bs-target="#navbarSupportedContent"
    aria-controls="navbarSupportedContent"
    aria-expanded="false"
    aria-label="Toggle navigation">
    <!-- 汉堡菜单图标 -->
    <i><fa :icon="['fas', 'bars']" class="icon toggle-alt fa-3x burger-icon burger-bars" /></i>
    <!-- 关闭图标 -->
    <i><fa :icon="['fas', 'xmark']" class="icon toggle-alt fa-3x burger-icon burger-xmark" /></i>
</button>

2. 添加CSS切换规则

Bootstrap会在菜单展开时给按钮添加aria-expanded="true"属性,我们利用这个状态写样式:

/* 默认隐藏关闭图标 */
.burger-xmark {
    display: none;
}

/* 菜单展开时,显示关闭图标、隐藏汉堡图标 */
.navbar-toggler[aria-expanded="true"] .burger-xmark {
    display: block;
}
.navbar-toggler[aria-expanded="true"] .burger-bars {
    display: none;
}

方案二:JavaScript监听折叠事件

通过监听Bootstrap折叠组件的show/hide事件,动态修改图标属性:

1. 给按钮和图标添加ref引用

<button
    ref="togglerBtn"
    class="navbar-toggler d-flex d-lg-none flex-column justify-content-around"
    type="button"
    data-bs-toggle="collapse"
    data-bs-target="#navbarSupportedContent"
    aria-controls="navbarSupportedContent"
    aria-expanded="false"
    aria-label="Toggle navigation">
    <i><fa ref="burgerIcon" :icon="['fas', 'bars']" class="icon toggle-alt fa-3x burger-bars" /></i>
</button>

2. 监听折叠事件并切换图标

在组件的mounted钩子中添加事件监听:

export default {
  name: "Navbar",
  data: () => ({
    windowSize: "mobile",
  }),
  mounted() {
    const collapseEl = document.getElementById('navbarSupportedContent');
    // 菜单展开时切换为xmark图标
    collapseEl.addEventListener('show.bs.collapse', () => {
      this.$refs.burgerIcon.icon = ['fas', 'xmark'];
    });
    // 菜单收起时切换回bars图标
    collapseEl.addEventListener('hide.bs.collapse', () => {
      this.$refs.burgerIcon.icon = ['fas', 'bars'];
    });
    window.addEventListener("resize", this.onResize.bind(this));
  },
  beforeUnmount() {
    // 移除事件监听避免内存泄漏
    const collapseEl = document.getElementById('navbarSupportedContent');
    collapseEl.removeEventListener('show.bs.collapse');
    collapseEl.removeEventListener('hide.bs.collapse');
    window.removeEventListener("resize", this.onResize.bind(this));
  },
  methods: {
    onResize() {
      if (window.innerWidth >= 320) this.windowSize = "mobile";
    },
  },
};

完整修改代码(CSS方案版)

整合上述改动后的完整组件代码:

<template>
    <nav class="navbar navbar-expand-lg navbar-light sticky-top set-nav">
        <div class="container">
            
            <nuxt-link to="/" class="brand">
                <img class="img-fluid desktop logo" height="auto" width="auto" src="~/assets/images/logo.png" alt="Logo"/>
                <img class="img-fluid mobile" height="120" width="120" src="~/assets/images/logo.png" alt=""/>
            </nuxt-link>

            <button
                class="navbar-toggler d-flex d-lg-none flex-column justify-content-around"
                type="button"
                data-bs-toggle="collapse"
                data-bs-target="#navbarSupportedContent"
                aria-controls="navbarSupportedContent"
                aria-expanded="false"
                aria-label="Toggle navigation">
                <i><fa :icon="['fas', 'bars']" class="icon toggle-alt fa-3x burger-icon burger-bars" /></i>
                <i><fa :icon="['fas', 'xmark']" class="icon toggle-alt fa-3x burger-icon burger-xmark" /></i>
            </button>

            <div class="collapse navbar-collapse" id="navbarSupportedContent">
                <ul class="nav ml-auto">
                    <li class="nav-item active">
                        <nuxt-link class="nav-link" :to="{ path: '/', hash: '' }" exact>Home</nuxt-link>
                    </li>
                    <li class="nav-item">
                        <nuxt-link class="nav-link" :to="{ path: '/', hash: '' }" exact>Hire A Bike</nuxt-link>
                    </li>
                    <li class="nav-item">
                        <nuxt-link class="nav-link" :to="{ path: '/', hash: '' }" exact>About</nuxt-link>
                    </li>
                    <li class="nav-item">
                        <nuxt-link class="nav-link" :to="{ path: '/', hash: '' }" exact>Contact</nuxt-link>
                    </li>
                </ul>
            </div>
            </div> 
            <div class="header">
                <div class="container">
                    <ul class="header-links">
                        <li class="header-link terms">
                            <fa :icon="['fas', 'hand-point-up']" class="terms-icon fa-2x" style="color:orange" />
                            <nuxt-link class="header-nuxt terms-link" :to="{ path: '/', hash: '' }" exact>Terms & Conditions</nuxt-link>
                        </li>
                        <li class="header-link phone-number">
                            <fa :icon="['fas', 'phone']" class="phone-icon fa-2x" style="color:orange" />
                            <nuxt-link class="header-nuxt phone-link" :to="{ path: '/', hash: '' }" exact>(+90) 533 505 50 50</nuxt-link>
                        </li>
                    </ul>
                </div>
                </div>
           
    </nav>
</template>

<script>
export default {
  name: "Navbar",
  data: () => ({
    windowSize: "mobile",
  }),
  beforeMount() {
    window.addEventListener("resize", this.onResize.bind(this));
  },
  beforeUnmount() {
    window.removeEventListener("resize", this.onResize.bind(this));
  },
  methods: {
    onResize() {
      if (window.innerWidth >= 320) this.windowSize = "mobile";
    },
  },
};
</script>

<style>
    .set-nav{
        height: 15rem;
        background-color: var(--color-dark-blue);
        margin-bottom:10rem;
    }
    .container{
        width: 80%;
    }
    .logo{
        height: 25rem;
    }
    .nav-link{
         font-size: 2.5rem;
         font-weight: bold;
         margin: 2rem;
         list-style-type: none;
         color: orange !important;
    }
    .nav-link:hover{
        color: white !important;
        transition: 0.3s ease-in-out;
    }
    .header{
        position: absolute;
        top: 100%;
        left: 0;
        right: 0;
        background-color: #3e80c3;
        width: 100%;
    }
    .header-links{
        list-style-type: none;
        margin-left: auto;
        margin-top: 1rem;
    }
    .header-link{
        display: inline-block;
    }
    .header-nuxt{
        font-size: 2.5rem;
        color: orange !important;
        margin: 2rem;
    }
    .terms:hover .terms-icon, .terms:hover .terms-link,
    .phone-number:hover .phone-icon, .phone-number:hover .phone-link{
        color: white !important;
        text-decoration: none;
        transition: 0.3s ease-in-out;
    }
    
    /* 图标切换样式 */
    .burger-xmark {
        display: none;
    }
    .navbar-toggler[aria-expanded="true"] .burger-xmark {
        display: block;
    }
    .navbar-toggler[aria-expanded="true"] .burger-bars {
        display: none;
    }
    
    @media (max-width: 992px) and (min-width: 320px) {
  img.desktop {
    display: none;
  }
  #navbarSupportedContent .nav {
    width: 100%;
  }
  .nav {
    align-items: left;
    flex-direction: column;
    position: relative;
    background-color: var(--color-dark-blue);
    
  }
  .nav-link {
    height: 6rem;
  }
  .nav-item {
    height: auto;
    text-align: center;
  }
  .navbar-toggler {
    width: 4rem;
    align-items: center;
    margin-top: -1rem;
    margin-right: 3rem;
    cursor: pointer;
    border: none;
    background-color: transparent !important;
  }

    }
@media (max-width: 1400px) and (min-width: 992px) {
  img.mobile {
    display: none;
  }
}
@media (max-width: 320px) and (min-width: 0px) {
  img.mobile {
    display: none;
  }
  img.desktop {
    display: none;
  }
}
@media (min-width: 1400px) {
  img.mobile {
    display: none;
  }
}
</style>

内容的提问来源于stack exchange,提问作者Emircan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.26 05:09:56