在这里插入图片描述

<template>  
    <div style="background-color: white; overflow-x: auto;width: 100%;" >
        <!-- 搜索区域 -->
        <div class="search-controls">
          <el-input
              v-model="searchText"
              placeholder="Search..."
              class="search-input"
              @keyup.enter="handleSearch"
              clearable
              @clear="clearSearch"
              >
              <template #append>
                <el-button-group>
                <el-button @click="prevMatch" :disabled="!hasMatches" title="上一个匹配项">
                    <el-icon><ArrowUp /></el-icon>
                </el-button>
                <el-button @click="nextMatch" :disabled="!hasMatches" title="下一个匹配项">
                  <el-icon><ArrowDown /></el-icon>
                </el-button>
              </el-button-group>
          </template>         
          </el-input>     
            <div class="match-count" v-if="hasMatches">
                {{ currentMatchIndex + 1 }}/{{ matches.length }}
            </div>
          </div>
             
            
          <div style="padding:10px 10px 10px 0px ;display: flex; ">
            
            <el-table :data="tableData" ref="tableRef" style="width:100%;height: calc(100vh - 150px);"  highlight-current-row @current-change="handleCurrentChange" :row-class-name="tableRowClassName" row-key="id">
              <el-table-column prop="id" label="ID" width="80" />
              <el-table-column prop="name" label="名称" width="180" />
              <el-table-column prop="description" label="描述" />
              <el-table-column prop="status" label="状态" width="120">
                <template #default="{ row }">
                  <el-switch v-model="row.status"  />
                </template>
              </el-table-column>
              <el-table-column prop="date" label="日期" width="180" />
            </el-table>

          </div>

      </div>    
    </template>

<script lang="ts" setup>

    import { ElInput, ElButton, ElTable, ElTableColumn } from 'element-plus';
    import { ArrowUp, ArrowDown } from '@element-plus/icons-vue'
    import { ref, computed, onMounted,onBeforeMount, getCurrentInstance } from 'vue'
    import { ElMessage, ElMessageBox} from 'element-plus'
    const activeName = ref()  //当前Tab选中的专案名,默认显示第一个专案

    const tableRef:any=ref()
    //------------------------------------- 模拟表格数据-----------------------
    const generateData = () => {
      const data = []
      const statuses = [true, false]
      const names = ['项目', '任务', '用户', '订单', '产品']
      const descriptions = [
        '这是一个重要的项目',
        '需要尽快完成的任务',
        '系统用户管理',
        '客户订单处理',
        '产品库存管理'
      ]
    
      for (let i = 1; i <= 100; i++) {
        data.push({
          id: i,
          name: `${names[i % names.length]} ${i}`,
          description: `${descriptions[i % descriptions.length]} (${i})`,
          status: statuses[i % statuses.length],
          date: new Date(2023, (i % 12), (i % 28) + 1).toLocaleDateString()
        })
      }
      return data
    }
 
    // 表格数据
    const tableData = ref(generateData())
    // 表格数据没带id可以自己手动添加id,用于数据定位以及row-key
    //tableData.value = tableData.value.map((item:any, index:any) => ({
    //  ...item,          // 保留原有属性
    //  id: index + 1,    // 添加 id(从 1 开始)
    //}));
//-------------------------------------------------------------

  // 为表格行添加类名,找到符合条件的行就给这行赋一个类名,通过css样式修改当前行的颜色
const tableRowClassName = ({ row }: { row: any }) => {
  return matchedRowIds.value.has(row.id) ? 'highlight-row' : '';
};


// 搜索相关状态
const searchText = ref('')  // 搜索框输入的值
const currentMatchIndex = ref(-1)  // 当前匹配到搜索结果的第几个值
const matches:any = ref([])
const matchedRowIds = ref(new Set()); // 存储所有匹配行的ID
 
// 计算属性
const hasMatches = computed(() => matches.value.length > 0)
 
// 搜索方法
const handleSearch = () => {
  if (!searchText.value.trim()) {
    clearSearch()
    return
  }
 
  const searchLower = searchText.value.toLowerCase()
  matches.value = tableData.value.map((row:any, index:any) => ({ row, index })).filter(( { row }: { row: any } ) =>
      Object.entries(row).some(([key, value]) => {
        if (key === 'id' || typeof value === 'object') return false
        return String(value).toLowerCase().includes(searchLower)
      })
    )
 

  // 更新匹配行的ID集合
  matchedRowIds.value = new Set(matches.value.map((m:any) => m.row.id));
  console.log('匹配行的ID集合', matchedRowIds.value)
  
  if (matches.value.length > 0) {
    currentMatchIndex.value = 0;
    scrollToMatch();
  } else {
    currentMatchIndex.value = -1;
  }
}
 
// 清除搜索
const clearSearch = () => {
  searchText.value = ''
  matches.value = []
  currentMatchIndex.value = -1
  matchedRowIds.value.clear();
  tableRef.value?.setCurrentRow()
}
 
// // 滚动到匹配项
const scrollToMatch = () => {
  if (!hasMatches.value || !tableRef.value) return;

  const match = matches.value[currentMatchIndex.value];

  const tableEl = tableRef.value.$el.querySelector('.el-table__body-wrapper');
  const rowEl = tableEl.querySelector(`.el-table__row:nth-child(${match.index + 1})`);

  if (rowEl) {
    // 优先使用 scrollIntoView(更精准)
    rowEl.scrollIntoView({ behavior: 'smooth', block: 'center' });
  } else {
    // 回退到 scrollTop(兼容方案)
    const rowHeight = tableEl.querySelector('.el-table__row')?.clientHeight || 40;
    tableEl.scrollTo({ top: match.index * rowHeight, behavior: 'smooth' });
  }

  tableRef.value.setCurrentRow(match.row);  // 将当前行执行选中操作,需要el-table带highlight-current-row才能实现
};
 
// 下一个匹配项
const nextMatch = () => {
  if (!hasMatches.value) return
 
  currentMatchIndex.value = (currentMatchIndex.value + 1) % matches.value.length
  scrollToMatch()
}
 
// 上一个匹配项
const prevMatch = () => {
  if (!hasMatches.value) return
 
  currentMatchIndex.value = (currentMatchIndex.value - 1 + matches.value.length) % matches.value.length
  scrollToMatch()
}
 
// 当前行变化处理
const handleCurrentChange = (currentRow:any) => {
  if (!currentRow || !hasMatches.value) return

  const matchIndex = matches.value.findIndex((m:any) => m.row.id === currentRow.id);
  if (matchIndex !== -1) {
    currentMatchIndex.value = matchIndex;
  }

}


</script>

<style>  //删除scope实现所有找到的行都高亮显示
  .table-search-container {
  padding: 20px;
  height: 100%;
    display: flex;
    flex-direction: column;
}
 
.search-controls {
    display: flex;
    align-items: center;
    margin-top: 10px;
    margin-bottom: 10px;
  gap: 10px;
  width:400px;
}
 
.search-input {
  flex: 1;
}
 
.match-count {
  min-width: 60px;
    text-align: center;
    color: var(--el-color-primary);
  font-weight: bold;
}
 
.el-table {
  flex: 1;
  margin-top: 10px;
  }



/* 实现所有找到的行都高亮显示,若不想直接删除scope可以在这三个格式前添加:deep() */
.highlight-row {
  background-color: var(--el-color-primary-light-9) !important;
}
.highlight-row:hover > td {
  background-color: var(--el-color-primary-light-8) !important;
}
.el-table .current-row.highlight-row > td {
  background-color: var(--el-color-primary-light-7) !important;
}


</style>
Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐