|
|
@@ -1,289 +0,0 @@
|
|
|
-<template>
|
|
|
- <div class="pet-box">
|
|
|
- <h2>萌宠乐园 🐱🐶</h2>
|
|
|
-
|
|
|
- <!-- 筛选区域 -->
|
|
|
- <div class="search-bar">
|
|
|
- <input
|
|
|
- v-model="keyword"
|
|
|
- placeholder="搜索宠物名称"
|
|
|
- class="search-input"
|
|
|
- />
|
|
|
- <span>颜值分值:</span>
|
|
|
- <input
|
|
|
- v-model.number="minLevel"
|
|
|
- type="number"
|
|
|
- placeholder="最低分"
|
|
|
- class="num-input"
|
|
|
- />
|
|
|
- -
|
|
|
- <input
|
|
|
- v-model.number="maxLevel"
|
|
|
- type="number"
|
|
|
- placeholder="最高分"
|
|
|
- class="num-input"
|
|
|
- />
|
|
|
- <button @click="resetFilter" class="btn reset-btn">重置筛选</button>
|
|
|
- </div>
|
|
|
-
|
|
|
- <!-- 功能按钮 -->
|
|
|
- <div class="btn-group">
|
|
|
- <label class="check-label">
|
|
|
- <input type="checkbox" v-model="isAllCheck" /> 全选萌宠
|
|
|
- </label>
|
|
|
- <button @click="reverseCheck" class="btn">反选</button>
|
|
|
- <button @click="clearCheck" class="btn">清空选中</button>
|
|
|
- <button @click="sortAsc" class="btn">分值升序</button>
|
|
|
- <button @click="sortDesc" class="btn">分值降序</button>
|
|
|
- </div>
|
|
|
-
|
|
|
- <!-- 萌宠列表 + 动画卡片 -->
|
|
|
- <div class="pet-list">
|
|
|
- <!-- 过渡动画:列表切换自动生效 -->
|
|
|
- <transition-group name="pet" tag="div" class="list-wrap">
|
|
|
- <div
|
|
|
- class="pet-card"
|
|
|
- :class="{ active: pet.checked }"
|
|
|
- v-for="pet in filterList"
|
|
|
- :key="pet.id"
|
|
|
- >
|
|
|
- <input type="checkbox" v-model="pet.checked" class="card-check" />
|
|
|
- <div class="pet-avatar">{{ pet.emoji }}</div>
|
|
|
- <div class="pet-name">{{ pet.name }}</div>
|
|
|
- <div class="pet-type">品类:{{ pet.type }}</div>
|
|
|
- <div class="pet-level">颜值:{{ pet.level }} 分</div>
|
|
|
- </div>
|
|
|
- </transition-group>
|
|
|
- </div>
|
|
|
-
|
|
|
- <!-- 数据统计 -->
|
|
|
- <div class="stat">
|
|
|
- <p>当前萌宠总数:{{ totalNum }}</p>
|
|
|
- <p>已挑选萌宠:{{ checkedNum }} 只</p>
|
|
|
- <p>选中萌宠平均颜值:{{ avgLevel.toFixed(1) }} 分</p>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
-</template>
|
|
|
-
|
|
|
-<script lang="ts" setup>
|
|
|
-import { ref, computed } from 'vue'
|
|
|
-
|
|
|
-// 响应式数据
|
|
|
-const keyword = ref('')
|
|
|
-const minLevel = ref(0)
|
|
|
-const maxLevel = ref(100)
|
|
|
-
|
|
|
-// 萌宠数据源,搭配表情更有趣
|
|
|
-const petList = ref([
|
|
|
- { id: 1, name: '橘猫', type: '猫咪', level: 92, emoji: '🐱', checked: false },
|
|
|
- { id: 2, name: '柴犬', type: '狗狗', level: 88, emoji: '🐶', checked: false },
|
|
|
- { id: 3, name: '小白兔', type: '萌宠', level: 95, emoji: '🐰', checked: false },
|
|
|
- { id: 4, name: '小仓鼠', type: '萌宠', level: 80, emoji: '🐹', checked: false },
|
|
|
- { id: 5, name: '布偶猫', type: '猫咪', level: 98, emoji: '😺', checked: false },
|
|
|
- { id: 6, name: '柯基', type: '狗狗', level: 85, emoji: '🐕', checked: false },
|
|
|
-])
|
|
|
-
|
|
|
-// 1. 综合筛选:名称 + 颜值区间
|
|
|
-const filterList = computed(() => {
|
|
|
- return petList.value.filter(pet => {
|
|
|
- const nameMatch = pet.name.includes(keyword.value)
|
|
|
- const levelMatch = pet.level >= minLevel.value && pet.level <= maxLevel.value
|
|
|
- return nameMatch && levelMatch
|
|
|
- })
|
|
|
-})
|
|
|
-
|
|
|
-// 2. 筛选后总数
|
|
|
-const totalNum = computed(() => filterList.value.length)
|
|
|
-
|
|
|
-// 3. 已选中数量
|
|
|
-const checkedNum = computed(() => filterList.value.filter(pet => pet.checked).length)
|
|
|
-
|
|
|
-// 4. 选中平均颜值
|
|
|
-const avgLevel = computed(() => {
|
|
|
- const checkedArr = filterList.value.filter(pet => pet.checked)
|
|
|
- if (checkedArr.length === 0) return 0
|
|
|
- const total = checkedArr.reduce((sum, pet) => sum + pet.level, 0)
|
|
|
- return total / checkedArr.length
|
|
|
-})
|
|
|
-
|
|
|
-// 5. 可写计算属性 - 全选
|
|
|
-const isAllCheck = computed({
|
|
|
- get() {
|
|
|
- return filterList.value.length > 0 && filterList.value.every(pet => pet.checked)
|
|
|
- },
|
|
|
- set(val: boolean) {
|
|
|
- filterList.value.forEach(pet => pet.checked = val)
|
|
|
- }
|
|
|
-})
|
|
|
-
|
|
|
-// 重置筛选
|
|
|
-const resetFilter = () => {
|
|
|
- keyword.value = ''
|
|
|
- minLevel.value = 0
|
|
|
- maxLevel.value = 100
|
|
|
-}
|
|
|
-
|
|
|
-// 反选
|
|
|
-const reverseCheck = () => {
|
|
|
- filterList.value.forEach(pet => pet.checked = !pet.checked)
|
|
|
-}
|
|
|
-
|
|
|
-// 清空选中
|
|
|
-const clearCheck = () => {
|
|
|
- filterList.value.forEach(pet => pet.checked = false)
|
|
|
-}
|
|
|
-
|
|
|
-// 分值升序
|
|
|
-const sortAsc = () => {
|
|
|
- petList.value.sort((a, b) => a.level - b.level)
|
|
|
-}
|
|
|
-
|
|
|
-// 分值降序
|
|
|
-const sortDesc = () => {
|
|
|
- petList.value.sort((a, b) => b.level - a.level)
|
|
|
-}
|
|
|
-</script>
|
|
|
-
|
|
|
-<style scoped>
|
|
|
-.pet-box {
|
|
|
- width: 90%;
|
|
|
- margin: 20px auto;
|
|
|
- font-family: "Microsoft Yahei", sans-serif;
|
|
|
-}
|
|
|
-h2 {
|
|
|
- text-align: center;
|
|
|
- color: #ff7875;
|
|
|
-}
|
|
|
-
|
|
|
-/* 筛选栏样式 */
|
|
|
-.search-bar {
|
|
|
- text-align: center;
|
|
|
- margin: 15px 0;
|
|
|
-}
|
|
|
-.search-input, .num-input {
|
|
|
- padding: 6px 8px;
|
|
|
- margin: 0 6px;
|
|
|
- border: 1px solid #ccc;
|
|
|
- border-radius: 6px;
|
|
|
- outline: none;
|
|
|
- transition: all 0.3s;
|
|
|
-}
|
|
|
-.search-input:focus, .num-input:focus {
|
|
|
- border-color: #ff9494;
|
|
|
- box-shadow: 0 0 4px #ffc8c8;
|
|
|
-}
|
|
|
-
|
|
|
-/* 按钮通用样式 + 动效 */
|
|
|
-.btn-group {
|
|
|
- text-align: center;
|
|
|
- margin: 10px 0;
|
|
|
-}
|
|
|
-.check-label {
|
|
|
- margin-right: 10px;
|
|
|
- cursor: pointer;
|
|
|
-}
|
|
|
-.btn {
|
|
|
- padding: 6px 12px;
|
|
|
- margin: 0 4px;
|
|
|
- border: none;
|
|
|
- border-radius: 6px;
|
|
|
- background: #ff9494;
|
|
|
- color: #fff;
|
|
|
- cursor: pointer;
|
|
|
- transition: all 0.2s ease;
|
|
|
-}
|
|
|
-.btn:hover {
|
|
|
- background: #ff7875;
|
|
|
- transform: translateY(-2px);
|
|
|
- box-shadow: 0 3px 6px rgba(255, 120, 117, 0.4);
|
|
|
-}
|
|
|
-.btn:active {
|
|
|
- transform: translateY(0);
|
|
|
-}
|
|
|
-.reset-btn {
|
|
|
- background: #74b9ff;
|
|
|
-}
|
|
|
-.reset-btn:hover {
|
|
|
- background: #0984e3;
|
|
|
-}
|
|
|
-
|
|
|
-/* 萌宠卡片布局 */
|
|
|
-.pet-list {
|
|
|
- margin-top: 20px;
|
|
|
-}
|
|
|
-.list-wrap {
|
|
|
- display: flex;
|
|
|
- flex-wrap: wrap;
|
|
|
- gap: 20px;
|
|
|
- justify-content: center;
|
|
|
-}
|
|
|
-
|
|
|
-/* 卡片基础样式 + hover 动画 */
|
|
|
-.pet-card {
|
|
|
- width: 160px;
|
|
|
- padding: 15px;
|
|
|
- border-radius: 12px;
|
|
|
- background: #fef5f5;
|
|
|
- text-align: center;
|
|
|
- box-shadow: 0 2px 8px rgba(0,0,0,0.1);
|
|
|
- transition: all 0.3s ease;
|
|
|
- position: relative;
|
|
|
-}
|
|
|
-.pet-card:hover {
|
|
|
- transform: translateY(-6px);
|
|
|
- box-shadow: 0 8px 16px rgba(255, 120, 117, 0.25);
|
|
|
-}
|
|
|
-
|
|
|
-/* 选中状态动画:放大+变色 */
|
|
|
-.pet-card.active {
|
|
|
- border: 2px solid #ff7875;
|
|
|
- transform: scale(1.05);
|
|
|
- background: #ffe8e8;
|
|
|
-}
|
|
|
-
|
|
|
-/* 宠物表情 */
|
|
|
-.pet-avatar {
|
|
|
- font-size: 48px;
|
|
|
- margin-bottom: 8px;
|
|
|
-}
|
|
|
-.pet-name {
|
|
|
- font-size: 16px;
|
|
|
- font-weight: bold;
|
|
|
- color: #333;
|
|
|
-}
|
|
|
-.pet-type, .pet-level {
|
|
|
- font-size: 14px;
|
|
|
- color: #666;
|
|
|
- margin: 4px 0;
|
|
|
-}
|
|
|
-.card-check {
|
|
|
- position: absolute;
|
|
|
- top: 8px;
|
|
|
- left: 8px;
|
|
|
- cursor: pointer;
|
|
|
-}
|
|
|
-
|
|
|
-/* Vue 列表过渡动画 入场/离场 */
|
|
|
-.pet-enter-active {
|
|
|
- transition: all 0.4s ease;
|
|
|
-}
|
|
|
-.pet-leave-active {
|
|
|
- transition: all 0.3s ease;
|
|
|
-}
|
|
|
-.pet-enter-from {
|
|
|
- opacity: 0;
|
|
|
- transform: scale(0.7) translateY(20px);
|
|
|
-}
|
|
|
-.pet-leave-to {
|
|
|
- opacity: 0;
|
|
|
- transform: scale(0.7) translateY(-20px);
|
|
|
-}
|
|
|
-
|
|
|
-/* 统计区域 */
|
|
|
-.stat {
|
|
|
- margin-top: 30px;
|
|
|
- text-align: center;
|
|
|
- font-size: 15px;
|
|
|
- color: #555;
|
|
|
-}
|
|
|
-</style>
|