Vue FullPage.js 完整使用指南:Vue 3 官方全屏滚动解决方案

发布于:2025-09-15 ⋅ 阅读:(20) ⋅ 点赞:(0)

概述

vue-fullpage.js 是 FullPage.js 的官方 Vue.js 3 包装器,为 Vue 3 应用提供了强大的全屏滚动功能。该插件基于成熟的 FullPage.js 库,支持多种滚动效果和丰富的配置选项,特别适用于企业级数据大屏、产品展示、单页应用等场景。

官方信息:

适用场景:

  • 企业数据可视化大屏
  • 领导驾驶舱系统
  • 产品功能演示页面
  • 企业官网首页
  • 多媒体展示应用

🚀 安装与配置

1. 安装依赖

# 使用 npm
npm install --save vue-fullpage.js

# 使用 yarn
yarn add vue-fullpage.js

# 使用 pnpm
pnpm add vue-fullpage.js

2. 在 main.ts 中全局注册

import { createApp } from 'vue'
import App from './App.vue'
import VueFullPage from 'vue-fullpage.js'
import 'vue-fullpage.js/dist/style.css'

const app = createApp(App)
app.use(VueFullPage)
app.mount('#app')

基础使用

1. 基本结构

根据官方文档,vue-fullpage.js 创建了一个 <full-page> 组件:

<template>
  <div>
    <full-page ref="fullpage" :options="options" id="fullpage">
      <!-- 第一屏 -->
      <div class="section">
        <div class="screen-content">
          <h1>第一屏内容</h1>
        </div>
      </div>
      
      <!-- 第二屏 -->
      <div class="section">
        <div class="screen-content">
          <h1>第二屏内容</h1>
        </div>
      </div>
      
      <!-- 第三屏 -->
      <div class="section">
        <div class="screen-content">
          <h1>第三屏内容</h1>
        </div>
      </div>
    </full-page>
  </div>
</template>

<script setup lang="ts">
import { ref } from 'vue'

// fullpage 引用
const fullpage = ref<any>(null)

// 配置选项 - 支持所有 FullPage.js 选项
const options = ref({
  // 许可证(商业使用必需)
  licenseKey: 'YOUR_KEY_HERE', // 替换为您的许可证密钥
  
  // 基础配置
  navigation: true,           // 显示导航点
  navigationPosition: 'right', // 导航点位置
  scrollingSpeed: 1000,       // 滚动速度(毫秒)
  easingcss3: 'ease-in-out',  // CSS3 缓动函数
  
  // 控制选项
  keyboardScrolling: true,    // 键盘控制
  touchSensitivity: 5,        // 触摸灵敏度
  autoScrolling: true,        // 自动滚动
  fitToSection: true,         // 适配屏幕
  
  // 回调函数
  afterLoad: (origin: any, destination: any) => {
    console.log('切换到屏幕:', destination.index + 1)
  },
  onLeave: (origin: any, destination: any) => {
    console.log('离开屏幕:', origin.index + 1, '前往:', destination.index + 1)
  }
})
</script>

<style scoped>
/* 确保 fullpage 容器占满整个视口 */
:deep(#fullpage) {
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 100vh;
  z-index: 1;
}

/* 确保 section 占满整个高度 */
:deep(.fp-section) {
  height: 100vh !important;
}

.screen-content {
  width: 100%;
  height: 100%;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  padding: 24px;
  box-sizing: border-box;
}
</style>

高级功能

1. 自定义导航菜单

<template>
  <!-- 自定义导航菜单 -->
  <div class="top-nav-menu">
    <div 
      class="nav-item" 
      :class="{ active: currentSection === 0 }" 
      @click="goToSection(0)"
    >
      <div class="nav-icon">🏠</div>
      <div class="nav-text">首页</div>
    </div>
    <div 
      class="nav-item" 
      :class="{ active: currentSection === 1 }" 
      @click="goToSection(1)"
    >
      <div class="nav-icon">📊</div>
      <div class="nav-text">数据</div>
    </div>
    <div 
      class="nav-item" 
      :class="{ active: currentSection === 2 }" 
      @click="goToSection(2)"
    >
      <div class="nav-icon">⚙️</div>
      <div class="nav-text">设置</div>
    </div>
  </div>

  <full-page ref="fullpage" :options="options" id="fullpage">
    <!-- 屏幕内容 -->
  </full-page>
</template>

<script setup lang="ts">
import { ref } from 'vue'

const fullpage = ref<any>(null)
const currentSection = ref(0)

// 菜单点击处理函数
const goToSection = (sectionIndex: number) => {
  if (fullpage.value && fullpage.value.api) {
    fullpage.value.api.moveTo(sectionIndex + 1)
  }
}

const options = ref({
  navigation: false, // 隐藏默认导航点
  afterLoad: (_origin: any, destination: any) => {
    currentSection.value = destination.index
  }
})
</script>

<style scoped>
.top-nav-menu {
  position: fixed;
  top: 20px;
  left: 20px;
  z-index: 1000;
  display: flex;
  gap: 8px;
  background: rgba(255, 255, 255, 0.95);
  backdrop-filter: blur(10px);
  border-radius: 12px;
  padding: 12px 16px;
  box-shadow: 0 4px 20px rgba(0, 0, 0, 0.1);
}

.nav-item {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 10px 14px;
  border-radius: 8px;
  cursor: pointer;
  transition: all 0.3s ease;
  color: #606266;
}

.nav-item:hover {
  background: rgba(64, 158, 255, 0.1);
  color: #409eff;
}

.nav-item.active {
  background: linear-gradient(135deg, #409eff, #66b3ff);
  color: white;
}
</style>

解决滚动重定向问题

在使用 Vue FullPage.js 时,可能会遇到以下问题:

  1. 页面滚动被 Vue Router 的 scrollBehavior 重定向
  2. 浏览器默认滚动行为与 FullPage.js 冲突
  3. 移动端触摸滚动事件干扰

解决方案

1. 路由配置优化
// router/index.ts
import { createRouter, createWebHistory, type RouterScrollBehavior } from 'vue-router'

const router = createRouter({
  history: createWebHistory(),
  routes: [
    {
      path: '/dashboard',
      name: 'leadershipDashboard',
      component: () => import('@/views/LeadershipDashboard/LeadershipDashboard.vue'),
      meta: { 
        disableScroll: true, // 标记需要禁用滚动的页面
        fullPage: true 
      }
    }
  ],
  scrollBehavior: ((to, from, savedPosition) => {
    // 如果目标页面需要禁用滚动,返回 false
    if (to.meta.disableScroll) {
      return false
    }
    
    // 如果是从全屏页面跳转,重置滚动位置
    if (from.meta.fullPage) {
      return { top: 0, left: 0 }
    }
    
    // 其他情况保持默认行为
    if (savedPosition) {
      return savedPosition
    }
    return { top: 0, left: 0 }
  }) as RouterScrollBehavior
})

export default router

隐藏 右下角 水印

1. CSS 方式隐藏水印
/* 在全局样式文件或组件样式中添加 */
/* 隐藏 fullPage.js 水印 - 方法一:通用选择器 */
.fp-watermark,
.fp-watermark a,
[data-watermark],
.fp-watermark-text,
div[style*="position: fixed"][style*="bottom: 0"][style*="right: 0"] {
  display: none !important;
  visibility: hidden !important;
  opacity: 0 !important;
}

/* 方法二:更精确的选择器 */
div[style*="position: fixed"][style*="bottom: 0"][style*="right: 0"][style*="z-index: 999999"] {
  display: none !important;
  visibility: hidden !important;
  opacity: 0 !important;
}

/* 方法三:针对特定类名 */
.fp-watermark,
.fp-watermark a,
.fp-watermark-text {
  display: none !important;
  visibility: hidden !important;
  opacity: 0 !important;
  pointer-events: none !important;
}

常见问题与解决方案

1. 图表不显示问题

问题描述: ECharts 图表在全屏滚动页面中无法正常显示。

解决方案:

// 延迟初始化图表,确保 DOM 元素已渲染
onMounted(() => {
  // 使用 nextTick 确保 DOM 更新完成
  nextTick(() => {
    setTimeout(() => {
      initChart()
    }, 100)
  })
})

// 或者使用 ResizeObserver 监听容器大小变化
const initChartWithObserver = () => {
  if (!chartRef.value) return
  
  const resizeObserver = new ResizeObserver(() => {
    if (chart.value) {
      chart.value.resize()
    }
  })
  
  resizeObserver.observe(chartRef.value)
}

2. 导航菜单层级问题

问题描述: 自定义导航菜单被 FullPage.js 容器遮挡。

解决方案:

/* 确保导航菜单在最上层 */
.top-nav-menu {
  position: fixed !important;
  top: 20px !important;
  left: 20px !important;
  z-index: 9999 !important; /* 高于 FullPage.js 的 z-index */
  background: rgba(255, 255, 255, 0.95) !important;
  backdrop-filter: blur(10px) !important;
}

/* 确保 FullPage.js 容器不会覆盖导航 */
:deep(#fullpage) {
  z-index: 1 !important;
}

3. 移动端触摸滚动问题

问题描述: 移动端触摸滚动与 FullPage.js 冲突。

解决方案:

// 移动端触摸事件处理
const handleTouchStart = (e: TouchEvent) => {
  // 记录触摸开始位置
  touchStartY = e.touches[0].clientY
}

const handleTouchMove = (e: TouchEvent) => {
  // 防止默认滚动行为
  e.preventDefault()
}

// 在组件中添加触摸事件监听
onMounted(() => {
  document.addEventListener('touchstart', handleTouchStart, { passive: true })
  document.addEventListener('touchmove', handleTouchMove, { passive: false })
})

4. 内存泄漏问题

问题描述: 组件销毁后 FullPage.js 实例未正确清理。

解决方案:

onBeforeUnmount(() => {
  // 1. 移除事件监听器
  window.removeEventListener('resize', handleResize)
  document.removeEventListener('wheel', preventScroll)
  document.removeEventListener('touchmove', preventScroll)
  
  // 2. 销毁 FullPage.js 实例
  if (fullpage.value && fullpage.value.api) {
    fullpage.value.api.destroy('all')
  }
  
  // 3. 清理图表实例
  if (chart.value) {
    chart.value.dispose()
  }
  
  // 4. 清理观察器
  if (watermarkObserver) {
    watermarkObserver.disconnect()
  }
})

5. 性能优化问题

问题描述: 大量数据或复杂图表导致页面卡顿。

解决方案:

// 使用虚拟滚动或分页加载
const useVirtualScroll = () => {
  const visibleItems = ref(10)
  const itemHeight = 50
  
  const getVisibleData = (data: any[]) => {
    return data.slice(0, visibleItems.value)
  }
  
  const loadMore = () => {
    visibleItems.value += 10
  }
  
  return { visibleItems, getVisibleData, loadMore }
}

// 图表懒加载
const useLazyChart = () => {
  const isChartVisible = ref(false)
  
  const observer = new IntersectionObserver((entries) => {
    entries.forEach(entry => {
      if (entry.isIntersecting) {
        isChartVisible.value = true
        observer.disconnect()
      }
    })
  })
  
  return { isChartVisible, observer }
}