<template><div><h1>带筛选和命令功能的表格</h1><!-- 筛选器部分 --><div class="filters"><input v-model="filters.name" placeholder="输入姓名筛选" /><select v-model="filters.age"><option value="">所有年龄</option><option v-for="age in uniqueAges" :key="age" :value="age">{{ age }}</option></select><input v-model="filters.city" placeholder="输入城市筛选" /><button @click="resetFilters">重置筛选</button></div><!-- 全局命令部分 --><div class="commands"><button @click="addRow">新增一行</button><button @click="deleteSelectedRows" :disabled="!selectedRows.length">删除选中行</button><button @click="deleteAllRows" :disabled="!data.length">删除所有数据</button></div><!-- 表格部分 --><table border="1"><thead><tr><th><input type="checkbox" @change="toggleSelectAll" :checked="isAllSelected" /></th><th @click="sortBy('name')">姓名</th><th @click="sortBy('age')">年龄</th><th @click="sortBy('city')">城市</th><th>操作</th></tr></thead><tbody><tr v-for="(item, index) in sortedFilteredData" :key="index"><!-- 多选列 --><td><inputtype="checkbox":value="index"v-model="selectedRows"/></td><!-- 姓名 --><td><div v-if="isEditing(index, 'name')"><input v-model="editCache.name" /><button @click="saveEdit(index, 'name')">保存</button><button @click="cancelEdit()">取消</button></div><div v-else>{{ item.name }}<button @click="startEdit(index, 'name', item.name)">编辑</button></div></td><!-- 年龄 --><td><div v-if="isEditing(index, 'age')"><input type="number" v-model="editCache.age" /><button @click="saveEdit(index, 'age')">保存</button><button @click="cancelEdit()">取消</button></div><div v-else>{{ item.age }}<button @click="startEdit(index, 'age', item.age)">编辑</button></div></td><!-- 城市 --><td><div v-if="isEditing(index, 'city')"><input v-model="editCache.city" /><button @click="saveEdit(index, 'city')">保存</button><button @click="cancelEdit()">取消</button></div><div v-else>{{ item.city }}<button @click="startEdit(index, 'city', item.city)">编辑</button></div></td><!-- 删除 --><td><button @click="deleteRow(index)">删除</button></td></tr></tbody></table></div>
</template><script>
export default {data() {return {data: [{ name: "张三", age: 25, city: "北京" },{ name: "李四", age: 30, city: "上海" },{ name: "王五", age: 25, city: "广州" },{ name: "赵六", age: 35, city: "深圳" },],filters: {name: "", age: "", city: "", },sortKey: "", sortOrder: 1, editing: {index: null, field: null, },editCache: {name: "",age: "",city: "",},selectedRows: [],};},computed: {uniqueAges() {return [...new Set(this.data.map((item) => item.age))];},filteredData() {return this.data.filter((item) => {const matchesName = item.name.includes(this.filters.name);const matchesAge = !this.filters.age || item.age === Number(this.filters.age);const matchesCity = item.city.includes(this.filters.city);return matchesName && matchesAge && matchesCity;});},sortedFilteredData() {return [...this.filteredData].sort((a, b) => {if (!this.sortKey) return 0;let valueA = a[this.sortKey];let valueB = b[this.sortKey];if (typeof valueA === "string") valueA = valueA.localeCompare(valueB);return (valueA > valueB ? 1 : -1) * this.sortOrder;});},isAllSelected() {return this.selectedRows.length === this.data.length && this.data.length > 0;},},methods: {resetFilters() {this.filters = { name: "", age: "", city: "" };},sortBy(key) {if (this.sortKey === key) {this.sortOrder *= -1; } else {this.sortKey = key;this.sortOrder = 1; }},startEdit(index, field, value) {this.editing = { index, field };this.editCache[field] = value;},isEditing(index, field) {return this.editing.index === index && this.editing.field === field;},saveEdit(index, field) {this.data[index][field] = this.editCache[field];this.cancelEdit();},cancelEdit() {this.editing = { index: null, field: null };this.editCache = { name: "", age: "", city: "" };},deleteRow(index) {this.data.splice(index, 1);},deleteSelectedRows() {this.data = this.data.filter((_, index) => !this.selectedRows.includes(index));this.selectedRows = [];},deleteAllRows() {this.data = [];},addRow() {this.data.push({ name: "", age: null, city: "" });},toggleSelectAll(event) {if (event.target.checked) {this.selectedRows = this.data.map((_, index) => index);} else {this.selectedRows = [];}},},
};
</script><style>
body {background-color: #f0f0f0; margin: 0;font-family: Arial, sans-serif;
}
.filters,
.commands {margin-bottom: 1rem;
}
.filters input,
.filters select,
.commands button {margin-right: 0.5rem;padding: 0.5rem;
}
table {width: 100%;border-collapse: collapse;background: white;
}
th {cursor: pointer;background: #e6e6e6; padding: 0.5rem;
}
th:hover {background: #d4d4d4;
}
td {padding: 0.5rem;text-align: center;
}
tr:nth-child(even) {background: #f9f9f9;
}
</style>
