diff --git a/index.html b/index.html index a59b6a3..ef067ba 100644 --- a/index.html +++ b/index.html @@ -17,7 +17,7 @@ - + @@ -27,13 +27,13 @@ - - + + - + @@ -41,7 +41,7 @@ - + diff --git a/src/assets/image/land/creator-h5.webp b/src/assets/image/land/creator-h5.webp new file mode 100644 index 0000000..573b2c8 Binary files /dev/null and b/src/assets/image/land/creator-h5.webp differ diff --git a/src/assets/image/land/creator.webp b/src/assets/image/land/creator.webp new file mode 100644 index 0000000..9d8af57 Binary files /dev/null and b/src/assets/image/land/creator.webp differ diff --git a/src/assets/image/land/download-lg.svg b/src/assets/image/land/download-lg.svg new file mode 100644 index 0000000..4a4123b --- /dev/null +++ b/src/assets/image/land/download-lg.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/src/assets/image/land/download-white.svg b/src/assets/image/land/download-white.svg new file mode 100644 index 0000000..45934d1 --- /dev/null +++ b/src/assets/image/land/download-white.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/src/assets/image/land/download.svg b/src/assets/image/land/download.svg new file mode 100644 index 0000000..b2e357c --- /dev/null +++ b/src/assets/image/land/download.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/src/assets/image/land/edit.svg b/src/assets/image/land/edit.svg new file mode 100644 index 0000000..452a12c --- /dev/null +++ b/src/assets/image/land/edit.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/src/assets/image/land/genres-h5.webp b/src/assets/image/land/genres-h5.webp new file mode 100644 index 0000000..4582b06 Binary files /dev/null and b/src/assets/image/land/genres-h5.webp differ diff --git a/src/assets/image/land/genres.webp b/src/assets/image/land/genres.webp new file mode 100644 index 0000000..ebec611 Binary files /dev/null and b/src/assets/image/land/genres.webp differ diff --git a/src/assets/image/land/guide-close.png b/src/assets/image/land/guide-close.png new file mode 100644 index 0000000..48552b9 Binary files /dev/null and b/src/assets/image/land/guide-close.png differ diff --git a/src/assets/image/land/hero-h5.webp b/src/assets/image/land/hero-h5.webp new file mode 100644 index 0000000..6cba847 Binary files /dev/null and b/src/assets/image/land/hero-h5.webp differ diff --git a/src/assets/image/land/hero.webp b/src/assets/image/land/hero.webp new file mode 100644 index 0000000..ff03451 Binary files /dev/null and b/src/assets/image/land/hero.webp differ diff --git a/src/assets/image/land/highlights-h5.webp b/src/assets/image/land/highlights-h5.webp new file mode 100644 index 0000000..66f77ec Binary files /dev/null and b/src/assets/image/land/highlights-h5.webp differ diff --git a/src/assets/image/land/highlights.webp b/src/assets/image/land/highlights.webp new file mode 100644 index 0000000..e33bb87 Binary files /dev/null and b/src/assets/image/land/highlights.webp differ diff --git a/src/assets/image/land/immersive-h5.webp b/src/assets/image/land/immersive-h5.webp new file mode 100644 index 0000000..88c4f02 Binary files /dev/null and b/src/assets/image/land/immersive-h5.webp differ diff --git a/src/assets/image/land/immersive.webp b/src/assets/image/land/immersive.webp new file mode 100644 index 0000000..817982c Binary files /dev/null and b/src/assets/image/land/immersive.webp differ diff --git a/src/assets/image/land/logo-icon.png b/src/assets/image/land/logo-icon.png new file mode 100644 index 0000000..04959fd Binary files /dev/null and b/src/assets/image/land/logo-icon.png differ diff --git a/src/assets/image/land/play.svg b/src/assets/image/land/play.svg new file mode 100644 index 0000000..05ce2b5 --- /dev/null +++ b/src/assets/image/land/play.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/src/assets/image/land/title.webp b/src/assets/image/land/title.webp new file mode 100644 index 0000000..fff50c8 Binary files /dev/null and b/src/assets/image/land/title.webp differ diff --git a/src/assets/image/land/wish-h5.webp b/src/assets/image/land/wish-h5.webp new file mode 100644 index 0000000..04e6fe3 Binary files /dev/null and b/src/assets/image/land/wish-h5.webp differ diff --git a/src/assets/image/land/wish.webp b/src/assets/image/land/wish.webp new file mode 100644 index 0000000..3de2a52 Binary files /dev/null and b/src/assets/image/land/wish.webp differ diff --git a/src/assets/image/land/wordmark.png b/src/assets/image/land/wordmark.png new file mode 100644 index 0000000..2dbd57c Binary files /dev/null and b/src/assets/image/land/wordmark.png differ diff --git a/src/components/landing-b/LandingBMobile.vue b/src/components/landing-b/LandingBMobile.vue deleted file mode 100644 index 5ffaa38..0000000 --- a/src/components/landing-b/LandingBMobile.vue +++ /dev/null @@ -1,3721 +0,0 @@ - - - - - diff --git a/src/components/landing-b/LandingBPc.vue b/src/components/landing-b/LandingBPc.vue deleted file mode 100644 index 98e9490..0000000 --- a/src/components/landing-b/LandingBPc.vue +++ /dev/null @@ -1,3052 +0,0 @@ - - - - - diff --git a/src/components/landing-b/useLandingB.ts b/src/components/landing-b/useLandingB.ts deleted file mode 100644 index 44b60de..0000000 --- a/src/components/landing-b/useLandingB.ts +++ /dev/null @@ -1,667 +0,0 @@ -import { ref, computed, watch, onMounted, onBeforeUnmount, nextTick } from 'vue' -import { useRoute } from 'vue-router' -import rawDramas from '~/data/b-land/dramas.json' -import rawFeatured from '~/data/b-land/featured.json' -import { useAppDownload } from '~/utils/useAppDownload' -import { copyToClipboard } from '~/utils/clipboard' -import { getLandingVersion } from '~/utils/landingVersion' - -export interface Drama { - t: string - tags: string[] - eps: number | null - cast: string | null - kind: '短剧' | '影集' - cover: string - syn: string | null - slug?: string -} - -interface RawDrama { - id?: number - title?: string - t?: string - tags?: string[] - episodes?: number | null - eps?: number | null - cast?: string | null - kind?: '短剧' | '影集' - cover?: string - synopsis?: string | null - syn?: string | null -} - -interface RawFeatured { - order?: number - title?: string - t?: string - slug: string - files?: Record -} - -const DRAMAS: Drama[] = (rawDramas as RawDrama[]).map((d) => ({ - t: d.t || d.title || '', - tags: Array.isArray(d.tags) ? d.tags : [], - eps: d.eps ?? d.episodes ?? null, - cast: d.cast ?? null, - kind: d.kind === '影集' ? '影集' : '短剧', - cover: d.cover || 'covers2/d01.jpg', - syn: d.syn ?? d.synopsis ?? '', -})) - -const FEATURED_CONFIG = rawFeatured as RawFeatured[] - -const FEATURED: Drama[] = FEATURED_CONFIG.map((f) => { - const title = f.t || f.title || '' - const found = DRAMAS.find((d) => d.t === title) - return { - t: title || (found ? found.t : ''), - tags: found?.tags && found.tags.length ? found.tags : ['原创'], - eps: found?.eps ?? 10, - cast: found?.cast ?? '原创', - kind: found?.kind || '短剧', - cover: f.files?.cover || found?.cover || `hero/${f.slug}-cover.jpg`, - syn: found?.syn || '', - slug: f.slug, - } -}) - -const GENRES = ['都市', '悬疑', '古装', '奇幻', '穿越', '重生', '武侠', '逆袭'] - -const FAQS = [ - { - q: '黄果短剧 App 需要付费吗?', - a: 'App 免费下载。海量短剧与影集每日更新,开通会员可解锁全站作品、免广告与高清画质,随时可取消。', - }, - { - q: 'iOS 如何安装黄果短剧 App?', - a: '用 Safari 打开本页,点击「下载 iOS 版」,允许下载描述文件后,前往 设置 › 已下载描述文件 › 安装,输入锁屏密码即可;桌面出现图标即安装完成。', - }, - { - q: '内容多久更新一次?', - a: '每日更新。短剧与影集双轨并行,新作上线会同步显示在「最新上架」与 App 首页。', - }, -] - -const assetUrl = (path: string) => `/b-land/assets/${path}` - -export type LandingBMode = 'pc' | 'mobile' - -/** - * Landing B 共享逻辑。mode 决定下载分流:pc 开扫码弹窗,mobile 直接触发下载。 - */ -export function useLandingB(mode: LandingBMode) { - const isMobileMode = mode === 'mobile' - const route = useRoute() - - const currentView = ref<'landing' | 'works'>('landing') - const currentHeroIndex = ref(0) - const isHeroTransitioning = ref(false) - const isHeroHovered = ref(false) - const heroProgKey = ref(0) - const bgFront = ref<'a' | 'b'>('a') - const bgAUrl = ref('') - const bgBUrl = ref('') - const topImgUrl = ref('') - let heroTimer: ReturnType | null = null - let heroStartedAt = 0 - let heroRemaining = 6000 - const HERO_INTERVAL = 6000 - - const currentHero = computed(() => { - return ( - FEATURED[currentHeroIndex.value] || - FEATURED[0] || { - t: '废柴杂役', - tags: ['重生', '武侠'], - eps: 15, - cast: '粗硬风辞', - kind: '短剧' as const, - cover: 'covers2/d01.jpg', - syn: '', - slug: '05-feichai', - } - ) - }) - - function heroBlurUrl(slug: string) { - return assetUrl(`hero/${slug}-land-blur.jpg`) - } - - function heroPortUrl(slug: string) { - return assetUrl(`hero/${slug}-port-top.jpg`) - } - - function applyHeroVisuals(index: number, first = false) { - const item = FEATURED[index] - if (!item?.slug) return - const blur = heroBlurUrl(item.slug) - topImgUrl.value = heroPortUrl(item.slug) - - if (first) { - bgAUrl.value = blur - bgBUrl.value = blur - bgFront.value = 'a' - return - } - - if (bgFront.value === 'a') { - bgBUrl.value = blur - bgFront.value = 'b' - } else { - bgAUrl.value = blur - bgFront.value = 'a' - } - } - - function setHero(index: number, first = false) { - if (!first && index === currentHeroIndex.value) return - - currentHeroIndex.value = index - applyHeroVisuals(index, first) - - if (!first) { - isHeroTransitioning.value = false - nextTick(() => { - isHeroTransitioning.value = true - }) - } - - heroProgKey.value += 1 - heroRemaining = HERO_INTERVAL - heroStartedAt = Date.now() - if (isHeroHovered.value) { - pauseHeroTimer() - } else { - startHeroTimer(HERO_INTERVAL) - } - } - - function nextHero() { - setHero((currentHeroIndex.value + 1) % FEATURED.length) - } - - function prevHero() { - setHero((currentHeroIndex.value - 1 + FEATURED.length) % FEATURED.length) - } - - function startHeroTimer(ms = HERO_INTERVAL) { - if (heroTimer) clearTimeout(heroTimer) - heroRemaining = ms - heroStartedAt = Date.now() - heroTimer = setTimeout(() => { - if (!isHeroHovered.value) nextHero() - }, ms) - } - - function pauseHeroTimer() { - if (heroTimer) { - clearTimeout(heroTimer) - heroTimer = null - } - } - - function onHeroMouseEnter() { - if (isMobileMode) return - if (isHeroHovered.value) return - isHeroHovered.value = true - if (heroStartedAt) { - heroRemaining = Math.max(50, heroRemaining - (Date.now() - heroStartedAt)) - } - pauseHeroTimer() - } - - function onHeroMouseLeave() { - if (isMobileMode) return - if (!isHeroHovered.value) return - isHeroHovered.value = false - startHeroTimer(heroRemaining) - } - - let touchStartX = 0 - let touchStartY = 0 - - function handleHeroTouchStart(e: TouchEvent) { - if (e.touches.length > 0) { - touchStartX = e.touches[0].clientX - touchStartY = e.touches[0].clientY - } - } - - function handleHeroTouchEnd(e: TouchEvent) { - if (e.changedTouches.length > 0) { - const diffX = e.changedTouches[0].clientX - touchStartX - const diffY = e.changedTouches[0].clientY - touchStartY - if (Math.abs(diffX) > 40 && Math.abs(diffX) > Math.abs(diffY)) { - if (diffX < 0) nextHero() - else prevHero() - } - } - } - - const wallDramas = computed(() => [...DRAMAS.slice(0, 12), ...DRAMAS.slice(0, 12)]) - - const selectedKind = ref<'全部' | '短剧' | '影集'>('全部') - const selectedGenres = ref([]) - - const showPcDownloadModal = ref(false) - const showInstallGuideModal = ref(false) - const installGuideTab = ref<'ios' | 'android'>('ios') - /** iOS 安装引导内:商店版 / 轻量版(仅 iOS 页内切换) */ - const iosInstallGuideTab = ref<'store' | 'lite'>('store') - const targetDramaForDownload = ref(null) - - const AGE_STORAGE_KEY = 'hg_age_ok' - const showAgeGate = ref(false) - - const isScrolled = ref(false) - const showFloatingQr = ref(false) - const isFloatingQrDismissed = ref(false) - const showMobileStickyBar = ref(false) - const activeAnchor = ref('#works') - - const toastMessage = ref('') - const isToastVisible = ref(false) - let toastTimer: ReturnType | null = null - - /** PC 扫码:当前页 URL(对齐 hjll2 / A 版),并带上当前 A/B 避免扫码后重新随机 */ - const pageQrUrl = ref('') - function buildPageQrUrl() { - const url = new URL(window.location.href) - if (!url.searchParams.has('version') && !url.searchParams.has('v')) { - url.searchParams.set('version', getLandingVersion(route.query, route.path)) - } - return url.toString() - } - - const { - buttonList, - isIos, - download, - hasIosStore: hasIosShopPackage, - iosInstallUrl, - isSocialInApp, - guide, - init: initDownload, - } = useAppDownload() - - function closeGuide() { - guide.value = null - } - - function showToast(msg: string) { - toastMessage.value = msg - isToastVisible.value = true - if (toastTimer) clearTimeout(toastTimer) - toastTimer = setTimeout(() => { - isToastVisible.value = false - }, 2000) - } - - function openInstallGuide( - platform: 'ios' | 'android' = 'ios', - iosVariant?: 'store' | 'lite', - ) { - installGuideTab.value = platform - if (platform === 'ios') { - iosInstallGuideTab.value = - iosVariant ?? (hasIosShopPackage.value ? 'store' : 'lite') - } - showInstallGuideModal.value = true - } - - function confirmAge() { - try { - sessionStorage.setItem(AGE_STORAGE_KEY, '1') - } catch { - /* ignore */ - } - showAgeGate.value = false - } - - function leaveSite() { - window.location.replace('about:blank') - } - - function syncPageLock() { - const locked = - showAgeGate.value || showPcDownloadModal.value || showInstallGuideModal.value - document.body.classList.toggle('landing-b-lock', locked) - document.body.style.overflow = locked ? 'hidden' : '' - document.documentElement.style.overflow = locked ? 'hidden' : 'auto' - } - - function handleFilterClick() { - if (isMobileMode) { - handleDownload() - } else { - showPcDownloadModal.value = true - } - } - - function setKind(k: '全部' | '短剧' | '影集') { - selectedKind.value = k - } - - function toggleGenre(g: string) { - const idx = selectedGenres.value.indexOf(g) - if (idx > -1) selectedGenres.value.splice(idx, 1) - else selectedGenres.value.push(g) - } - - function filterDramaList(list: Drama[]) { - return list.filter((d) => { - const tags = Array.isArray(d.tags) ? d.tags : [] - const matchKind = selectedKind.value === '全部' || d.kind === selectedKind.value - const matchGenre = - selectedGenres.value.length === 0 || - selectedGenres.value.some((tag) => tags.includes(tag)) - return matchKind && matchGenre - }) - } - - const top5List = computed(() => DRAMAS.slice(0, 5)) - const filteredTop5 = computed(() => filterDramaList(top5List.value)) - const latest6List = computed(() => DRAMAS.slice(5, 11)) - const filteredLatest6 = computed(() => filterDramaList(latest6List.value)) - const allWorksList = computed(() => DRAMAS) - const filteredAllWorks = computed(() => filterDramaList(allWorksList.value)) - - const faqOpenIndex = ref(0) - function toggleFaq(index: number) { - faqOpenIndex.value = faqOpenIndex.value === index ? null : index - } - - function handleDownload( - platform?: 'ios' | 'ios-lite' | 'ios-store' | 'android', - drama?: Drama | null, - ) { - targetDramaForDownload.value = drama || null - - if (isMobileMode) { - // 商店版:直接跳转 App Store,不进安装引导 - if (platform === 'ios-store') { - handleIosStoreAction() - return - } - - // H5:对齐 A 版 —— 先弹出安装引导,同时触发真实下载(download 内会跳描述文件 / APK) - // A 版是 CTA 直接 download(0),再用 IosInstallGuide 做说明层;B 版用自研引导页承接说明 - if (platform === 'android') { - openInstallGuide('android') - download(0) - return - } - if (platform === 'ios-lite') { - openInstallGuide('ios', 'lite') - // 社媒内置浏览器无法装描述文件,只展示引导文案,由底栏「复制/下载」处理 - if (!isSocialInApp) download(0) - return - } - if (platform === 'ios') { - openInstallGuide('ios') - if (iosInstallGuideTab.value === 'lite' && !isSocialInApp) download(0) - return - } - - // 无平台参数:按 UA 打开引导,并立刻开始对应下载 - if (isIos) { - openInstallGuide('ios') - if (iosInstallGuideTab.value === 'lite' && !isSocialInApp) download(0) - } else { - openInstallGuide('android') - download(0) - } - } else { - showPcDownloadModal.value = true - } - } - - function handleInstallGuideDownload() { - download(0) - } - - function handleInstallGuidePrimary() { - // isSocialInApp 来自 useAppDownload,是 boolean 不是 ref - if (installGuideTab.value === 'ios') { - if (iosInstallGuideTab.value === 'store' && hasIosShopPackage.value) { - handleIosStoreAction() - return - } - if (isSocialInApp) { - handleCopyIosLiteLink() - return - } - download(0, 'ios').then((ok) => { - if (!ok) showToast('下载链接获取中,请稍后重试') - }) - return - } - - download(0, 'android').then((ok) => { - if (!ok) showToast('下载链接获取中,请稍后重试') - }) - } - - function handleCopyIosLiteLink() { - copyToClipboard(iosInstallUrl.value) - showToast('已复制链接') - } - - function handleIosStoreAction() { - if (!hasIosShopPackage.value) { - showToast('商店版链接获取中,请扫码下载') - return - } - // 链接由 bottonclick 返回,拿到后同页跳转(异步后 window.open 会被拦截) - download(1, 'ios').then((ok) => { - if (!ok) showToast('商店版链接获取中,请扫码下载') - }) - } - - function handlePcAndroidDownload() { - download(0, 'android').then((ok) => { - if (!ok) showToast('正在获取 Android 安装包,请扫码下载') - }) - } - - function handleOpenAppDeepLink() { - showToast('示意:Deep link 未配置') - } - - function onModalKeydown(e: KeyboardEvent) { - if (e.key !== 'Escape') return - // 年龄确认不可 Esc 关闭 - if (showAgeGate.value) return - if (showPcDownloadModal.value) showPcDownloadModal.value = false - else if (showInstallGuideModal.value) showInstallGuideModal.value = false - } - - watch([showAgeGate, showPcDownloadModal, showInstallGuideModal], syncPageLock) - - let revealObserver: IntersectionObserver | null = null - - function initScrollReveal() { - if (typeof window === 'undefined') return - if (revealObserver) revealObserver.disconnect() - - revealObserver = new IntersectionObserver( - (entries) => { - entries.forEach((entry) => { - if (entry.isIntersecting) { - entry.target.classList.add('rv') - revealObserver?.unobserve(entry.target) - } - }) - }, - { rootMargin: '0px 0px -8% 0px', threshold: 0.05 }, - ) - - const elements = document.querySelectorAll('[data-reveal]:not(.rv)') - elements.forEach((el) => { - if (el.getBoundingClientRect().top < window.innerHeight * 1.15) { - el.classList.add('rv') - } else { - revealObserver?.observe(el) - } - }) - - setTimeout(() => { - document.querySelectorAll('[data-reveal]:not(.rv)').forEach((el) => { - el.classList.add('rv') - }) - }, 6000) - } - - function switchView(view: 'landing' | 'works', anchor?: string) { - currentView.value = view - window.scrollTo({ top: 0, behavior: 'instant' as ScrollBehavior }) - setTimeout(() => initScrollReveal(), 50) - if (anchor) { - setTimeout(() => { - const el = document.querySelector(anchor) - if (el) el.scrollIntoView({ behavior: 'smooth' }) - }, 100) - } - } - - function onScroll() { - const top = window.scrollY - isScrolled.value = top > 40 - - const triggerHeight = window.innerHeight * 0.6 - const modalOpen = showAgeGate.value || showInstallGuideModal.value || showPcDownloadModal.value - if (top > triggerHeight && !modalOpen) { - if (!isFloatingQrDismissed.value) showFloatingQr.value = true - showMobileStickyBar.value = true - } else { - showFloatingQr.value = false - showMobileStickyBar.value = false - } - - if (currentView.value === 'landing') { - const anchors = ['#works', '#about', '#faq'] - for (const a of anchors) { - const el = document.querySelector(a) - if (el && el.getBoundingClientRect().top < window.innerHeight * 0.45) { - activeAnchor.value = a - } - } - } - } - - let prevHtmlOverflow = '' - - onMounted(() => { - prevHtmlOverflow = document.documentElement.style.overflow - document.documentElement.style.overflow = 'auto' - - // 年龄确认暂时关闭 - // const skipGate = - // route.query.nogate != null || - // (typeof location !== 'undefined' && /(?:^|[?&])nogate(?:[=&]|$)/.test(location.search)) - // let ageOk = false - // try { - // ageOk = sessionStorage.getItem(AGE_STORAGE_KEY) === '1' - // } catch { - // ageOk = false - // } - // showAgeGate.value = !skipGate && !ageOk - showAgeGate.value = false - syncPageLock() - - setHero(0, true) - pageQrUrl.value = buildPageQrUrl() - initDownload() - window.addEventListener('scroll', onScroll, { passive: true }) - window.addEventListener('keydown', onModalKeydown) - onScroll() - - setTimeout(() => initScrollReveal(), 100) - - if (route.query.view === 'works') { - currentView.value = 'works' - } - }) - - onBeforeUnmount(() => { - document.documentElement.style.overflow = prevHtmlOverflow || 'hidden' - document.body.classList.remove('landing-b-lock') - document.body.style.overflow = '' - pauseHeroTimer() - window.removeEventListener('scroll', onScroll) - window.removeEventListener('keydown', onModalKeydown) - if (toastTimer) clearTimeout(toastTimer) - if (revealObserver) revealObserver.disconnect() - }) - - return { - DRAMAS, - FEATURED, - GENRES, - FAQS, - assetUrl, - currentView, - currentHeroIndex, - isHeroTransitioning, - isHeroHovered, - heroProgKey, - bgFront, - bgAUrl, - bgBUrl, - topImgUrl, - currentHero, - setHero, - nextHero, - prevHero, - onHeroMouseEnter, - onHeroMouseLeave, - handleHeroTouchStart, - handleHeroTouchEnd, - wallDramas, - selectedKind, - selectedGenres, - showPcDownloadModal, - showInstallGuideModal, - installGuideTab, - iosInstallGuideTab, - showAgeGate, - confirmAge, - leaveSite, - openInstallGuide, - handleInstallGuideDownload, - handleInstallGuidePrimary, - targetDramaForDownload, - isScrolled, - showFloatingQr, - isFloatingQrDismissed, - showMobileStickyBar, - activeAnchor, - toastMessage, - isToastVisible, - pageQrUrl, - buttonList, - isIos, - download, - iosInstallUrl, - isSocialInApp, - guide, - hasIosShopPackage, - closeGuide, - showToast, - handleFilterClick, - setKind, - toggleGenre, - filteredTop5, - filteredLatest6, - filteredAllWorks, - faqOpenIndex, - toggleFaq, - handleDownload, - handleCopyIosLiteLink, - handleIosStoreAction, - handlePcAndroidDownload, - handleOpenAppDeepLink, - switchView, - } -} diff --git a/src/components/landing-b/LandingB.vue b/src/components/landing-hg2/Landing.vue similarity index 51% rename from src/components/landing-b/LandingB.vue rename to src/components/landing-hg2/Landing.vue index fd134de..fb5ecd5 100644 --- a/src/components/landing-b/LandingB.vue +++ b/src/components/landing-hg2/Landing.vue @@ -1,6 +1,6 @@ - diff --git a/src/components/landing-hg2/Mobile.vue b/src/components/landing-hg2/Mobile.vue new file mode 100644 index 0000000..d2ae57f --- /dev/null +++ b/src/components/landing-hg2/Mobile.vue @@ -0,0 +1,1133 @@ + + + + + diff --git a/src/components/landing-hg2/Pc.vue b/src/components/landing-hg2/Pc.vue new file mode 100644 index 0000000..acb3d08 --- /dev/null +++ b/src/components/landing-hg2/Pc.vue @@ -0,0 +1,851 @@ + + + + + diff --git a/src/pages/index.vue b/src/pages/index.vue index cd4597c..ac06507 100644 --- a/src/pages/index.vue +++ b/src/pages/index.vue @@ -1,9 +1,9 @@ diff --git a/src/pages/land-b/index.vue b/src/pages/land-b/index.vue index d59b1fa..17b5592 100644 --- a/src/pages/land-b/index.vue +++ b/src/pages/land-b/index.vue @@ -1,7 +1,7 @@ diff --git a/vite.config.js b/vite.config.js index 18bbb4b..47a71fb 100644 --- a/vite.config.js +++ b/vite.config.js @@ -3,6 +3,23 @@ import AutoImport from 'unplugin-auto-import/vite'; import vue from '@vitejs/plugin-vue' import path from 'path'; + +// 新落地页移动端样式按 375 设计稿写 px,这里统一转 rem(根字号见 main.js:width/7.5,375 宽时 1rem=50px) +const landingPx2Rem = () => ({ + postcssPlugin: 'landing-hg2-px2rem', + Declaration(decl) { + const file = (decl.source && decl.source.input && decl.source.input.file) || '' + if (!file.includes('landing-hg2/Mobile.vue')) return + if (!/\d*\.?\d+px/.test(decl.value)) return + decl.value = decl.value.replace(/(-?\d*\.?\d+)px/g, (m, n) => { + const v = parseFloat(n) + if (!v || Math.abs(v) < 0.5) return m + return +(v / 50).toFixed(5) + 'rem' + }) + }, +}) +landingPx2Rem.postcss = true + export default defineConfig({ plugins: [vue(),AutoImport({ imports: [ @@ -10,6 +27,11 @@ export default defineConfig({ 'vue-router', ], })], + css: { + postcss: { + plugins: [landingPx2Rem()], + }, + }, resolve: { alias: { '~': path.resolve(__dirname, 'src'),