vue 一个简单的项目 之三 详情页面 step6 动态获取详情页面数据 与 跳转页面滚动条设置

本文介绍如何在Vue项目中实现详情页面的数据动态获取,通过axios请求API,并展示数据加载和组件更新的过程。

上篇,实现了递归组件。本篇,实现详情页面的数据动态获取。

先新建一个分支 detail-ajax,pull 下来,在新分支上写代码。

其实,动态获取数据,之前就做过。使用axios, 就可以了。

父组件 Detail.vue 代码如下。

<template>
  <div>
    <detail-banner
      :sightName="sightName"
      :bannerImg="bannerImg"
      :bannerImgs="gallaryImgs"
    ></detail-banner>
    <detail-header></detail-header>
    <div class="content">
      <detail-list :list="list"></detail-list>
    </div>
  </div>
</template>

<script>
import DetailHeader from './components/Header'
import DetailBanner from './components/Banner'
import DetailList from './components/List'
import axios from 'axios'
export default {
  name: 'Detail',
  components: {
    DetailBanner,
    DetailHeader,
    DetailList
  },
  data () {
    return {
      sightName: '',
      bannerImg: '',
      gallaryImgs: [],
      categoryList: [],
      list: []
    }
  },
  methods: {
    getDetailInfo () {
      // axios.get('/api/detail.json?id=' + this.$route.params.id)
      axios.get('/api/detail.json', {
        params: {
          id: this.$route.params.id
        }
      }).then(this.handleGetDataSucc)
    },
    handleGetDataSucc (res) {
      res = res.data
      if (res.ret && res.data) {
        const data = res.data
        console.log(data)
        this.sightName = data.sightName
        this.bannerImg = data.bannerImg
        this.gallaryImgs = data.gallaryImgs
        this.categoryList = data.categoryList
        this.list = data.categoryList
      }
    }
  },
  mounted () {
    this.getDetailInfo()
  }
}
</script>

<style lang="stylus" scoped>
  .content
    height: 50rem
</style>

Banner.vue 代码如下。

<template>
  <div>
    <detail-banner
      :sightName="sightName"
      :bannerImg="bannerImg"
      :bannerImgs="gallaryImgs"
    ></detail-banner>
    <detail-header></detail-header>
    <div class="content">
      <detail-list :list="list"></detail-list>
    </div>
  </div>
</template>

<script>
import DetailHeader from './components/Header'
import DetailBanner from './components/Banner'
import DetailList from './components/List'
import axios from 'axios'
export default {
  name: 'Detail',
  components: {
    DetailBanner,
    DetailHeader,
    DetailList
  },
  data () {
    return {
      sightName: '',
      bannerImg: '',
      gallaryImgs: [],
      categoryList: [],
      list: []
    }
  },
  methods: {
    getDetailInfo () {
      // axios.get('/api/detail.json?id=' + this.$route.params.id)
      axios.get('/api/detail.json', {
        params: {
          id: this.$route.params.id
        }
      }).then(this.handleGetDataSucc)
    },
    handleGetDataSucc (res) {
      res = res.data
      if (res.ret && res.data) {
        const data = res.data
        console.log(data)
        this.sightName = data.sightName
        this.bannerImg = data.bannerImg
        this.gallaryImgs = data.gallaryImgs
        this.categoryList = data.categoryList
        this.list = data.categoryList
      }
    }
  },
  mounted () {
    this.getDetailInfo()
  }
}
</script>

<style lang="stylus" scoped>
  .content
    height: 50rem
</style>

有一点,就是 在App.vue 中每个路由都加了 keep-alive 标签。如果我们不想要详情页面加上这个标签,一种方法,是之前使用activated 钩子函数,还有一种方法,如下。App.vue 代码。

<template>
  <div id="app">
    <keep-alive exclude="Detail">
      <router-view/>
    </keep-alive>
  </div>
</template>

最后,还有一个问题,当一个页面,滚动到中部,跳转到另一个页面,滚动条的距离会保持过去。这个也很好解决。查看vue-router 文件的滚动行为。

然后将router目录下的 index.js 添加一段代码,即可。如下。

import Vue from 'vue'
import Router from 'vue-router'
import Home from '@/pages/home/Home.vue'
import City from '@/pages/city/City.vue'
import Detail from '@/pages/detail/Detail.vue'
Vue.use(Router)

export default new Router({
  routes: [
    {
      path: '/',
      name: 'Home',
      component: Home
    }, {
      path: '/city',
      name: 'City',
      component: City
    }, {
      path: '/detail/:id',
      name: 'Detail',
      component: Detail
    }
  ],
  scrollBehavior (to, from, savedPosition) {
    return { x: 0, y: 0 }
  }
})

Done!

可以提交合并了!

<think>我们之前讨论了一个基于Vue2的滚动实现,现在用户询问如何在Vue3中实现无限循环滚动或轮播效果。根据引用[1]中提到的vue3-seamless-scroll组件,我们可以直接使用这个现成的组件来实现,因为它支持上下左右无缝滚动,并且适用于Vue3。实现步骤:1.安装组件:`npminstallvue3-seamless-scroll--save`2.在组件中引入并使用3.配置组件参数另外,我们也可以自己实现一个简单的循环滚动,但考虑到稳定性和功能丰富性,推荐使用组件。下面提供两种方案:方案一:使用vue3-seamless-scroll组件(推荐)方案二:自己实现一个简单的循环滚动(基于Vue3的CompositionAPI)由于用户之前的问题中已经有一个Vue2的实现,我们可以将其升级到Vue3,并结合CompositionAPI自己实现。用户要求实现循环滚动数据,我们先给出方案一的示例,再给出方案二(自定义实现)的示例。方案一:使用vue3-seamless-scroll组件示例代码:```vue<template><vue3-seamless-scroll:list="listData":step="0.5"hoverpauseOnHover><ul><liv-for="(item,index)inlistData":key="index">{{item}}</li></ul></vue3-seamless-scroll></template><scriptsetup>import{Vue3SeamlessScroll}from"vue3-seamless-scroll";constlistData=["数据项1","数据项2","数据项3","数据项4","数据项5","数据6",];</script><style>ul{list-style:none;padding:0;margin:0;}li{height:30px;line-height:30px;}</style>```方案二:自定义实现(基于Vue3CompositionAPI)我们可以将之前Vue2的代码转换为Vue3,并做一些优化。示例代码:```vue<template><divclass="scroll-container"@mouseenter="pauseScroll"@mouseleave="resumeScroll"><divclass="scroll-content":style="{transform:`translateY(${position}px)`}"><divv-for="(item,index)invisibleItems":key="index"class="scroll-item">{{item}}</div></div></div></template><scriptsetup>import{ref,computed,onMounted,onUnmounted}from'vue';constitems=ref(['数据项1','数据项2','数据项3','数据项4','数据项5','数据6']);constposition=ref(0);constspeed=ref(1);//滚动速度(像素/帧)constinterval=ref(50);//滚动间隔(毫秒)constcontainerHeight=ref(0);//容器高度constitemHeight=ref(30);//单条数据高度lettimer=null;//计算属性:克隆数据以实现无缝滚动constvisibleItems=computed(()=>{//克隆足够的数据来填充可视区域,这里克隆原始数据两次(或根据需要克隆足够的数据)//由于我们每次只滚动一条,为了无缝,至少需要克隆一份return[...items.value,...items.value];});//初始化滚动functioninitScroll(){//获取容器高度,如果容器高度是固定的,也可以直接设置constcontainer=document.querySelector('.scroll-container');containerHeight.value=container.clientHeight;timer=setInterval(()=>{position.value-=speed.value;//当滚动完一个原始列表高度后,重置位置(减去原始列表高度)实现无缝if(Math.abs(position.value)>=items.value.length*itemHeight.value){//重置位置到0,但要注意这时候实际上已经滚动完原始列表,我们立即重置到0并继续滚动,但为了无缝,跳转瞬间用户不可见//为了避免跳转的视觉差,我们在跳转的同时将位置重置为0,并加上已经滚动过的那一点(因为setInterval可能不会正好在整数位置)//更好的做法:在跳转前瞬间,我们已经显示的是克隆的数据,然后重置位置到0(同时减去原始列表高度),这样就没有视觉跳跃//这里我们直接重置到0,由于我们克隆了数据,所以跳回0的时候内容是一样的position.value=0;}},interval.value);}functionpauseScroll(){if(timer){clearInterval(timer);timer=null;}}functionresumeScroll(){if(!timer){initScroll();}}onMounted(()=>{initScroll();});onUnmounted(()=>{pauseScroll();});</script><style>.scroll-container{height:120px;/*显示区域高度*/overflow:hidden;position:relative;border:1pxsolid#eee;}.scroll-content{position:absolute;width:100%;}.scroll-item{height:30px;line-height:30px;padding:015px;border-bottom:1pxsolid#f0f0f0;}</style>```注意:自定义实现中,我们使用两层相同的数组来实现无缝滚动。在滚动完一个原始列表后,立即重置位置到0(此时由于克隆的第二份数据第一份相同,所以视觉上无缝)。两种方案的比较:-组件方案:功能强大,配置丰富,支持水平和垂直滚动,支持单步滚动等。-自定义方案:轻量,但需要自己处理一些细节(比如跳转瞬间的平滑)。推荐使用组件方案,因为它已经处理了很多边界情况。如果只需要简单滚动,自定义方案也足够。相关问题:1.如何在水平方向实现循环滚动?2.如何调整滚动速度以适应不同内容?3.当滚动数据量很大时,如何优化性能?4.如何实现触摸设备的滚动控制?</think> 在 Vue3 中实现循环滚动效果,推荐以下两种高效方案: ### 方案一:使用专业组件 vue3-seamless-scroll (推荐) ```bash npm install vue3-seamless-scroll --save ``` ```vue <template> <div class="container"> <vue3-seamless-scroll :list="items" direction="up" :hover="true" :step="0.5" class="scroll-wrap" > <div v-for="(item, index) in items" :key="index" class="item"> {{ item }} </div> </vue3-seamless-scroll> </div> </template> <script setup> import { Vue3SeamlessScroll } from 'vue3-seamless-scroll' const items = ref([ '新闻内容 1', '重要通知:系统升级', '市场动态分析报告', '行业峰会即将举办', '新产品发布预告' ]) </script> <style> .container { height: 300px; } .scroll-wrap { height: 100%; overflow: hidden; } .item { height: 60px; line-height: 60px; padding: 0 15px; border-bottom: 1px solid #eee; } </style> ``` #### 优势 1. 支持**四向滚动**:通过`direction`参数控制方向(up/down/left/right)[^1] 2. **响应式设计**:自动适应不同屏幕尺寸 3. **悬停暂停**:开启`:hover="true"`实现鼠标悬停控制 4. **平滑滚动**:通过`:step`参数控制滚动速度(值越小越平滑) --- ### 方案二:自定义实现(Composition API) ```vue <template> <div class="scroll-container" ref="container" @mouseenter="pauseScroll" @mouseleave="startScroll" > <div class="scroll-content" :style="{ transform: `translateY(${position}px)` }" ref="content" > <div v-for="(item, index) in visibleItems" :key="index" class="scroll-item"> {{ item }} </div> </div> </div> </template> <script setup> import { ref, computed, onMounted, onUnmounted } from 'vue' // 原始数据 const items = ref(['数据1', '数据2', '数据3', '数据4', '数据5']) // DOM元素 const container = ref(null) const content = ref(null) // 滚动控制 const position = ref(0) const speed = ref(1) const frameRate = 60 let animationId = null let containerHeight = 0 // 计算克隆后的可见项 const visibleItems = computed(() => { return [...items.value, ...items.value.slice(0, Math.ceil(containerHeight / 50) + 1)] }) onMounted(() => { // 初始化容器高度 containerHeight = container.value.clientHeight startScroll() }) onUnmounted(() => { pauseScroll() }) // 开始滚动 function startScroll() { if (animationId) return const animate = () => { position.value -= speed.value // 重置位置实现无缝衔接 if (Math.abs(position.value) >= items.value.length * 50) { position.value = 0 } animationId = requestAnimationFrame(animate) } animationId = requestAnimationFrame(animate) } // 暂停滚动 function pauseScroll() { if (animationId) { cancelAnimationFrame(animationId) animationId = null } } </script> <style> .scroll-container { height: 200px; overflow: hidden; position: relative; border: 1px solid #eee; } .scroll-content { position: absolute; width: 100%; will-change: transform; /* 优化性能 */ } .scroll-item { height: 50px; line-height: 50px; padding: 0 15px; border-bottom: 1px solid #f0f0f0; } </style> ``` #### 关键优化 1. **使用`requestAnimationFrame`替代setInterval** - 提供更流畅的动画体验 ```js // 传统方式 setInterval(() => {...}, 16) // 优化方式 const animate = () => { ... requestAnimationFrame(animate) } ``` 2. **will-change属性** - 提前通知浏览器元素会变化,优化渲染性能 3. **响应式容器尺寸** - 自动计算容器高度适应不同屏幕 ```js containerHeight = container.value.clientHeight ``` ### 选择建议 | 场景 | 推荐方案 | 理由 | |------|----------|------| | 生产环境 | vue3-seamless-scroll | 功能完善,支持触摸事件和自适应 | | 简单需求 | 自定义实现 | 轻量级,无额外依赖 | | 复杂交互 | vue3-seamless-scroll | 内置丰富的配置选项和回调方法 | --- ### 使用技巧 1. **速度适配公式**:滚动速度可按屏幕尺寸动态调整 $$speed = \frac{baseSpeed \times screenHeight}{1080}$$ ```js // 在组件中 const baseSpeed = 1 // 1080p基准速度 const speed = ref(baseSpeed * window.innerHeight / 1080) ``` 2. **大数据量优化**:使用虚拟滚动技术 ```vue <vue3-seamless-scroll :list="largeData" :virtual="true" :item-size="50" /> ``` 3. **触摸事件支持**:给自定义组件添加触摸事件 ```js // 在onMounted中添加 container.value.addEventListener('touchstart', pauseScroll) container.value.addEventListener('touchend', startScroll) ``` [^1]: vue3-seamless-scroll 官方文档
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值