|
@@ -1,11 +1,217 @@
|
|
|
-import { Component } from '@angular/core';
|
|
|
+import { Component, OnInit, AfterViewInit, HostListener } from '@angular/core';
|
|
|
+import { CommonModule } from '@angular/common';
|
|
|
+// import { SwiperModule } from 'swiper/angular';
|
|
|
+import Swiper from 'swiper';
|
|
|
|
|
|
+import { register } from 'swiper/element/bundle';
|
|
|
+register()
|
|
|
@Component({
|
|
|
selector: 'app-home-tab',
|
|
|
- imports: [],
|
|
|
templateUrl: './home-tab.html',
|
|
|
- styleUrl: './home-tab.scss'
|
|
|
+ styleUrls: ['./home-tab.scss'],
|
|
|
+ standalone: true,
|
|
|
+ imports: [CommonModule]
|
|
|
})
|
|
|
-export class HomeTab {
|
|
|
+export class HomeTab implements OnInit, AfterViewInit {
|
|
|
+ // 分类名称映射
|
|
|
+ categoryNames: { [key: string]: string } = {
|
|
|
+ all: "全部",
|
|
|
+ chuan: "川菜",
|
|
|
+ lu: "鲁菜",
|
|
|
+ yue: "粤菜",
|
|
|
+ su: "苏菜",
|
|
|
+ zhe: "浙菜",
|
|
|
+ min: "闽菜",
|
|
|
+ xiang: "湘菜",
|
|
|
+ hui: "徽菜",
|
|
|
+ more: "国际"
|
|
|
+ };
|
|
|
|
|
|
-}
|
|
|
+ currentCategory = 'all';
|
|
|
+ isLoading = false;
|
|
|
+ loadedItemsCount = 0;
|
|
|
+ dishes: any[] = [];
|
|
|
+ isRefreshing = false;
|
|
|
+ startY = 0;
|
|
|
+ isThrottled = false;
|
|
|
+ swiper?: Swiper;
|
|
|
+
|
|
|
+ // 热门搜索标签
|
|
|
+ hotTags = ['川菜', '家常菜', '早餐', '低卡', '烘焙', '火锅', '海鲜', '甜品'];
|
|
|
+
|
|
|
+ ngOnInit(): void {
|
|
|
+ this.renderDishes(this.currentCategory);
|
|
|
+ }
|
|
|
+
|
|
|
+ ngAfterViewInit(): void {
|
|
|
+ this.initSwiper();
|
|
|
+ }
|
|
|
+
|
|
|
+ initSwiper(): void {
|
|
|
+ this.swiper = new Swiper('.swiper-container', {
|
|
|
+ loop: true,
|
|
|
+ autoplay: {
|
|
|
+ delay: 3000,
|
|
|
+ disableOnInteraction: false,
|
|
|
+ }
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ // 菜品数据生成函数
|
|
|
+ generateDishes(category: string, count: number, existingItems = 0): any[] {
|
|
|
+ const baseImages = [
|
|
|
+ "https://img.freepik.com/free-photo/top-view-table-full-delicious-food-composition_23-2149141352.jpg",
|
|
|
+ "https://img.freepik.com/free-photo/flat-lay-table-full-delicious-food_23-2149141308.jpg",
|
|
|
+ "https://img.freepik.com/free-photo/top-view-table-full-delicious-food-composition_23-2149141353.jpg",
|
|
|
+ "https://img.freepik.com/free-photo/flat-lay-table-full-delicious-food_23-2149141309.jpg",
|
|
|
+ "https://img.freepik.com/free-photo/top-view-table-full-delicious-food-composition_23-2149141354.jpg",
|
|
|
+ "https://img.freepik.com/free-photo/delicious-vietnamese-food-including-pho-ga-noodles-spring-rolls-white-table_181624-34062.jpg",
|
|
|
+ "https://img.freepik.com/free-photo/top-view-table-full-delicious-food-composition_23-2149141355.jpg",
|
|
|
+ "https://img.freepik.com/free-photo/flat-lay-table-full-delicious-food_23-2149141310.jpg",
|
|
|
+ "https://img.freepik.com/free-photo/top-view-table-full-delicious-food-composition_23-2149141356.jpg",
|
|
|
+ "https://img.freepik.com/free-photo/flat-lay-table-full-delicious-food_23-2149141311.jpg"
|
|
|
+ ];
|
|
|
+
|
|
|
+ const dishNames: { [key: string]: string[] } = {
|
|
|
+ chuan: ["水煮鱼", "回锅肉", "夫妻肺片", "麻婆豆腐", "宫保鸡丁", "鱼香肉丝", "口水鸡", "担担面", "酸菜鱼", "辣子鸡"],
|
|
|
+ lu: ["九转大肠", "糖醋鲤鱼", "葱烧海参", "油爆双脆", "德州扒鸡", "四喜丸子", "锅塌豆腐", "奶汤蒲菜", "黄焖鸡块", "爆炒腰花"],
|
|
|
+ yue: ["白切鸡", "烧鹅", "虾饺", "叉烧", "肠粉", "煲仔饭", "豉汁蒸排骨", "干炒牛河", "蜜汁叉烧包", "萝卜牛腩"],
|
|
|
+ su: ["松鼠桂鱼", "清炖狮子头", "盐水鸭", "大煮干丝", "蟹粉豆腐", "水晶肴肉", "响油鳝糊", "无锡排骨", "鸭血粉丝汤", "三套鸭"],
|
|
|
+ zhe: ["西湖醋鱼", "东坡肉", "龙井虾仁", "宋嫂鱼羹", "干炸响铃", "叫化童鸡", "油焖春笋", "蜜汁火方", "雪菜大汤黄鱼", "糟烩鞭笋"],
|
|
|
+ min: ["佛跳墙", "沙县小吃", "荔枝肉", "蚵仔煎", "土笋冻", "福州鱼丸", "闽南咸饭", "红糟鱼", "海蛎煎蛋", "八宝红鲟饭"],
|
|
|
+ xiang: ["剁椒鱼头", "毛氏红烧肉", "腊味合蒸", "永州血鸭", "东安子鸡", "辣椒炒肉", "湘西酸肉", "组庵鱼翅", "宁乡口味蛇", "湘味臭豆腐"],
|
|
|
+ hui: ["徽州毛豆腐", "黄山炖鸽", "臭鳜鱼", "胡适一品锅", "问政山笋", "刀板香", "中和汤", "绩溪炒粉丝", "深渡包袱饺", "葛粉圆子"],
|
|
|
+ more: ["意大利面", "日式寿司", "法式甜点", "印度咖喱", "泰国冬阴功", "韩国泡菜", "越南河粉", "墨西哥卷饼", "德国香肠", "美式汉堡"]
|
|
|
+ };
|
|
|
+
|
|
|
+ // 如果是全部分类,合并所有菜系的菜品
|
|
|
+ if (category === "all") {
|
|
|
+ const allDishes: any[] = [];
|
|
|
+ for (const key in dishNames) {
|
|
|
+ if (key !== "all") {
|
|
|
+ dishNames[key].forEach((name, index) => {
|
|
|
+ allDishes.push({
|
|
|
+ name: name,
|
|
|
+ category: key,
|
|
|
+ image: baseImages[(index + existingItems) % baseImages.length],
|
|
|
+ popularity: (Math.random() * 5 + 5).toFixed(1) + "k"
|
|
|
+ });
|
|
|
+ });
|
|
|
+ }
|
|
|
+ }
|
|
|
+ // 随机排序
|
|
|
+ return allDishes.sort(() => Math.random() - 0.5).slice(0, count);
|
|
|
+ } else {
|
|
|
+ // 其他分类生成对应菜品
|
|
|
+ const dishes: any[] = [];
|
|
|
+ for (let i = 0; i < count; i++) {
|
|
|
+ const nameIndex = (i + existingItems) % dishNames[category].length;
|
|
|
+ dishes.push({
|
|
|
+ name: dishNames[category][nameIndex],
|
|
|
+ category: category,
|
|
|
+ image: baseImages[(i + existingItems) % baseImages.length],
|
|
|
+ popularity: (Math.random() * 5 + 5).toFixed(1) + "k"
|
|
|
+ });
|
|
|
+ }
|
|
|
+ return dishes;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 渲染菜品函数
|
|
|
+ renderDishes(category: string, isRefresh = false): void {
|
|
|
+ if (this.isLoading) return;
|
|
|
+ this.isLoading = true;
|
|
|
+
|
|
|
+ // 如果是刷新,重置状态
|
|
|
+ if (isRefresh) {
|
|
|
+ this.dishes = [];
|
|
|
+ this.loadedItemsCount = 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 模拟API请求延迟
|
|
|
+ setTimeout(() => {
|
|
|
+ // 生成更多菜品数据
|
|
|
+ const newDishes = this.generateDishes(category, 10, this.loadedItemsCount);
|
|
|
+
|
|
|
+ // 添加菜品到列表
|
|
|
+ this.dishes = [...this.dishes, ...newDishes];
|
|
|
+
|
|
|
+ // 更新已加载项目计数
|
|
|
+ this.loadedItemsCount += newDishes.length;
|
|
|
+ this.currentCategory = category;
|
|
|
+ this.isLoading = false;
|
|
|
+ }, 800);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 切换分类
|
|
|
+ changeCategory(category: string): void {
|
|
|
+ this.currentCategory = category;
|
|
|
+ this.renderDishes(category, true);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 检查滚动位置
|
|
|
+ checkScroll(): void {
|
|
|
+ if (window.innerHeight + window.scrollY >= document.body.offsetHeight - 500) {
|
|
|
+ this.renderDishes(this.currentCategory);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 滚动事件监听
|
|
|
+ @HostListener('window:scroll', [])
|
|
|
+ onWindowScroll(): void {
|
|
|
+ if (!this.isThrottled) {
|
|
|
+ this.checkScroll();
|
|
|
+ this.isThrottled = true;
|
|
|
+ setTimeout(() => {
|
|
|
+ this.isThrottled = false;
|
|
|
+ }, 200);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 下拉刷新相关事件
|
|
|
+ onTouchStart(event: TouchEvent): void {
|
|
|
+ if (this.isRefreshing || window.scrollY > 0) return;
|
|
|
+ this.startY = event.touches[0].clientY;
|
|
|
+ }
|
|
|
+
|
|
|
+ onTouchMove(event: TouchEvent): void {
|
|
|
+ if (this.isRefreshing || window.scrollY > 0) return;
|
|
|
+
|
|
|
+ const y = event.touches[0].clientY;
|
|
|
+ const diff = y - this.startY;
|
|
|
+
|
|
|
+ if (diff > 0) {
|
|
|
+ event.preventDefault();
|
|
|
+ const progress = Math.min(diff / 100, 1);
|
|
|
+ const indicator = document.querySelector('.refresh-indicator') as HTMLElement;
|
|
|
+ if (indicator) {
|
|
|
+ indicator.style.transform = `translateY(${-50 + progress * 50}px)`;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (diff > 100 && !this.isRefreshing) {
|
|
|
+ this.isRefreshing = true;
|
|
|
+ const indicator = document.querySelector('.refresh-indicator') as HTMLElement;
|
|
|
+ if (indicator) {
|
|
|
+ indicator.innerHTML = '<i class="bi bi-arrow-clockwise refresh-spinner"></i><span>正在刷新...</span>';
|
|
|
+ }
|
|
|
+
|
|
|
+ // 模拟刷新数据
|
|
|
+ setTimeout(() => {
|
|
|
+ this.renderDishes(this.currentCategory, true);
|
|
|
+ if (indicator) {
|
|
|
+ indicator.style.transform = 'translateY(-100%)';
|
|
|
+ }
|
|
|
+ this.isRefreshing = false;
|
|
|
+ }, 1000);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ onTouchEnd(): void {
|
|
|
+ if (this.isRefreshing) return;
|
|
|
+ const indicator = document.querySelector('.refresh-indicator') as HTMLElement;
|
|
|
+ if (indicator) {
|
|
|
+ indicator.style.transform = 'translateY(-100%)';
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|