uni.pageScrollTo滚动时出现抖动问题

文章探讨了uni-app中页面滚动到顶部的两种方法:使用scroo-view标签和uni.pageScrollTo。通过实践,发现uni.pageScrollTo在部分机型上存在抖动、下拉刷新感及无效滚动的问题,并提出将duration置为0的解决方案。建议优先使用scroll-view以减少bug。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

uni-app中,将页面滚动到顶部,有两种方式:

 

一、使用scroo-view标签中的@scrolltoupper实现

 

二:使用uni.pageScrollTo实现

 

近期在做视频类的一个重播功能,要求点击“重播”按钮后页面能够回到顶部(由于视频在页面的顶部,这样点击“重播”后不会跳到视频之外的其他地方),用uni.pageScrollTo来实现,但是发现三个问题:

1>部分机型会出现抖动;

2>在触发uni.pageScrollTo之后,会先滚动到最顶端,触发刷新,再从最顶端滚动到我们需要的位置。就是有个下拉刷新的感觉,体验不是很好!某前不知道是不是所有的机型是这样,未测试,只至少我的安卓oppo手机上是这样的!

3》部分机型有时无效,没回到顶部去~

     后续发现将duration置为0,即可解决上面三个问题!

建议还是用scroll-view来实现,bug相对少些~

 

ps:微信小程序中解决方法也类同~

<think>我们正在讨论的是在UniApp中实现类似同花顺成交明细页面新增数据带有向下滚动动画的效果。根据用户需求,我们需要实现一个列表,当新数据添加,列表自动向下滚动以显示最新数据,并且带有平滑的滚动动画。在UniApp中,我们可以使用`<scroll-view>`组件来实现滚动区域,并通过设置其`scroll-top`属性来控制滚动位置。但是,为了实现平滑滚动,我们可以使用CSS的`transition`属性或者使用UniApp的`createAnimation`API来创建动画。然而,考虑到新增数据自动滚动到底部的需求,实际上更常见的做法是使用`scroll-view`组件的`scroll-into-view`属性,通过指定子元素的id来滚动到该元素。同,我们可以结合CSS过渡效果来实现平滑滚动。另一种方法是使用`scroll-view`的`scroll-top`属性,并通过计算新数据加入后的滚动位置,然后通过动画改变`scroll-top`的值。但是,注意:在UniApp中,直接修改`scroll-top`可能会引起页面抖动,而且需要计算每个列表项的高度,这样较为复杂。因此,使用`scroll-into-view`可能是更简单直接的方法。步骤:1.使用`<scroll-view>`组件,并设置`scroll-y`为`true`(允许纵向滚动)。2.在数据新增,将`scroll-into-view`属性设置为最新数据的id(例如,每条数据都有一个唯一的id,并且设置对应的视图id)。3.为了有动画效果,我们可以给`scroll-view`设置`scroll-with-animation`属性,这样滚动会带有平滑动画。但是,这里有一个问题:新增数据,我们想要的效果是列表向下滚动(即滚动到底部),因此我们可以将最新的一条数据的id赋值给`scroll-into-view`,这样就会滚动到该元素。然而,当数据量很大,为每条数据设置一个唯一的id并动态改变`scroll-into-view`的值可能会造成性能问题。另外,如果最新数据还没有渲染到页面上,设置`scroll-into-view`可能不会立即生效。因此,另一种做法是使用`scrollTo`方法,通过组件的ref来调用。我们可以通过`this.$refs.scrollView.scrollTo({top:新的滚动位置,duration:动画间})`来实现。但是,在UniApp中,我们也可以使用`uni.pageScrollTo`,但它用于整个页面的滚动。对于局部滚动区域,我们只能使用`scroll-view`的方法。具体实现:方案一:使用`scroll-into-view`-在模板中,给`scroll-view`设置`scroll-into-view`属性(绑定一个变量`scrollInto`),并设置`scroll-with-animation`为`true`。-每条数据用`<view:id="'item'+index">`来设置id(注意:id不能以数字开头)。-当新增数据,将`scrollInto`设置为最新一条数据的id(例如,最后一条数据的id为`'item'+(list.length-1)`),这样就会滚动到最后一条。-注意:每次滚动后,需要将`scrollInto`重置为空字符串,否则下次新增相同id的数据不会触发滚动(因为值没变)。但这样处理可能会导致连续新增滚动失效,因此我们可以在设置id后,用`$nextTick`来重置,并在下一次新增再设置新的id。方案二:使用`scrollTo`方法-给`scroll-view`设置ref,例如`ref="scrollView"`。-在新增数据后,使用`this.$nextTick`确保DOM更新,然后调用`this.$refs.scrollView.scrollTo({top:10000,duration:300})`(将top设置一个很大的值,确保滚动到底部)。但是,我们无法直接知道滚动区域的高度,所以更好的做法是计算滚动内容的高度减去滚动可视区域的高度,得到最大滚动位置。或者直接设置top为99999,然后它会自动滚动到最大值(即底部)。-在`scroll-view`组件中,`scrollTo`方法需要传递一个对象,包含`top`和`duration`(动画间)。由于方案二不需要为每个列表项设置id,且实现起来更简单,因此我们选择方案二。具体代码步骤:1.模板部分:```html<template><view><scroll-viewref="scrollView"scroll-y="true":style="{height:scrollHeight+'px'}"><viewv-for="(item,index)inlist":key="index"><!--每条数据的展示--></view></scroll-view></view></template>```2.在data中定义列表数据`list`和滚动区域的高度`scrollHeight`(可以设置为屏幕剩余高度)。3.在mounted中,可以计算`scrollHeight`(例如,整个屏幕高度减去其他固定区域的高度)。4.当新增数据:```javascriptaddNewData(){//假设新数据为newItemthis.list.push(newItem);this.$nextTick(()=>{this.$refs.scrollView.scrollTo({top:99999,//设置一个足够大的值,确保滚动到底部duration:300//300ms的动画});});}```注意:在UniApp中,使用`scrollTo`方法需要确保`scroll-view`组件已经初始化完成,并且`$refs.scrollView`指向正确。但是,在UniApp的`scroll-view`组件文档中,并没有直接提供`scrollTo`方法的说明,实际上,在微信小程序中,`scroll-view`有`scrollTo`方法,而UniApp也支持。但为了确保兼容性,我们可以查看UniApp的文档。根据UniApp官方文档(https://uniapp.dcloud.net.cn/component/scroll-view.html),`scroll-view`组件支持`@scroll`事件,但没有明确说明有`scrollTo`方法。但实际在微信小程序中,我们可以通过创建`selectorQuery`来获取节点并调用`scrollTo`方法,或者使用组件的`scrollIntoView`方法(对应`scroll-into-view`属性)。因此,如果直接使用`this.$refs.scrollView.scrollTo`在H5端可能有效,但在小程序端可能无效。所以,我们需要使用更兼容的方式。兼容方案:使用`uni.createSelectorQuery()`来获取`scroll-view`的节点,然后调用`scrollTo`方法。示例代码:```javascriptaddNewData(){this.list.push(newItem);this.$nextTick(()=>{constquery=uni.createSelectorQuery().in(this);query.select('.scroll-view').node(res=>{if(res&&res.node){res.node.scrollTo({top:99999,duration:300});}}).exec();});}```但是,注意:在小程序中,`scroll-view`是一个原生组件,使用`createSelectorQuery`获取到的是WebView上下文中的节点,可能无法直接调用`scrollTo`方法。因此,回到方案一:使用`scroll-into-view`可能是更安全且兼容性更好的方式。方案一具体实现:1.在data中定义`scrollInto`,初始值为空字符串。2.在模板中,给`scroll-view`设置`scroll-into-view`和`scroll-with-animation`:```html<scroll-viewscroll-y="true":scroll-into-view="scrollInto"scroll-with-animation:style="{height:scrollHeight+'px'}"><viewv-for="(item,index)inlist":key="index":id="'item'+index"><!--内容--></view></scroll-view>```3.在新增数据:```javascriptaddNewData(){this.list.push(newItem);//设置滚动到最新的一条(即最后一条)this.scrollInto='item'+(this.list.length-1);//在滚动完成后,重置scrollInto,以便下一次新增可以再次触发//注意:不能立即重置,否则下次相同id不会触发。我们可以设置一个定器,或者在下一次新增前再设置。//但是,如果连续新增,我们希望在每次新增后都滚动到底部,那么每次都要设置不同的id(因为index在变),所以重置不是必须的。//但是,如果新增后index没有变化(比如删除中间数据再新增?)则可能不会触发,因此我们可以在设置后,在$nextTick中重置,然后下次新增再设置新的id。this.$nextTick(()=>{this.scrollInto='';//重置});}```注意:当重置为空后,下一次新增,我们设置`scrollInto`为新的id(例如,从0到1),由于之前是空,现在设置成新的id,就会触发滚动。但是,如果在两次新增之间用户手动滚动了位置,那么重置后用户的位置不会变,而新增又会滚动到底部。这符合我们的需求:即每次新增数据,自动滚动到底部。因此,我们选择方案一。另外,注意:id不能以数字开头,所以我们用`'item'+index`,这样是合法的。总结步骤:1.在data中定义:```javascriptdata(){return{list:[],//列表数据scrollInto:'',//滚动到的idscrollHeight:0//滚动区域高度}}```2.在模板中:```html<scroll-viewscroll-y="true":scroll-into-view="scrollInto"scroll-with-animation:style="{height:scrollHeight+'px'}"class="scroll-view"><viewv-for="(item,index)inlist":key="index":id="'item'+index"><!--具体内容,例如成交明细--><text>{{item.time}}</text><text>{{item.price}}</text><text>{{item.volume}}</text></view></scroll-view>```3.在mounted中,计算滚动区域的高度(如果需要):```javascriptonLoad(){//使用uni.getSystemInfo获取屏幕高度,然后减去其他固定区域的高度uni.getSystemInfo({success:(res)=>{//假设顶部有一个标题栏,高度为50px,这里假设没有其他固定区域,则直接使用屏幕高度//如果有其他固定区域,需要减去this.scrollHeight=res.windowHeight-50;//50是示例,具体根据实际情况}});}```4.新增数据的方法:```javascriptmethods:{addNewData(newItem){this.list.push(newItem);constnewIndex=this.list.length-1;this.scrollInto=`item${newIndex}`;//重置,以便下次可以再次触发this.$nextTick(()=>{this.scrollInto='';});}}```5.模拟新增数据(例如,定添加):```javascript//在某个地方,比如mounted中,模拟定新增setInterval(()=>{constnewItem={time:newDate().toLocaleTimeString(),price:'10.00',volume:'100'};this.addNewData(newItem);},1000);```这样,每新增一条数据,就会自动滚动到该条数据的位置(即底部),并且有平滑的滚动动画。注意事项:-如果列表项的高度是固定的,那么滚动效果会很平滑。如果高度不固定,可能会导致滚动位置不准确。-滚动过程中,如果用户进行交互,可能会打断滚动动画。但符合预期。以上就是在UniApp中实现列表新数据添加自动向下滚动动画效果的方法。引用说明:在实现滚动动画,我们参考了UniApp的`scroll-view`组件的文档[^1]。根据用户之前的问题,我们参考了站内引用中关于UniApp实现订单列表和标签切换的内容[^1],以及同花顺自动化交易中关于页面交互的内容[^3],但本实现主要基于UniApp的组件特性。相关问题:1.UniApp中,如何实现滚动到指定位置?2.除了`scroll-view`,还有哪些方法可以实现局部滚动?3.如何优化大量数据列表的滚动性能?</think>### 在UniApp中实现列表新数据添加自动向下滚动动画效果(同花顺成交明细案例) 在UniApp中实现类似同花顺成交明细的新数据自动滚动效果,可通过以下步骤实现: #### 核心实现方案 ```vue <template> <!-- 滚动区域容器 --> <scroll-view scroll-y :scroll-top="scrollTop" :scroll-with-animation="true" :style="{height: `${scrollHeight}px`}" @scroll="onScroll" ref="scrollView" > <!-- 动态渲染的列表 --> <view v-for="(item, index) in tradeList" :key="index" class="trade-item" :class="{'new-item': index === tradeList.length - 1}" > <text>{{ item.time }}</text> <text :class="item.type === 'buy' ? 'buy-color' : 'sell-color'"> {{ item.price }} </text> <text>{{ item.volume }}手</text> </view> </scroll-view> </template> <script> export default { data() { return { tradeList: [], // 成交数据列表 scrollTop: 0, // 滚动位置 scrollHeight: 600, // 滚动区域高度 maxScrollTop: 0, // 最大滚动位置 isUserScroll: false, // 是否用户手动滚动 }; }, mounted() { // 初始化滚动区域高度(根据屏幕计算) this.calcScrollHeight(); // 模拟实数据更新 setInterval(this.addNewTradeData, 1000); }, methods: { // 计算滚动区域高度 calcScrollHeight() { uni.getSystemInfo({ success: (res) => { this.scrollHeight = res.windowHeight - 50; // 减去顶部导航栏高度 } }); }, // 添加新的成交数据 addNewTradeData() { const newData = { time: new Date().toLocaleTimeString(), price: (Math.random() * 10).toFixed(2), volume: Math.floor(Math.random() * 100) + 1, type: Math.random() > 0.5 ? 'buy' : 'sell' }; this.tradeList = [...this.tradeList, newData]; // 自动滚动逻辑 if (!this.isUserScroll) { this.$nextTick(() => { // 计算新滚动位置(确保在底部) const query = uni.createSelectorQuery().in(this); query.select('.scroll-view').boundingClientRect(); query.selectAll('.trade-item').boundingClientRect(); query.exec(res => { const containerHeight = res[0].height; const itemsHeight = res[1].reduce((sum, item) => sum + item.height, 0); this.scrollTop = itemsHeight - containerHeight + 20; // +20像素缓冲 }); }); } }, // 监听用户滚动事件 onScroll(e) { const { scrollTop, scrollHeight } = e.detail; this.maxScrollTop = scrollHeight - this.scrollHeight; // 用户滚动到顶部附近暂停自动滚动 this.isUserScroll = scrollTop < this.maxScrollTop - 100; } } }; </script> <style> .scroll-view { background-color: #f5f5f5; } .trade-item { display: flex; justify-content: space-between; padding: 12rpx 20rpx; border-bottom: 1rpx solid #eee; transition: all 0.5s; } .new-item { background-color: rgba(0, 255, 0, 0.1); /* 新项高亮动画 */ animation: highlight 1s; } .buy-color { color: #e74c3c; } /* 买入红色 */ .sell-color { color: #2ecc71; } /* 卖出绿色 */ @keyframes highlight { 0% { background-color: rgba(0, 255, 0, 0.5); } 100% { background-color: transparent; } } </style> ``` #### 关键实现原理 1. **滚动控制**: - 使用`scroll-view`组件的`scroll-top`属性和`scroll-with-animation`实现平滑滚动 - 通过计算内容高度与容器高度的差值确定滚动位置 2. **新数据动画**: - 通过CSS `animation`实现新增项的背景高亮过渡效果 - 使用`:class`动态绑定`new-item`类标识最新项 3. **智能滚动判断**: - 当用户手动向上查看历史记录,暂停自动滚动 - 当用户回到列表底部,恢复自动滚动 4. **性能优化**: - 使用`$nextTick`确保DOM更新后执行滚动计算 - 通过`createSelectorQuery`精确获取元素尺寸 #### 同花顺特色效果实现 ```javascript // 扩展:实现同花顺式价格跳动动画 addNewTradeData() { // ...数据生成逻辑同上... // 价格跳动动画 if (this.tradeList.length > 0) { const lastItem = this.tradeList[this.tradeList.length - 1]; const priceChange = newData.price - lastItem.price; if (priceChange !== 0) { newData.animateClass = priceChange > 0 ? 'price-up' : 'price-down'; setTimeout(() => { newData.animateClass = ''; }, 1000); } } // ...滚动逻辑同上... } ``` ```css /* 价格跳动动画 */ .price-up { animation: priceUp 0.8s; } .price-down { animation: priceDown 0.8s; } @keyframes priceUp { 0% { color: #000; transform: scale(1); } 50% { color: #e74c3c; transform: scale(1.2); } 100% { color: #e74c3c; transform: scale(1); } } @keyframes priceDown { 0% { color: #000; transform: scale(1); } 50% { color: #2ecc71; transform: scale(0.8); } 100% { color: #2ecc71; transform: scale(1); } } ``` #### 注意事项 1. **性能优化**: - 大数据量使用`虚拟列表`技术 - 使用`throttle`限制滚动事件频率 - 避免频繁操作DOM 2. **多端适配**: - 通过`uni.getSystemInfo`动态计算高度 - 使用`rpx`单位确保各端样式一致 - 测试iOS/Android滚动行为差异 3. **数据更新策略**: - WebSocket实数据接入 - 数据分页加载历史记录 - 自动清理旧数据(如保留最近100条) > 该实现参考了同花顺客户端的交互设计原则[^3],结合UniApp的跨平台能力[^1],在保证性能的同实现了流畅的数据更新动画效果。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值