当前位置:   article > 正文

uniapp vue3 h5,微信小程序滚动屏幕元素渐入动画&自定义导航栏_小程序滚动渐变导航栏

小程序滚动渐变导航栏

项目文件下载地址

实际效果如下:
在这里插入图片描述

一、滚动屏幕元素渐入

注意事项:
animate.css需要添加样式兼容微信小程序;
微信小程序滚动时boundingClientRect获取不到标签信息

1、HBuilderX打开uniapp创建的vue3项目,在编辑器下方打开终端输入npm install animate.css --save 安装模块
animate.css官网地址
参考官方文档安装使用animate.css

npm install animate.css --save
  • 1

在这里插入图片描述

2、main.js中引入animate.css

import 'animate.css';
  • 1

在这里插入图片描述
3、app.vue中添加全局样式兼容微信小程序
项目中我已将改代码放入base.scss文件中

//animate.css 兼容小程序
page {
--animate-duration: 1s;
--animate-delay: 1s;
--animate-repeat: 1;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

在这里插入图片描述

4、根据animate.css官网文档给标签添加动画,然后再通过js监听屏幕滚动当标签出现在屏幕可视区时给标签切换class,页面全部代码如下:
main-layout 是自定义组件,除去即可

<template>
	<view class="home-wrap">
		//<main-layout title="首页">
			<view class="animate-item animate__animated " v-for="(item,index) in domList" :id="'item'+item.id"
				:class="item.show?item.showClass:item.hideClass">{{item.text}}</view>
		//</main-layout>
	</view>
</template>

<script lang="ts">
	import {
		defineComponent,
		computed,
		onMounted,
		watch,
		ref,
		getCurrentInstance,
		reactive,
		nextTick,
		toRefs,
		toRef
	} from 'vue';
	export default {
		setup(props,context){
			//dom节点列表
			let domList: {
				id: String | Number,
				text: String,
				show: Boolean,
				showClass: String,
				hideClass: String,
				siteInfo: Object
			} [] = ref([{
				id: 1,
				text: '1',
				show: true,
				showClass: 'animate__fadeInLeftBig',
				hideClass: 'animate__fadeOutLeftBig',
				siteInfo: {}
			}, {
				id: 2,
				text: '2',
				show: true,
				showClass: 'animate__fadeInRightBig',
				hideClass: 'animate__fadeOutRightBig',
				siteInfo: {}
			}, {
				id: 3,
				text: '3',
				show: true,
				showClass: 'animate__fadeInLeftBig',
				hideClass: 'animate__fadeOutLeftBig',
				siteInfo: {}
			}, {
				id: 4,
				text: '4',
				show: true,
				showClass: 'animate__fadeInRightBig',
				hideClass: 'animate__fadeOutRightBig',
				siteInfo: {}
			}, {
				id: 5,
				text: '5',
				show: true,
				showClass: 'animate__fadeInLeftBig',
				hideClass: 'animate__fadeOutLeftBig',
				siteInfo: {}
			}, {
				id: 6,
				text: '6',
				show: true,
				showClass: 'animate__fadeInRightBig',
				hideClass: 'animate__fadeOutRightBig',
				siteInfo: {}
			}, {
				id: 7,
				text: '7',
				show: true,
				showClass: 'animate__fadeInLeftBig',
				hideClass: 'animate__fadeOutLeftBig',
				siteInfo: {}
			}, {
				id: 8,
				text: '8',
				show: true,
				showClass: 'animate__fadeInRightBig',
				hideClass: 'animate__fadeOutRightBig',
				siteInfo: {}
			}, {
				id: 9,
				text: '9',
				show: true,
				showClass: 'animate__fadeInLeftBig',
				hideClass: 'animate__fadeOutLeftBig',
				siteInfo: {}
			}])
		
			// 获取上下文this
			const instance = getCurrentInstance();
			// 获取屏幕高度
			const sysInfo = uni.getSystemInfoSync();
			// 屏幕滚动防抖定时器
			let scrollTimer = null;
			
			const screenScroll = (): void => {
				//屏幕滚动停止后获取dom节点信息,执行动画
				if (scrollTimer) clearTimeout(scrollTimer);
				scrollTimer = setTimeout(() => {
					domList.value.forEach(async (t, i) => {
						await getNodeInfo('item' + t.id).then(res => {
							domList.value[i].siteInfo = res;
						})
						if (i == domList.value.length - 1) {
							loadAni();
						}
					})
				}, 100)
			
			}
			const getNodeInfo = (id: String): any => {
				// 获取位置信息并返回
				return new Promise(resolve => {
					const query = uni.createSelectorQuery().in(instance);
					query.select('#' + id).boundingClientRect(data => {
						// console.log("得到布局位置信息" + JSON.stringify(data));
						// console.log("节点离页面顶部的距离为" + data.top);
						resolve({
							domInfo: data ? data.height : 100,
							domTop: data ? data.top : 100
						})
					}).exec();
			
				});
			}
			const loadAni = (): void => {
				const screenH: String | Number = sysInfo.screenHeight;
				domList.value.forEach((t, i) => {
					if ((t.siteInfo.domTop > 0) && (t.siteInfo.domTop < screenH)) {
						domList.value[i].show = true;
					} else {
						domList.value[i].show = false;
					}
				})
			}
			onMounted(() => {
				screenScroll();
				
			})
		
			return{
				domList,
				screenScroll
			}
		},
		onPageScroll() {
			this.screenScroll();
			
		},
		onReachBottom() {
		   console.log('bottom')
		}
	}
</script>

<style lang="scss">
	.home-wrap{
		overflow: hidden;
		.animate-item{
			border: 1px solid #bbb;
			margin: 10px 10px 100px;
			text-align: center;
			padding: 10px;
		}
	}
</style>

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176

二、uniapp自定义头部导航栏

在这里插入图片描述

1、pages.json中这只导航栏样式为自定义

"globalStyle": {
		"navigationStyle": "custom"
	},
  • 1
  • 2
  • 3

在这里插入图片描述

2、编写头部组件代码

<template>
	<view class="main-wrap" :style="'padding-top:'+(statusBarHeight+titleBarHeight)+'px;'">
		<view class="head-bar">
			//状态栏占位
			<view class="status-bar" :style="'height:'+statusBarHeight+'px'">
				
			</view>
			<view class="title-bar" :style="'height:'+titleBarHeight+'px'">
			//导航左侧返回键
				<view class="title-bar-left">
					<uni-icons type="back" size="30" v-if="back" @click="backPage"></uni-icons>
				</view>
				//导航栏中间标题
				<view class="title-bar-center">
					{{cTitle}}
				</view>
				//导航栏右侧插槽
				<view class="title-bar-right">
					<slot name="titleRight"></slot>
				</view>
			</view>
		</view>
		//导航栏下方页面内容区域插槽
		<view class="main">
			<slot></slot>
		</view>
		
	</view>
</template>

<script lang="ts">
	import { defineComponent, computed, onMounted, watch,ref,getCurrentInstance,reactive,nextTick ,toRefs} from 'vue'
	export default {
		name:"MainLayout",
		props:{
			title:{
				type:String||Number,
				default:''
			},
			back:{
				type:Boolean,
				default:false
			}
			
		},
		created() {
			this.setHeaderHeight();
		},
		setup(props, context){
			let statusBarHeight = ref<Number>(0);
			let titleBarHeight = ref<Number>(0);
			let tabBarHeight = ref<Number>(60);
			
			
			
			const setHeaderHeight =():void=>{
				uni.getSystemInfo({
					success:e=>{
					 let statusBar = 0  //状态栏高度
					      let customBar = 0  // 状态栏高度 + 导航栏高度  
					      let navbar = 0 // 自定义标题与胶囊对齐高度
					      
					      
					      // #ifdef MP
					      statusBar = e.statusBarHeight
					      customBar = e.statusBarHeight + 45
					      if (e.platform === 'android') {
					        customBar = e.statusBarHeight + 50
					      }
					      // #endif
					      
					      
					      // #ifdef MP-WEIXIN
					      statusBar = e.statusBarHeight
					      const custom = wx.getMenuButtonBoundingClientRect()
					      customBar = custom.bottom + custom.top - e.statusBarHeight
					 
					      navbar = (custom.top - e.statusBarHeight) * 2 + custom.height
					      // #endif
					 
					 
					      // #ifdef MP-ALIPAY
					      statusBar = e.statusBarHeight
					      customBar = e.statusBarHeight + e.titleBarHeight
					      // #endif
					 
					 
					      // #ifdef APP-PLUS
					      console.log('app-plus', e)
					      statusBar = e.statusBarHeight
					      customBar = e.statusBarHeight + 45
					      // #endif
					 
					 
					      // #ifdef H5
					      statusBar = 0
					      customBar = e.statusBarHeight + 45
					      // #endif
						  
						  
						titleBarHeight.value = navbar||customBar;
						statusBarHeight.value = statusBar;
				}
				})
			}
			
			const cTitle = computed({
				get:()=>{
					return props.title ;
					},
				set:()=>{}
			})
			
			const backPage = ():void=>{
				uni.navigateBack({
				    //关闭当前页面,返回上一页面或多级页面。
				    delta:1
				});
			}
			
			return {
				setHeaderHeight,
				statusBarHeight,
				titleBarHeight,
				tabBarHeight,
				cTitle,
				backPage
			}
		}
		
	}
</script>

<style lang="scss">
	//@import "@/styles/base.scss";
	.main-wrap {
		display: block;
		position: relative;
		width:100%;
		
		.head-bar{
			position: fixed;
			top: 0;
			left: 0;
			right: 0;
			z-index:999;
			.status-bar{
				background-color: #fff;
			}
			.title-bar{
				display: flex;
				align-items: center;
				justify-content: space-between;
				background-color: $uni-bg-color-nav;
				.title-bar-left,.title-bar-right{
					width: 50px;
				}
				.title-bar-center{
					white-space: nowrap;
					overflow: hidden;
					text-overflow: ellipsis;
					max-width: calc(100% - 100px);
				}
				
			}
		}
		
		
		
		
	}

</style>

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174

3、 main.js全局引用该组件

import MainLayout from "./layout/index.vue"
//vue2
Vue.component("main-layout", MainLayout);
//vue3
app.component("main-layout", MainLayout);
  • 1
  • 2
  • 3
  • 4
  • 5

在这里插入图片描述

4、页面上直接使用该组件

<main-layout title="首页" back>
			 <template v-slot:titleRight>
				<text>右插槽</text>
			  </template>
			<text>页面内容</text>
		</main-layout>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

结语:有用点赞,无用留言批评

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小小林熬夜学编程/article/detail/246863
推荐阅读
相关标签
  

闽ICP备14008679号