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

VueJS+Bootstrap图标排序问题:图标不显示且需点击图标触发排序

解决点击图标触发排序及图标不显示的问题

问题分析

你碰到的问题主要有两个核心原因:

  1. Bootstrap 4不再内置Glyphicon图标:你当前使用的是Bootstrap 4,但Glyphicon图标在Bootstrap 4版本中已经被移除,所以glyphicon类不会渲染出任何可视图标。
  2. 事件冒泡与对象引用比较异常:点击图标时会触发父元素<th>的点击事件,导致activeColumn被意外切换;同时初始activeColumn是空对象,直接和toolAttribute做引用比较会出现逻辑判断偏差。

解决方案

1. 替换图标库(使用Font Awesome)

Bootstrap官方推荐用Font Awesome替代Glyphicon,我们引入这个图标库来解决图标不显示的问题。

2. 阻止事件冒泡

在图标点击事件上添加.stop修饰符,确保点击图标时只会触发排序逻辑,不会触发表头的点击事件。

3. 修正活跃列判断逻辑

由于对象是引用类型,直接用toolAttribute == activeColumn判断不准确,我们封装方法通过数组索引来判断当前列是否为活跃列(如果后续能给每个toolAttribute添加唯一ID会更严谨)。

修正后的完整代码

<!-- 引入Font Awesome图标库 -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">

<style>
.falseclass{
  background:red;
  color:white;
}
th.active {
  background-color: #f8f9fa;
}
</style>

<div id="app">
  <table class="table table-bordered">
    <tr>
      <th rowspan="2" @click="sort(['deviceName'])">Device Info</th>
    </tr>
    <tr>
      <th v-for="(toolAttribute, index) in results.toolAttribute" 
          :key="index" 
          @click="activeColumn = toolAttribute" 
          :class="{active: isActiveColumn(toolAttribute, index)}">
        {{toolAttribute.attributeName}}
        <!-- 排序方向图标 -->
        <span @click.stop="sort(['info', index, 'value']); toolAttribute.order = toolAttribute.order * (-1)" 
              class="ml-2"
              v-show="isActiveColumn(toolAttribute, index)">
          <i v-if="toolAttribute.order > 0" class="fa-solid fa-chevron-down"></i>
          <i v-else class="fa-solid fa-chevron-up"></i>
        </span>
        <!-- 默认排序图标 -->
        <span class="ml-2" v-show="!isActiveColumn(toolAttribute, index)">
          <i class="fa-solid fa-sort"></i>
        </span>
      </th>
    </tr>
    <tr v-for="(device, index) in sortedResults" >
      <td :class="{'falseclass' : flasecond(index)}">{{ device.deviceName }}</td>
      <td v-for="info in device.info" :class="{'falseclass' : !info.value}">{{info.value}}</td>
    </tr>
  </table>
</div>

<script>
new Vue({
  el: '#app',
  data: {
    results: {
      toolAttribute: [{attributeName: "Present", order: 1},{attributeName: "Present", order: 1},{attributeName: "Present", order: 1}],
      device: [
        {deviceName: "Device Name 1", info: [{value: true}, {value: false}, {value: true}]},
        {deviceName: "Device Name 2", info: [{value: false}, {value: false}, {value: false}]},
        {deviceName: "Device Name 3", info: [{value: true}, {value: true}, {value: true}]},
        {deviceName: "Device Name 4", info: [{value: false}, {value: true}, {value: false}]},
        {deviceName: "Device Name 5", info: [{value: true}, {value: true}, {value: true}]}
      ]
    },
    activeColumn: null,
    currentSort:['deviceName'],
    currentSortDir:'asc'
  },
  computed:{
    sortedResults:function() {
      return this.results.device.sort(function(a,b){
        let modifier = 1;
        if(this.currentSortDir === 'desc') modifier = -1;
        let aVal = a;
        let bVal = b;
        this.currentSort.forEach(x => {
          aVal = aVal[x];
          bVal = bVal[x];
        })
        if(aVal < bVal) return -1 * modifier;
        if(aVal > bVal) return 1 * modifier;
        return 0;
      }.bind(this));
    }
  },
  methods:{
    flasecond(index){
      let res = false
      this.results.device[index].info.forEach(info=> {
        if(!info.value) res = true
      })
      return res
    },
    sort:function(s) {
      if(s.join('') === this.currentSort.join('')) {
        this.currentSortDir = this.currentSortDir==='asc'?'desc':'asc';
      }
      this.currentSort = s;
    },
    isActiveColumn(toolAttr, index) {
      if (!this.activeColumn) return false;
      // 通过索引判断当前列是否为活跃列(因为三个toolAttribute内容完全一致,引用不同)
      const activeIndex = this.results.toolAttribute.findIndex(item => item === this.activeColumn);
      return activeIndex === index;
    }
  }
})
</script>

关键修改点说明

  • 图标替换:用Font Awesome图标替代废弃的Glyphicon,确保图标正常显示。
  • 事件冒泡阻止:给图标点击事件添加.stop修饰符,避免触发表头的点击逻辑。
  • 活跃列判断:封装isActiveColumn方法,通过数组索引解决对象引用比较的逻辑偏差问题。
  • 初始状态优化:将activeColumn初始设为null,确保默认排序图标在初始状态下正常显示。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.12 05:06:31