vuetify3 实现表格整行选中高亮显示效果

Vuetify3实现表格整行选中高亮显示效果

1.效果显示

在这里插入图片描述

2.效果实现

  • 实现原理在于使用插槽,然后插槽中再渲染每一行数据,这样我们就能控制行的显示效果了
  • 点击的时候获取该行的数据匹配使该行高亮显示,同时也能拿到该行的数据方便后续操作。
  • 插槽页面代码
	<template v-slot:item="{ item }">
		<!-- 定义鼠标悬浮、离开、选中的事件  -->
        <tr  @mouseover="handleMouseOver(item)"
        @mouseout="handleMouseOut()"
        @click="handleSelect(item)"
        :class="{ 'hover-row': isItemHovered === item , 'select-row':isItemSelected === item }">
          <td>{{ item.name }} </td>
          <td>{{ item.calories }}</td>
          <td>{{ item.fat }}</td>
          <td>{{ item.carbs }}</td>
          <td>{{ item.protein }}</td>
          <td>
          <!-- 官方代码编辑删除按钮的模板,将原本的顶部插槽移至此处 -->
            <v-icon
              class="me-2"
              size="small"
              @click="editItem(item)"
            >
              mdi-pencil
            </v-icon>
            <v-icon
              size="small"
              @click="deleteItem(item)"
            > 
              mdi-delete
            </v-icon>
          </td>
        </tr>
    </template>
  • js脚本代码
// 选中项
const isItemSelected = ref()
// 是否悬浮
const isItemHovered = ref()

// 悬浮事件
const handleMouseOver = (item) => {
  isItemHovered.value = item
}
// 鼠标离开
const handleMouseOut = () => {
  isItemHovered.value = null
}
// 鼠标点击
const handleSelect = (item) => {
  // 是否选中
  isItemSelected.value = item
  console.log(isItemSelected.value)
}
  • css样式
.hover-row {
  background-color: #E3F2FD; /* 悬停时的背景色 */
}
.select-row {
  background-color: #BBDEFB; /* 选中时的背景色 */
}

案例使用的是官方CRUD操作的模板
完整演示代码如下

<!-- HelloWorld.vue -->
<template>
  <v-data-table
    :headers="headers"
    :items="desserts"
    :sort-by="[{ key: 'calories', order: 'asc' }]"
  >
    <template v-slot:top>
      <v-toolbar
        flat
      >
        <v-toolbar-title>My CRUD</v-toolbar-title>
        <v-divider
          class="mx-4"
          inset
          vertical
        ></v-divider>
        <v-spacer></v-spacer>
        <v-dialog
          v-model="dialog"
          max-width="500px"
        >
          <template v-slot:activator="{ props }">
            <v-btn
              class="mb-2"
              color="primary"
              dark
              v-bind="props"
            >
              New Item
            </v-btn>
          </template>
          <v-card>
            <v-card-title>
              <span class="text-h5">{{ formTitle }}</span>
            </v-card-title>

            <v-card-text>
              <v-container>
                <v-row>
                  <v-col
                    cols="12"
                    md="4"
                    sm="6"
                  >
                    <v-text-field
                      v-model="editedItem.name"
                      label="Dessert name"
                    ></v-text-field>
                  </v-col>
                  <v-col
                    cols="12"
                    md="4"
                    sm="6"
                  >
                    <v-text-field
                      v-model="editedItem.calories"
                      label="Calories"
                    ></v-text-field>
                  </v-col>
                  <v-col
                    cols="12"
                    md="4"
                    sm="6"
                  >
                    <v-text-field
                      v-model="editedItem.fat"
                      label="Fat (g)"
                    ></v-text-field>
                  </v-col>
                  <v-col
                    cols="12"
                    md="4"
                    sm="6"
                  >
                    <v-text-field
                      v-model="editedItem.carbs"
                      label="Carbs (g)"
                    ></v-text-field>
                  </v-col>
                  <v-col
                    cols="12"
                    md="4"
                    sm="6"
                  >
                    <v-text-field
                      v-model="editedItem.protein"
                      label="Protein (g)"
                    ></v-text-field>
                  </v-col>
                </v-row>
              </v-container>
            </v-card-text>

            <v-card-actions>
              <v-spacer></v-spacer>
              <v-btn
                color="blue-darken-1"
                variant="text"
                @click="close"
              >
                Cancel
              </v-btn>
              <v-btn
                color="blue-darken-1"
                variant="text"
                @click="save"
              >
                Save
              </v-btn>
            </v-card-actions>
          </v-card>
        </v-dialog>
        <v-dialog v-model="dialogDelete" max-width="500px">
          <v-card>
            <v-card-title class="text-h5">Are you sure you want to delete this item?</v-card-title>
            <v-card-actions>
              <v-spacer></v-spacer>
              <v-btn color="blue-darken-1" variant="text" @click="closeDelete">Cancel</v-btn>
              <v-btn color="blue-darken-1" variant="text" @click="deleteItemConfirm">OK</v-btn>
              <v-spacer></v-spacer>
            </v-card-actions>
          </v-card>
        </v-dialog>
      </v-toolbar>
    </template>
    
    <template v-slot:no-data>
      <v-btn
        color="primary"
        @click="initialize"
      >
        Reset
      </v-btn>
    </template>
    <template v-slot:item="{ item }">
        <tr  @mouseover="handleMouseOver(item)"
        @mouseout="handleMouseOut()"
        @click="handleSelect(item)"
        :class="{ 'hover-row': isItemHovered === item , 'select-row':isItemSelected === item }">
          <td>{{ item.name }} </td>
          <td>{{ item.calories }}</td>
          <td>{{ item.fat }}</td>
          <td>{{ item.carbs }}</td>
          <td>{{ item.protein }}</td>
          <!--  -->
          <td>
            <v-icon
              class="me-2"
              size="small"
              @click="editItem(item)"
            >
              mdi-pencil
            </v-icon>
            <v-icon
              size="small"
              @click="deleteItem(item)"
            > 
              mdi-delete
            </v-icon>
          </td>
        </tr>
    </template>
  </v-data-table>
</template>

<script setup>
  import { computed, nextTick, ref, watch } from 'vue'

  const dialog = ref(false)
  const dialogDelete = ref(false)
  const headers = ref([
    {
      title: 'Dessert (100g serving)',
      align: 'start',
      sortable: false,
      key: 'name',
    },
    { title: 'Calories', key: 'calories' },
    { title: 'Fat (g)', key: 'fat' },
    { title: 'Carbs (g)', key: 'carbs' },
    { title: 'Protein (g)', key: 'protein' },
    { title: 'Actions', key: 'actions', sortable: false },
  ])
  const desserts = ref([])
  const editedIndex = ref(-1)
  const editedItem = ref({
    name: '',
    calories: 0,
    fat: 0,
    carbs: 0,
    protein: 0,
  })
  const defaultItem = ref({
    name: '',
    calories: 0,
    fat: 0,
    carbs: 0,
    protein: 0,
  })
  const formTitle = computed(() => {
    return editedIndex.value === -1 ? 'New Item' : 'Edit Item'
  })
  function initialize () {
    desserts.value = [
      {
        name: 'Frozen Yogurt',
        calories: 159,
        fat: 6,
        carbs: 24,
        protein: 4,
      },
      {
        name: 'Ice cream sandwich',
        calories: 237,
        fat: 9,
        carbs: 37,
        protein: 4.3,
      },
      {
        name: 'Eclair',
        calories: 262,
        fat: 16,
        carbs: 23,
        protein: 6,
      },
      {
        name: 'Cupcake',
        calories: 305,
        fat: 3.7,
        carbs: 67,
        protein: 4.3,
      },
      {
        name: 'Gingerbread',
        calories: 356,
        fat: 16,
        carbs: 49,
        protein: 3.9,
      },
      {
        name: 'Jelly bean',
        calories: 375,
        fat: 0,
        carbs: 94,
        protein: 0,
      },
      {
        name: 'Lollipop',
        calories: 392,
        fat: 0.2,
        carbs: 98,
        protein: 0,
      },
      {
        name: 'Honeycomb',
        calories: 408,
        fat: 3.2,
        carbs: 87,
        protein: 6.5,
      },
      {
        name: 'Donut',
        calories: 452,
        fat: 25,
        carbs: 51,
        protein: 4.9,
      },
      {
        name: 'KitKat',
        calories: 518,
        fat: 26,
        carbs: 65,
        protein: 7,
      },
    ]
  }
  function editItem (item) {
    editedIndex.value = desserts.value.indexOf(item)
    editedItem.value = Object.assign({}, item)
    dialog.value = true
  }
  function deleteItem (item) {
    editedIndex.value = desserts.value.indexOf(item)
    editedItem.value = Object.assign({}, item)
    dialogDelete.value = true
  }
  function deleteItemConfirm () {
    desserts.value.splice(editedIndex.value, 1)
    closeDelete()
  }
  function close () {
    dialog.value = false
    nextTick(() => {
      editedItem.value = Object.assign({}, defaultItem.value)
      editedIndex.value = -1
    })
  }
  function closeDelete () {
    dialogDelete.value = false
    nextTick(() => {
      editedItem.value = Object.assign({}, defaultItem.value)
      editedIndex.value = -1
    })
  }
  function save () {
    if (editedIndex.value > -1) {
      Object.assign(desserts.value[editedIndex.value], editedItem.value)
    } else {
      desserts.value.push(editedItem.value)
    }
    close()
  }
  watch(dialog, val => {
    val || close()
  })
  watch(dialogDelete, val => {
    val || closeDelete()
  })
  initialize()

// 选中项
const isItemSelected = ref()
// 是否悬浮
const isItemHovered = ref()

// 悬浮事件
const handleMouseOver = (item) => {
  isItemHovered.value = item
}
// 鼠标离开
const handleMouseOut = () => {
  isItemHovered.value = null
}
// 鼠标点击
const handleSelect = (item) => {
  // 是否选中
  isItemSelected.value = item
  console.log(isItemSelected.value)
}
</script>

<style>
.hover-row {
  background-color: #E3F2FD; /* 悬停时的背景色 */
}
.select-row {
  background-color: #BBDEFB; /* 选中时的背景色 */
}
</style>

  • 27
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值