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

项目文件下载地址

实际效果如下:

一、滚动屏幕元素渐入

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

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

npm install animate.css --save

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

2、main.js中引入animate.css

import 'animate.css';

uniapp vue3 h5,微信小程序滚动屏幕元素渐入动画&自定义导航栏_第2张图片
3、app.vue中添加全局样式兼容微信小程序
项目中我已将改代码放入base.scss文件中

//animate.css 兼容小程序
page {
--animate-duration: 1s;
--animate-delay: 1s;
--animate-repeat: 1;
}

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

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

<template>
	<view class="home-wrap">
		//
			<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>
		//
	</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>

二、uniapp自定义头部导航栏

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

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

"globalStyle": {
		"navigationStyle": "custom"
	},

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

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>

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

import MainLayout from "./layout/index.vue"
//vue2
Vue.component("main-layout", MainLayout);
//vue3
app.component("main-layout", MainLayout);

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

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

<main-layout title="首页" back>
			 <template v-slot:titleRight>
				<text>右插槽</text>
			  </template>
			<text>页面内容</text>
		</main-layout>

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

你可能感兴趣的:(uniapp,微信小程序,vue,微信小程序,uni-app,javascript)