VueJS+Bootstrap图标排序问题:图标不显示且需点击图标触发排序
解决点击图标触发排序及图标不显示的问题
问题分析
你碰到的问题主要有两个核心原因:
- Bootstrap 4不再内置Glyphicon图标:你当前使用的是Bootstrap 4,但Glyphicon图标在Bootstrap 4版本中已经被移除,所以
glyphicon类不会渲染出任何可视图标。 - 事件冒泡与对象引用比较异常:点击图标时会触发父元素
<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
相关产品推荐
相关产品推荐

