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

news/2024/7/9 23:35:30 标签: vue, 前端, vue.js

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>


http://www.niftyadmin.cn/n/5465556.html

相关文章

复习Spring-Spring核心概念

Spring核心概念 在Spring核心概念这部分内容中主要包含IOC/DI、IOC容器和Bean,那么问题就来了&#xff0c;这些都是什么呢? 目前项目中的问题 要想解答这个问题&#xff0c;就需要先分析下目前咱们代码在编写过程中遇到的问题: (1)业务层需要调用数据层的方法&#xff0c;就…

vue3从精通到入门7:ref系列

Vue 3 的 Ref 是一个集合&#xff0c;包括多个与响应式引用相关的功能&#xff0c;这些功能共同构成了 Vue 3 响应式系统的重要组成部分。以下是更全面的介绍&#xff1a; 1.ref ref 接受一个内部值并返回一个响应式且可变的 ref 对象。这个对象具有一个 .value 属性&#xf…

vue项目双击from表单限制重复提交 添加全局注册自定义函数

第一步: 找到utils文件夹添加directive.js文件 import Vue from vue //全局防抖函数 // 在vue上挂载一个指量 preventReClick const preventReClick Vue.directive(preventReClick, {inserted: function (el, binding) {console.log(el.disabled)el.addEventListener(click,…

分享一个宝藏课程:近屿AIGC工程师和产品经理训练营

说起AIGC&#xff0c;大家都会自然地想到近两年火的一塌糊涂的ChatGPT,而开发出它的OpenAI&#xff0c;去年年底的年化收入已突破16亿美元&#xff0c;部分OpenAI的管理层认为&#xff0c;按目前进度&#xff0c;到2024年底&#xff0c;OpenAI的年化收入至少能达到50亿美元。而…

HTTPS跟HTTP有区别吗?

HTTPS和HTTP的区别&#xff0c;白话一点说就是&#xff1a; 1. 安全程度&#xff1a; - HTTP&#xff1a;就像是你和朋友面对面聊天&#xff0c;说的话大家都能听见&#xff08;信息明文传输&#xff0c;容易被偷听&#xff09;。 - HTTPS&#xff1a;就像是你们俩戴着加密耳机…

HTML常用文本标签以及注释文本

目录 前言: 1.标题标签&#xff1a; 前言&#xff1a; 实践&#xff1a; 总结&#xff1a; 2.段落标签&#xff1a; 前言&#xff1a; 段落中的空格&#xff1a; 总结: 3.文本格式化标签&#xff1a; 前言: 和标签的区别: 和标记之间的区别: 总结&#xff1a; 4.如…

工艺品wordpress外贸主题

工艺品wordpress外贸主题 简约大气的wordpress外贸主题&#xff0c;适合做工艺品进出品外贸的公司官网使用。 https://www.jianzhanpress.com/?p5377

【好书推荐4】图机器学习

【好书推荐4】图机器学习 写在最前面编辑推荐内容简介作者简介目录前言/序言本书读者内容介绍 &#x1f308;你好呀&#xff01;我是 是Yu欸 &#x1f30c; 2024每日百字篆刻时光&#xff0c;感谢你的陪伴与支持 ~ &#x1f680; 欢迎一起踏上探险之旅&#xff0c;挖掘无限可能…