From 314b03a9ab60a873a4f731a37efb05ce34186be0 Mon Sep 17 00:00:00 2001 From: feie9456 Date: Tue, 8 Jul 2025 11:34:29 +0800 Subject: [PATCH] waapi --- src/data/index.ts | 469 ++++++++++++++++++++++++++++++++++++++++++++ src/pages/Page1.vue | 402 ++++++++++++++++++++++--------------- 2 files changed, 718 insertions(+), 153 deletions(-) create mode 100644 src/data/index.ts diff --git a/src/data/index.ts b/src/data/index.ts new file mode 100644 index 0000000..4e54c17 --- /dev/null +++ b/src/data/index.ts @@ -0,0 +1,469 @@ +// 店铺信息接口 +export interface Store { + 城市: string; + 店铺号: string; + 店铺: string; + 备注: string; +} + +// 区域类型 +export type RegionType = + | "奥莱北区" + | "奥莱东区" + | "博物馆" + | "大北区" + | "大东区" + | "大南区" + | "大西区" + | "免税"; + +// 区域数据接口 +export interface RegionData { + 奥莱北区: Store[]; + 奥莱东区: Store[]; + 博物馆: Store[]; + 大北区: Store[]; + 大东区: Store[]; + 大南区: Store[]; + 大西区: Store[]; + 免税: Store[]; +} + +export const regions: RegionData = { + "奥莱北区": [ + { + "城市": "北京", + "店铺号": "B36", + "店铺": "北京斯普瑞斯", + "备注": "B36-北京斯普瑞斯" + }, + { + "城市": "北京", + "店铺号": "T032", + "店铺": "北京燕莎奥特莱斯", + "备注": "T032-北京燕莎奥特莱斯" + }, + { + "城市": "北京", + "店铺号": "T055", + "店铺": "北京赛特奥莱", + "备注": "T055-北京赛特奥莱" + }, + { + "城市": "北京", + "店铺号": "T056", + "店铺": "北京八达岭奥莱", + "备注": "T056-北京八达岭奥莱" + }, + { + "城市": "成都", + "店铺号": "T043", + "店铺": "成都时代奥莱", + "备注": "T043-成都时代奥莱" + }, + { + "城市": "成都", + "店铺号": "T075", + "店铺": "成都佛罗伦萨二期", + "备注": "T075-成都佛罗伦萨二期" + }, + { + "城市": "上海", + "店铺号": "A41", + "店铺": "亚玛芬上海员工店", + "备注": "A41-亚玛芬上海员工店" + }, + { + "城市": "沈阳", + "店铺号": "T047", + "店铺": "沈阳赛特奥特莱斯", + "备注": "T047-沈阳赛特奥特莱斯" + }, + { + "城市": "天津", + "店铺号": "T033", + "店铺": "天津佛罗伦萨", + "备注": "T033-天津佛罗伦萨" + }, + { + "城市": "长春", + "店铺号": "T046", + "店铺": "长春净月赛特奥莱", + "备注": "T046-长春净月赛特奥莱" + } + ], + "奥莱东区": [ + { + "城市": "杭州", + "店铺号": "T053", + "店铺": "杭州下沙", + "备注": "T053-杭州下沙" + }, + { + "城市": "南京", + "店铺号": "T051", + "店铺": "南京汤山百联奥莱", + "备注": "T051-南京汤山百联奥莱" + }, + { + "城市": "宁波", + "店铺号": "T059", + "店铺": "宁波杉井奥特莱斯", + "备注": "T059-宁波杉井奥特莱斯" + }, + { + "城市": "上海", + "店铺号": "A26", + "店铺": "上海奕欧莱奥特莱斯", + "备注": "A26-上海奕欧莱奥特莱斯" + }, + { + "城市": "上海", + "店铺号": "A36", + "店铺": "上海青浦奥莱", + "备注": "A36-青浦奥莱" + }, + { + "城市": "上海", + "店铺号": "T074", + "店铺": "上海佛罗伦萨小镇", + "备注": "T074-上海佛罗伦萨小镇" + }, + { + "城市": "苏州", + "店铺号": "T035", + "店铺": "苏州奕欧来", + "备注": "T035-苏州奕欧来" + }, + { + "城市": "无锡", + "店铺号": "T050", + "店铺": "无锡百联奥莱", + "备注": "T050-无锡百联奥莱" + }, + { + "城市": "武汉", + "店铺号": "T052", + "店铺": "武汉百联奥莱", + "备注": "T052-武汉百联奥莱" + }, + { + "城市": "郑州", + "店铺号": "T045", + "店铺": "郑州杉杉奥莱", + "备注": "T045-郑州杉杉奥莱" + } + ], + "博物馆": [ + { + "城市": "上海", + "店铺号": "T083", + "店铺": "始祖鸟博物馆", + "备注": "T083-始祖鸟博物馆" + } + ], + "大北区": [ + { + "城市": "北京", + "店铺号": "B19", + "店铺": "北京王府中环", + "备注": "B19-北京王府中环" + }, + { + "城市": "北京", + "店铺号": "B25", + "店铺": "北京颐堤港购物中心", + "备注": "B25-北京颐堤港购物中心" + }, + { + "城市": "北京", + "店铺号": "B26", + "店铺": "北京金融街购物中心", + "备注": "B26-北京金融街购物中心" + }, + { + "城市": "北京", + "店铺号": "B27", + "店铺": "北京SKP", + "备注": "B27-北京SKP" + }, + { + "城市": "北京", + "店铺号": "T028", + "店铺": "北京金源燕莎", + "备注": "T028-北京金源燕莎" + }, + { + "城市": "北京", + "店铺号": "T029", + "店铺": "北京国贸", + "备注": "T029-北京国贸" + }, + { + "城市": "北京", + "店铺号": "T072", + "店铺": "北京宜家荟聚", + "备注": "T072-北京宜家荟聚" + }, + { + "城市": "北京", + "店铺号": "T082", + "店铺": "北京三里屯", + "备注": "T082-北京三里屯" + }, + { + "城市": "北京", + "店铺号": "T102", + "店铺": "北京王府半岛", + "备注": "T102-北京王府半岛" + }, + { + "城市": "大连", + "店铺号": "T069", + "店铺": "大连恒隆广场", + "备注": "T069-大连恒隆广场" + }, + { + "城市": "沈阳", + "店铺号": "T106", + "店铺": "沈阳万象城", + "备注": "T106-沈阳万象城" + }, + { + "城市": "天津", + "店铺号": "T031", + "店铺": "天津海信广场", + "备注": "T031-天津海信广场" + }, + { + "城市": "天津", + "店铺号": "T057", + "店铺": "天津万象城", + "备注": "T057-天津万象城" + } + ], + "大东区": [ + { + "城市": "杭州", + "店铺号": "A44", + "店铺": "杭州万象城", + "备注": "A44-杭州万象城" + }, + { + "城市": "杭州", + "店铺号": "B05", + "店铺": "杭州大厦", + "备注": "B05-杭州大厦" + }, + { + "城市": "杭州", + "店铺号": "T030", + "店铺": "杭州湖滨银泰", + "备注": "T030-杭州湖滨银泰" + }, + { + "城市": "合肥", + "店铺号": "T081", + "店铺": "合肥银泰", + "备注": "T081-合肥银泰" + }, + { + "城市": "济南", + "店铺号": "T092", + "店铺": "济南恒隆", + "备注": "T092-济南恒隆" + }, + { + "城市": "南京", + "店铺号": "T085", + "店铺": "南京IFC", + "备注": "T085-南京IFC" + }, + { + "城市": "南京", + "店铺号": "T096", + "店铺": "南京德基", + "备注": "T096-南京德基" + }, + { + "城市": "上海", + "店铺号": "A06", + "店铺": "上海港汇", + "备注": "A06-上海港汇" + }, + { + "城市": "上海", + "店铺号": "A24", + "店铺": "上海静安嘉里", + "备注": "A24-上海静安嘉里" + }, + { + "城市": "上海", + "店铺号": "A25", + "店铺": "上海浦东嘉里中心", + "备注": "A25-上海浦东嘉里中心" + }, + { + "城市": "上海", + "店铺号": "T063", + "店铺": "上海始祖鸟明珠店", + "备注": "T063-上海始祖鸟明珠店" + }, + { + "城市": "上海", + "店铺号": "T065", + "店铺": "上海恒隆广场", + "备注": "T065-上海恒隆广场" + }, + { + "城市": "上海", + "店铺号": "T086", + "店铺": "上海IAPM", + "备注": "T086-上海IAPM" + }, + { + "城市": "上海", + "店铺号": "T097", + "店铺": "上海虹桥机场", + "备注": "T097-虹桥机场" + }, + { + "城市": "上海", + "店铺号": "T999", + "店铺": "上海始祖鸟阿尔法中心", + "备注": "T999-上海始祖鸟阿尔法中心" + }, + { + "城市": "苏州", + "店铺号": "T066", + "店铺": "苏州中心", + "备注": "T066-苏州中心" + }, + { + "城市": "武汉", + "店铺号": "T038", + "店铺": "武汉武商广场", + "备注": "T038-武汉武商广场" + }, + { + "城市": "武汉", + "店铺号": "T071", + "店铺": "武汉恒隆广场", + "备注": "T071-武汉恒隆广场" + }, + { + "城市": "武汉", + "店铺号": "T080", + "店铺": "武汉梦时代", + "备注": "T080-武汉梦时代" + }, + { + "城市": "武汉", + "店铺号": "T093", + "店铺": "武汉SKP", + "备注": "T093-武汉SKP" + }, + { + "城市": "长沙", + "店铺号": "T095", + "店铺": "长沙IFS", + "备注": "T095-长沙IFS" + }, + { + "城市": "郑州", + "店铺号": "T098", + "店铺": "郑州正弘城", + "备注": "T098-郑州正弘城" + } + ], + "大南区": [ + { + "城市": "成都", + "店铺号": "T084", + "店铺": "成都in99", + "备注": "T084-成都in99" + }, + { + "城市": "广州", + "店铺号": "B21", + "店铺": "广州天环", + "备注": "B21-广州天环" + }, + { + "城市": "广州", + "店铺号": "T061", + "店铺": "广州太古汇", + "备注": "T061-广州太古汇" + }, + { + "城市": "南宁", + "店铺号": "T094", + "店铺": "南宁万象城", + "备注": "T094-南宁万象城" + }, + { + "城市": "深圳", + "店铺号": "B23", + "店铺": "深圳湾万象城", + "备注": "B23-深圳湾万象城" + }, + { + "城市": "深圳", + "店铺号": "B31", + "店铺": "深圳罗湖万象城", + "备注": "B31-深圳罗湖万象城" + }, + { + "城市": "深圳", + "店铺号": "T067", + "店铺": "深圳万象天地", + "备注": "T067-深圳万象天地" + }, + { + "城市": "深圳", + "店铺号": "T079", + "店铺": "深圳宝安机场", + "备注": "T079-深圳宝安机场" + } + ], + "大西区": [ + { + "城市": "太原", + "店铺号": "T087", + "店铺": "太原万象城", + "备注": "T087-太原万象城" + }, + { + "城市": "太原", + "店铺号": "T099", + "店铺": "太原天美", + "备注": "T099-太原天美" + }, + { + "城市": "西安", + "店铺号": "T109", + "店铺": "西安赛格国际5楼", + "备注": "T109-西安赛格国际5楼" + }, + { + "城市": "西安", + "店铺号": "T110", + "店铺": "西安赛格国际1楼", + "备注": "T110-西安赛格国际1楼" + } + ], + "免税": [ + { + "城市": "海口", + "店铺号": "DFT0002", + "店铺": "海口新海港", + "备注": "DFT0002-海口新海港" + }, + { + "城市": "三亚", + "店铺号": "DFT0001", + "店铺": "三亚海棠湾免税店", + "备注": "DFT0001-三亚海棠湾免税店" + } + ] +} \ No newline at end of file diff --git a/src/pages/Page1.vue b/src/pages/Page1.vue index a8f0cb3..acde2ab 100644 --- a/src/pages/Page1.vue +++ b/src/pages/Page1.vue @@ -2,7 +2,9 @@ import { onMounted } from 'vue'; import assets from '../assets'; -const regions = [ +import { regions } from '../data'; + +const regionsPos = [ { w: 68.8, h: 68.8, l: -1, t: -4, src: assets.p1.大北区, tt: '大北区', trt: -13, ad: 6 }, { w: 73.3, h: 73.3, l: 44, t: 20, src: assets.p1.大东区, tt: '大东区', ad: 3 }, { w: 62.3, h: 63.7, l: -32, t: 72, src: assets.p1['大南区&免税'], tt: '大南区&免税', trt: 5, ad: 3 }, @@ -10,41 +12,194 @@ const regions = [ { w: 52.1, h: 52, l: 3, t: 40, src: assets.p1.奥莱, tt: '奥莱', ad: 2 }, { w: 62.7, h: 62.7, l: 33, t: 74, src: assets.p1.博物馆, tt: '博物馆', tc: '#fff', ad: 0 }, ] -onMounted(() => { - const regionBubbles = document.querySelectorAll('.region-bubble'); - regionBubbles.forEach((bubble, index) => { - const pDown = () => { - bubble.animate([ - { transform: 'translate3d(-50%, -50%, 0) scale(1)', filter: 'brightness(1)' }, - { transform: 'translate3d(-50%,-50%, 0) scale(0.92)', filter: 'brightness(0.9)' }, - ], { - duration: 500, - easing: 'ease-in-out', - fill: 'forwards' - }); - } - const pUp = () => { - bubble.querySelector('span')?.animate([ - { opacity: 1 }, - { opacity: 0 }, - ], { - duration: 1000, - easing: 'ease-in-out', - fill: 'forwards' - }); - bubble.animate([ - { transform: 'translate3d(-50%, -50%, 0) scale(0.92)', filter: 'brightness(0.9)' }, - { transform: 'translate3d(-50%, -50%, 0) scale(4)', filter: 'brightness(1)', top: '53%', left: '50%' }, - ], { - duration: 1000, - easing: 'ease-in-out', - fill: 'forwards' - }); - // 其他元素淡出 - regionBubbles.forEach((otherBubble, otherIndex) => { - if (otherIndex == index) return - otherBubble.animate([ +// 动画管理 +let fadeInAnimations: Animation[] = []; +let swapInAnimations: Animation[] = []; +let scaleInAnimations: Animation[] = []; +let bubbleDropAnimations: Animation[] = []; + +// 保存所有动画的数组 +let allAnimations: Animation[] = []; + +// 淡入动画 +function createFadeInAnimation(element: Element, delay: number = 0) { + const animation = element.animate([ + { opacity: 0 }, + { opacity: 1 } + ], { + duration: 500, + easing: 'ease-in-out', + delay: delay * 1000, + fill: 'forwards' + }); + fadeInAnimations.push(animation); + allAnimations.push(animation); + return animation; +} + +// Swap in 动画(渐进显示) +function createSwapInAnimation(element: Element, delay: number = 0) { + const animation = element.animate([ + { clipPath: 'inset(0 100% 0 0)' }, + { clipPath: 'inset(0 0% 0 0)' } + ], { + duration: 500, + easing: 'ease-in-out', + delay: delay * 1000, + fill: 'forwards' + }); + swapInAnimations.push(animation); + allAnimations.push(animation); + return animation; +} + +// Scale in 动画(容器) +function createScaleInContainerAnimation(element: Element, delay: number = 0) { + const animation = element.animate([ + { transform: 'scale(0)' }, + { transform: 'scale(1)' } + ], { + duration: 500, + easing: 'cubic-bezier(0.5, 0, 0.71, 1.85)', + delay: (delay + 0.2) * 1000, + fill: 'forwards' + }); + scaleInAnimations.push(animation); + allAnimations.push(animation); + return animation; +} + +// Scale in 动画(文本) +function createScaleInTextAnimation(element: Element, delay: number = 0) { + const animation = element.animate([ + { transform: 'scale(0)' }, + { transform: 'scale(1)' } + ], { + duration: 500, + easing: 'cubic-bezier(0.5, 0, 0.71, 1.5)', + delay: (delay + 0.2 + 0.1) * 1000, + fill: 'forwards' + }); + scaleInAnimations.push(animation); + allAnimations.push(animation); + return animation; +} + +// 气泡下降动画 +function createBubbleDropAnimation(element: Element, startTop: string, startLeft: string, endTop: string, endLeft: string, delay: number = 0, duration: number = 600) { + const animation = element.animate([ + { + top: startTop, + left: startLeft, + transform: 'translate3d(-50%, -50%, 0) scale(0.1)' + }, + { + top: endTop, + left: endLeft, + transform: 'translate3d(-50%, -50%, 0) scale(1)' + } + ], { + duration: duration, + easing: 'ease-out', + delay: (delay + 1) * 1000, + fill: 'forwards' + }); + bubbleDropAnimations.push(animation); + allAnimations.push(animation); + return animation; +} + +// 反向播放所有动画来淡出 +function reverseAllAnimations() { + allAnimations.forEach(animation => { + // 确保动画已经完成 + if (animation.playState === 'finished') { + animation.reverse(); + } + }); +} + +// 淡出所有动画(备用方案) +function fadeOutAllAnimations() { + const allElements = document.querySelectorAll('.fade-in, .swap-in, .scale-in-ctn, .scale-in-txt, .region-bubble'); + allElements.forEach((element) => { + element.animate([ + { opacity: 1 }, + { opacity: 0 } + ], { + duration: 1000, + easing: 'ease-in-out', + fill: 'forwards' + }); + }); +} + +// 暴露函数供外部使用 +(window as any).reverseAllAnimations = reverseAllAnimations; +(window as any).fadeOutAllAnimations = fadeOutAllAnimations; + +onMounted(() => { + // 等待一帧确保所有元素都已渲染 + requestAnimationFrame(() => { + // 初始化logo淡入动画 + const logo = document.querySelector('.logo'); + if (logo) { + createFadeInAnimation(logo, 2); + } + + // 初始化swap-in动画 + const swapInElements = document.querySelectorAll('.swap-in'); + swapInElements.forEach((element) => { + const htmlElement = element as HTMLElement; + const delay = parseFloat(htmlElement.style.getPropertyValue('--base-delay')?.replace('s', '') || '0'); + createSwapInAnimation(element, delay); + }); + + // 初始化scale-in动画 + const scaleInContainers = document.querySelectorAll('.scale-in-ctn'); + scaleInContainers.forEach((element) => { + const htmlElement = element as HTMLElement; + const delay = parseFloat(htmlElement.style.getPropertyValue('--base-delay')?.replace('s', '') || '0'); + createScaleInContainerAnimation(element, delay); + }); + + const scaleInTexts = document.querySelectorAll('.scale-in-txt'); + scaleInTexts.forEach((element) => { + const htmlElement = element as HTMLElement; + const delay = parseFloat(htmlElement.style.getPropertyValue('--base-delay')?.replace('s', '') || '0'); + createScaleInTextAnimation(element, delay); + }); + + // 初始化气泡动画 + const regionBubbles = document.querySelectorAll('.region-bubble'); + regionBubbles.forEach((bubble, index) => { + const region = regionsPos[index]; + const startTop = `${region.t + 50 - 200 - (100 - region.t)}%`; + const startLeft = `${region.l / 2 + 50}%`; + const endTop = `${region.t + 50}%`; + const endLeft = `${region.l + 50}%`; + + // 设置初始位置 + (bubble as HTMLElement).style.top = startTop; + (bubble as HTMLElement).style.left = startLeft; + + createBubbleDropAnimation(bubble, startTop, startLeft, endTop, endLeft, 0, 600 + region.ad * 100); + + // 点击事件 + const pDown = () => { + bubble.animate([ + { transform: 'translate3d(-50%, -50%, 0) scale(1)', filter: 'brightness(1)' }, + { transform: 'translate3d(-50%,-50%, 0) scale(0.92)', filter: 'brightness(0.9)' }, + ], { + duration: 500, + easing: 'ease-in-out', + fill: 'forwards' + }); + } + + const pUp = () => { + bubble.querySelector('span')?.animate([ { opacity: 1 }, { opacity: 0 }, ], { @@ -52,13 +207,38 @@ onMounted(() => { easing: 'ease-in-out', fill: 'forwards' }); + + bubble.animate([ + { transform: 'translate3d(-50%, -50%, 0) scale(0.92)', filter: 'brightness(0.9)' }, + { transform: 'translate3d(-50%, -50%, 0) scale(4)', filter: 'brightness(1)', top: '53%', left: '50%' }, + ], { + duration: 1000, + easing: 'ease-in-out', + fill: 'forwards' + }); - }); + // 反向播放所有动画来淡出其他元素 + reverseAllAnimations(); - bubble.removeEventListener('pointerdown', pDown); - } - bubble.addEventListener('pointerdown', pDown); - bubble.addEventListener('pointerup', pUp, { once: true }); + // 淡出其他气泡 + regionBubbles.forEach((otherBubble, otherIndex) => { + if (otherIndex == index) return + otherBubble.animate([ + { opacity: 1 }, + { opacity: 0 }, + ], { + duration: 1000, + easing: 'ease-in-out', + fill: 'forwards' + }); + }); + + bubble.removeEventListener('pointerdown', pDown); + } + + bubble.addEventListener('pointerdown', pDown); + bubble.addEventListener('pointerup', pUp, { once: true }); + }); }); }); @@ -66,18 +246,18 @@ onMounted(() => {