本文实例为大家分享了Vue实现列表滚动过渡动画的具体代码,供大家参考,具体内容如下
效果图
失帧比较严重,在手机上效果更佳。
原理分析
这个滚动页面由两个部分布局(底部固定的Tab页面除外)。一个是顶部的banner轮播,一个是下面的列表。这里的重点是做列表的动画,banner轮播的网上资料很多,请自行查找。
这个动画最重要的是在滚动中实时计算startIndex和endIndex,动画比较简单,就是scale和opacity的变化。向下滚动时,startIndex变小;向上滚动时,endIndex变大时,新露脸的项做该动画。当滚动连起来,就是一个完整的动画了。
涉及的技术
使用better-scroll做滚动以及轮播图
使用create-keyframe-animation做动画控制
实现步骤
1、vue的template部分
注意:由于IOS渲染速度比较快, 必须把没有展现在首屏的页面上的item隐藏掉,即index比startIndex小、比endIndex大的item都应该隐藏,避免页面动画混乱。
endIndex) ? 0 : 1}">{{item.num}}
{{item.name}}
{{item.desc}}
高度预设。用于计算startIndex、endIndex
const AreaItemHeight = 119 // 每一项的高度(这里默认一致,如果不一致请自行修改startIndex、endIndex的计算方式) const MarginBottom = 15 // 列表项的底部边距 const TopHeight = 160 // banner的高度 const BottomHeight = 50 // 底部Tab的高度
监听滚动。并实时计算startIndex、endIndex
scroll (position) {
const scrollY = position.y
if (scrollY < 0) {
// startIndex计算
const currentStartIndex = Math.abs(scrollY) <= TopHeight ? 0 : parseInt((Math.abs(scrollY) - TopHeight) / (AreaItemHeight + MarginBottom))
// endIndex计算
let currentEndIndex = Math.floor((window.innerHeight - (TopHeight + scrollY) - BottomHeight) / (AreaItemHeight + MarginBottom))
if (currentEndIndex > this.areaList.length - 1) {
currentEndIndex = this.areaList.length - 1
}
// 这里使用vue的watch属性监听更好
if (currentStartIndex !== this.startIndex) {
if (currentStartIndex < this.startIndex) {
// 运行动画
this.runAnimation(currentStartIndex)
}
this.startIndex = currentStartIndex
}
// 这里使用vue的watch属性监听更好
if (currentEndIndex !== this.endIndex) {
if (currentEndIndex > this.endIndex) {
this.runAnimation(currentEndIndex)
}
this.endIndex = currentEndIndex
}
}
}
运行动画
runAnimation (index) {
animations.registerAnimation({
name: 'scale',
animation: [
{
scale: 0.5,
opacity: 0
},
{
scale: 1,
opacity: 1
}
],
presets: {
duration: 300,
resetWhenDone: true
}
})
animations.runAnimation(this.$refs['area-' + index], 'scale')
}
完整代码
.vue文件
endIndex) ? 0 : 1}"> {{item.num}}
{{item.name}}
{{item.desc}}
.address-wrapper { .address-content { height: 100%; overflow: hidden; .banner-bg { height: 50px; width: 100%; position: absolute; bottom: -1px; background:-moz-linear-gradient(top, rgba(249, 250, 252, 0.3), rgba(249, 250, 252, 1)); background: -webkit-gradient(linear, 0% 0%, 0% 100%, from(rgba(249, 250, 252, 0.3)), to(rgba(249, 250, 252, 1))); background-image: -webkit-gradient(linear,left bottom,left top,color-start(0, rgba(249, 250, 252, 0.3)),color-stop(1, rgba(249, 250, 252, 1))); } .banner-bg-1 { height: 20px; width: 100%; position: absolute; bottom: 49px; background:-moz-linear-gradient(top, rgba(249, 250, 252, 0), rgba(249, 250, 252, 0.3)); background: -webkit-gradient(linear, 0% 0%, 0% 100%, from(rgba(249, 250, 252, 0)), to(rgba(249, 250, 252, 0.3))); background-image: -webkit-gradient(linear,left bottom,left top,color-start(0, rgba(249, 250, 252, 0)),color-stop(1, rgba(249, 250, 252, 0.3))); } .area-wrapper { transform: translateY(-45px) padding: 0 15px; z-index: 1; .area { margin-bottom: 15px; height: 119px; width: 100%; border-radius: 10px; background-repeat: no-repeat; background-size: cover; box-shadow: 0 0 10px #a4a3a3; display: flex; align-items: flex-end; .content { color: #fff; display: flex; padding-right: 60px; padding-bottom: 15px; line-height: 1.2; .num { bottom: 35px; font-size: 48px; font-weight: 100; padding: 0 15px; display:table-cell; vertical-align:bottom; } .name { font-size: 21px; font-weight: 600; line-height: 1.7; } .desc { font-size: 14px; } } } } } }
本地json文件,请自行修改图片路径
bannerAddress.json
[
{
"id": 1,
"contentId": 111111,
"type": 1,
"thumbUrl": "./static/img/banner/banner_address_1.jpg"
},
{
"id": 2,
"contentId": 111111,
"type": 1,
"thumbUrl": "./static/img/banner/banner_address_2.jpg"
},
{
"id": 3,
"contentId": 111111,
"type": 1,
"thumbUrl": "./static/img/banner/banner_address_3.jpg"
}
]
areaList.json
[
{
"id": "ba062c32fdf611e7ba2d00163e0c27f8",
"name": "凯里",
"desc": "这是凯里哟~",
"num": 17,
"thumbUrl": "./static/img/area/kaili.png"
}, {
"id": "ba5287a7fdf611e7ba2d00163e0c27f8",
"name": "丹寨",
"desc": "这是丹寨哟~",
"num": 8,
"thumbUrl": "./static/img/area/danzai.png"
}, {
"id": "ba9da079fdf611e7ba2d00163e0c27f8",
"name": "麻江",
"desc": "这是麻江哟~",
"num": 12,
"thumbUrl": "./static/img/area/majiang.png"
}, {
"id": "baeb0926fdf611e7ba2d00163e0c27f8",
"name": "黄平",
"desc": "这是黄平哟~",
"num": 7,
"thumbUrl": "./static/img/area/huangping.png"
}, {
"id": "bb357191fdf611e7ba2d00163e0c27f8",
"name": "施秉",
"desc": "这是施秉哟~",
"num": 6,
"thumbUrl": "./static/img/area/shibing.png"
}, {
"id": "bb842d8ffdf611e7ba2d00163e0c27f8",
"name": "镇远",
"desc": "这是镇远哟~",
"num": 3,
"thumbUrl": "./static/img/area/zhenyuan.png"
}, {
"id": "bbce67dffdf611e7ba2d00163e0c27f8",
"name": "岑巩",
"desc": "这是岑巩哟~",
"num": 23,
"thumbUrl": "./static/img/area/cengong.png"
}, {
"id": "bc198ca9fdf611e7ba2d00163e0c27f8",
"name": "三穗",
"desc": "这是三穗哟~",
"num": 66,
"thumbUrl": "./static/img/area/sansui.png"
}, {
"id": "bc64498bfdf611e7ba2d00163e0c27f8",
"name": "天柱",
"desc": "这是天柱哟~",
"num": 128,
"thumbUrl": "./static/img/area/tianzhu.png"
}, {
"id": "bcaf466bfdf611e7ba2d00163e0c27f8",
"name": "锦屏",
"desc": "这是锦屏哟~",
"num": 107,
"thumbUrl": "./static/img/area/jinping.png"
}, {
"id": "bcfa6f1bfdf611e7ba2d00163e0c27f8",
"name": "黎平",
"desc": "这是黎平哟~",
"num": 211,
"thumbUrl": "./static/img/area/liping.png"
}, {
"id": "bd44cca9fdf611e7ba2d00163e0c27f8",
"name": "从江",
"desc": "这是从江哟~",
"num": 17,
"thumbUrl": "./static/img/area/congjiang.png"
}, {
"id": "bd8f5cd4fdf611e7ba2d00163e0c27f8",
"name": "榕江",
"desc": "这是榕江哟~",
"num": 17,
"thumbUrl": "./static/img/area/rongjiang.png"
}, {
"id": "bdda2928fdf611e7ba2d00163e0c27f8",
"name": "雷山",
"desc": "这是雷山哟~",
"num": 17,
"thumbUrl": "./static/img/area/leishan.png"
}, {
"id": "be25afc0fdf611e7ba2d00163e0c27f8",
"name": "台江",
"desc": "这是台江哟~",
"num": 17,
"thumbUrl": "./static/img/area/taijiang.png"
}, {
"id": "be702db5fdf611e7ba2d00163e0c27f8",
"name": "剑河",
"desc": "这是剑河哟~",
"num": 17,
"thumbUrl": "./static/img/area/jianhe.png"
}
]
关于vue.js组件的教程,请大家点击专题vue.js组件学习教程进行学习。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持考高分网。



