【组件封装】uniapp vue3 封装一个自定义下拉刷新组件pullRefresh,带刷新时间和加载动画教程

文章目录

  • 前言
  • 一、实现原理
  • 二、组件样式和功能设计
  • 三、scroll-view 自定义下拉刷新使用回顾
    • 相关属性:
    • 最终版完整代码:


前言

手把手教你封装一个移动端 自定义下拉刷新组件带更新时间和加载动画(PullRefresh),以uniapp vue3为代码示例。

在这里插入图片描述

请添加图片描述

在这里插入图片描述


一、实现原理

基于系统自带组件scroll-view封装,开启组件refresher-enabled属性支持自定义下拉刷新功能。下拉自定义UI容器默认状态下位于页面顶部外不可视区域,下拉时候自定义区域进入页面显示。并通过多个自定义下拉刷新回调函数refresherpulling、refresherrefresh、refresherrestore进行逻辑和UI控制。

二、组件样式和功能设计

请添加图片描述
1、如上述动图所示,下拉未达到阈值提示文字显示下拉可以刷新,到达或超过阈值显示释放立即刷新
2、释放后进入刷新状态,提示文字显示正在刷新,左边出现加载转圈动画,下拉区域卡住不动
3、数据刷新完成后设置更新时间,恢复到初始状态,再次下拉会显示上次更新时间

三、scroll-view 自定义下拉刷新使用回顾

相关属性:

属性名类型默认值说明
refresher-enabledBooleanfalse开启自定义下拉刷新
refresher-thresholdNumber45(单位px)设置自定义下拉刷新阈值
refresher-default-styleString“black”设置自定义下拉刷新默认样式,支持设置 black,white,none,none 表示不使用默认样式
refresher-backgroundString“#FFF”设置自定义下拉刷新区域背景颜色
refresher-triggeredBooleanfalse设置当前下拉刷新状态,true 表示下拉刷新已经被触发,false 表示下拉刷新未被触发
@refresherpullingEventHandle自定义下拉刷新控件被下拉
@refresherrefreshEventHandle自定义下拉刷新被触发
@refresherrestoreEventHandle自定义下拉刷新被复位

上面比较重要一个关系就是下拉松手那一刻下拉高度大于或等于refresher-threshold时(刷新阈值)会触发刷新事件@refresherrefresh

refresher-enabled用来控制下拉区域是否复位,当值从true转变为false才能复位。

分析下拉过程属性值变化和回调函数的触发时机:

1、初始状态refresher-triggered=false
2、 开始下拉@refresherpulling一直持续被触发,下拉松手那一刻当下拉距离大于或等于refresher-threshold(刷新阈值)时,@refresherrefresh 被触发一次,此时设置refresher-triggered=true,下拉区域卡住不复位进入加载中状态,数据加载完成设置refresher-triggered=false,下拉复位,触发@refresherrestore。

按上面描述我们很容易实现一个自定义下拉刷新简易版如下:

pullRefresh.vue

<template>
	<view class="pull-refresh">
		<scroll-view style="height: 100%;" scroll-y refresher-enabled refresher-default-style="none"
			refresher-background="#ffffff" :refresher-threshold="threshold" :refresher-triggered="loading"
			@refresherpulling="onRefresherpulling" @refresherrefresh="onRefresherrefresh"
			@refresherrestore="onRefresherrestore" >
			<view class="main">
				<!-- 下拉提示内容 -->
				<view class="content" :style="{top:`-${threshold}px`,height:`${threshold}px`}">
					<view class="tip-view">
						<view class="text">{{tipText}}</view>
					</view>
				</view>
			</view>
		</scroll-view>
	</view>
</template>

<script setup>
	import {ref} from 'vue'
	
	//拉刷新阈值
	const threshold=ref(80)

	//是否正在刷新(加载数据)
	const loading = ref(false)
	//提示文字
	const tipText = ref('下拉可以刷新')

	//控件被下拉触发回调
	const onRefresherpulling = (e) => {
		console.log(e,'正在下拉')
	}

	//下拉刷新被触发回调
	const onRefresherrefresh = (e) => {
	     loading.value=true;
		 tipText.value="正在刷新..."
		 //模拟接口请求数据
		 setTimeout(()=>{
			loading.value=false 
			uni.showToast({
				title:'刷新成功',
				icon:'none'
			})
		 },1000)
	}



	//下拉刷新被复位回调
	const onRefresherrestore = () => {
		tipText.value = "下拉可以刷新"
	}

</script>

<style lang="scss" scoped>
	.pull-refresh {
		height: 100vh;
		width: 100%;
		position: relative;
	}

	.main {
		position: relative;
	}

	.content {
		width: 100%;
		display: flex;
		align-items: center;
		justify-content: center;
		position: absolute;
		top: -80px;
		height: 80px;
		color: #000;
		z-index: 999;
		padding-bottom: 15px;
		box-sizing: border-box;

		.arrow {
			width: 45rpx;
			height: auto;
		}

		.tip-view {
			width: 10em;
			display: flex;
			font-size: 22rpx;
			flex-direction: column;
			align-items: center;
			margin-left: 20rpx;
			.text {
				font-size: 28rpx;
				color: #666;
			}

		}
	}

</style>

运行效果:
请添加图片描述

通过运行效果可以看出除了图标、加载动画、更新时间外,和我们设想的效果最关键的区别在于释放刷新这个状态实现,组件无提供此状态,此时需要我们自己判断定义出来。

我们打印下来下拉刷新控件被下拉回调函数的参数

	//控件被下拉触发回调
	const onRefresherpulling = (e) => {
		console.log(e,'下拉触发')
	}

小程序端:
在这里插入图片描述
H5或APP:
![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/3051ac201bdc4ba395b784f56521f24a.png

可以看到下拉过程中该回调一直被触发,小程序端内部有个dy字段而H5或APP端却变成了deltaY,dy或deltaY就是我们下拉区域的高度(单位px),当这个值大于等于下拉刷新阈值( refresher-threshold)将触发下拉刷新回调(@refresherrefresh)

所以是否达到释放立即刷新这个状态就很容易判断,也即dy或deltaY>=refresher-threshold进入释放立即刷新状态

	//控件被下拉触发回调
     const onRefresherpulling = (e) => {
     	//微信小程dy字段,H5和app deltaY字段
		//#ifdef H5||APP
		if (e.detail.deltaY >= threshold ) {
			tipText.value = props.loosingText || "释放立即刷新"
		}
		// #endif
     //#ifndef H5||APP
		if (e.detail.dy >= threshold) {
			tipText.value = props.loosingText || "释放立即刷新"
		}
   	// #endif		
		else {
			tipText.value = props.pullingText || "下拉可以刷新"
		}
	}

为了更好控制下拉区域图标和文字我们定义3中状态:

/**
	 * 状态:0:下拉状态 1:可释放刷新状态 2:正在刷新状态
	 */
	const status = ref(0)

通过不同状态来改变UI和执行逻辑。

完整代码如下:
pullRefresh.vue

<template>
	<view class="pull-refresh">
		<scroll-view style="height: 100%;" scroll-y refresher-enabled refresher-default-style="none"
			refresher-background="#ffffff" :refresher-threshold="threshold" :refresher-triggered="loading"
			@refresherpulling="onRefresherpulling" @refresherrefresh="onRefresherrefresh"
			@refresherrestore="onRefresherrestore" @scrolltolower="onScrolltolower">
			<view class="main">
				<!-- 下拉提示内容 -->
				<view class="content" :style="{top:`-${threshold}px`,height:`${threshold}px`}">
					<!-- 下拉或可释放状态 -->
					<image v-if="status<2" class="arrow"
						:src="status===0 ? '/static/arrow_down.png':'/static/arrow_up.png'" mode="widthFix"></image>
					<!-- 正在刷新中 -->
					<image v-else-if="status==2" class="arrow loading" src="/static/loading.png" mode="widthFix">
					</image>
					<view class="tip-view">
						<view :class="['text',{start:!updateTime}]">{{tipText}}</view>
						<view v-if="updateTime" class="update-time">上次更新 {{updateTime}}</view>
					</view>
				</view>
				<slot></slot>
			</view>
		</scroll-view>
	</view>
</template>

<script setup>
	import {
		ref,
		nextTick,
		computed
	} from 'vue'

	const props = defineProps({
		//下拉刷新阈值
		threshold: {
			type: Number,
			default: 80
		},
		//下拉刷新接口方法,cb:接口请求完成回调
		refreshMethod: {
			type: Function,
			default: cb => cb()
		},
		//下拉过程文案
		pullingText: {
			type: String,
			default: '下拉可以刷新'
		},
		//释放过程文案
		loosingText: {
			type: String,
			default: '释放立即刷新'
		},
		//刷新中文案
		loadingText: {
			type: String,
			default: '正在刷新...'
		},
	})

	const emits = defineEmits(['scrolltolower'])


	//是否正在刷新(加载数据)
	const loading = ref(false)
	/**
	 * 状态:0:下拉状态 1:可释放刷新状态 2:正在刷新状态
	 */
	const status = ref(0)
	//提示文字
	const tipText = computed(()=>{
		let tips={
			0:props.pullingText,
			1:props.loosingText,
			2:props.loadingText
		}
		return tips[status.value]||props.pullingText
	})
	//上一次刷新时间
	const updateTime = ref('')

	//控件被下拉触发回调
	const onRefresherpulling = (e) => {
	    //微信小程dy字段,H5和app deltaY字段
	    
		//#ifdef H5||APP
		if (e.detail.deltaY >= props.threshold ) {
			status.value = 1
		}
		// #endif

		//#ifndef H5||APP
		if (e.detail.dy >= props.threshold) {
			status.value = 1
		}
		// #endif
		else {
			status.value = 0
		}
	}

	//下拉刷新被触发回调
	const onRefresherrefresh = (e) => {
		//到达下拉阈值刷新数据
		if (status.value === 1) {
			loading.value = true
			status.value = 2;
			//接口获取数据
			props.refreshMethod(() => {
				nextTick(() => {
					uni.showToast({
						title: '刷新成功',
						icon: 'none'
					})
					updateTime.value = formatDateTime()
					loading.value = false
				})

			})
		}
	}



	//下拉刷新被复位回调
	const onRefresherrestore = () => {
		status.value = 0
	}

	//获取当前日期时间
	const formatDateTime = () => {
		let date = new Date()
		let month = (date.getMonth() + 1).toString().padStart(2, '0')
		let day = date.getDate().toString().padStart(2, '0')
		let hour = date.getHours().toString().padStart(2, '0')
		let minus = date.getMinutes().toString().padStart(2, '0')
		let second = date.getSeconds().toString().padStart(2, '0')
		return `${month}-${day} ${hour}:${minus}`
	}

	//触底
	const onScrolltolower = () => {
		emits('scrolltolower')
	}
</script>

<style lang="scss" scoped>
	.pull-refresh {
		height: 100%;
		width: 100%;
		position: relative;
	}

	.main {
		position: relative;
	}

	.content {
		width: 100%;
		display: flex;
		align-items: center;
		justify-content: center;
		position: absolute;
		top: -80px;
		height: 80px;
		color: #000;
		z-index: 999;
		padding-bottom: 15px;
		box-sizing: border-box;

		.arrow {
			width: 45rpx;
			height: auto;

			&.loading {
				animation: loadingFrames 1s linear infinite;
			}
		}

		.tip-view {
			width: 10em;
			display: flex;
			font-size: 22rpx;
			flex-direction: column;
			align-items: center;
			margin-left: 20rpx;

			.text {
				font-size: 28rpx;
				color: #666;
				&.start{
					align-self: flex-start;
				}
			}

			.update-time {
				font-size: 22rpx;
				margin-top: 10rpx;
				color: #808080;

			}
		}
	}

	@keyframes loadingFrames {
		from {
			transform: rotate(0deg);
		}

		to {
			transform: rotate(360deg);
		}

	}
</style>

页面调用:
index.vue

<template>
	<view class="container">
		<PullRefresh :threshold="80"  :refreshMethod="getData" @scrolltolower="handleScrolltolower">
			<view class="item" v-for="(item,index) in 20">{{item}}</view>
		</PullRefresh>
		
	</view>
</template>

<script setup>
	import PullRefresh from '@/components/pullRefresh.vue';

	/**
	 * 获取数据
	 * cb:接口数据获取完成回调函数
	 */
	const getData=(cb)=>{
		//模拟接口请求数据
		setTimeout(()=>{
			cb()
		},2000)

	}
	
	//触底回调
	const handleScrolltolower=()=>{
		console.log('触底')
	}
	
</script>

<style lang="scss" scoped>
	.container {
		height: 100vh;
		background-color: #f2f2f2;

	}

	.item {
		height: 90rpx;
		line-height: 90rpx;
		text-align: center;
		margin-top: 20rpx;
	}
</style>

说明:为了让用户自定义文字,我们提供了各种状态下的文案属性设置,下拉刷新阈值也暴露属性threshold给用户自定义,同时还定义了refreshMethod属性用来控制接口获取刷新数据是否完成,该属性是一个方法内部写入从接口获取刷新数据逻辑,入参cb是个回调函数,刷新数据获取完成调用回调函数组件即可复位。组件高度默认100%继承父容器,内部默认插槽可添加页面内容。

ps:scrollView组件外层必须设置高度或最大高度才能保证自定义下拉刷新或者滚动触底功能正常

在小程序端运行:
请添加图片描述

H5或APP运行:

请添加图片描述

从运行效果看出小程序运行正常,而H5或APP端存在bug,当下拉区域较长时正常,当下拉区域较短(刚处于立即释放刷新状态)就放开手指会出现异常,组件不进入刷新状态。

查阅uniapp官方文档,官方文档对下拉回调参数都是轻描淡写,没写详细,通过多次试验测试,发现当中的猫腻,原来是下拉触发回调@refresherpulling返回的当前下拉区域高度值deltaY在这2端是不准确的,经过测试发现跟实际误差10px左右(多了10px),因此判断这2端是否到达阈值需要减去10

	//控件被下拉触发回调
	const onRefresherpulling = (e) => {
		console.log(e,'e')
		//微信小程dy字段,H5和app deltaY字段
		//#ifdef H5||APP
		//H5或APP端值判断是否到达阈值需要额外加10
		if (e.detail.deltaY-10 >= props.threshold ) {
			status.value = 1
		}
		// #endif

		//#ifndef H5||APP
		if (e.detail.dy >= props.threshold) {
			status.value = 1
		}
		// #endif
		else {
			status.value = 0
		}
	}

最终版完整代码:

pullRefresh.vue(自定义下拉刷新组件)

<template>
	<view class="pull-refresh">
		<scroll-view style="height: 100%;" scroll-y refresher-enabled refresher-default-style="none"
			refresher-background="#ffffff" :refresher-threshold="threshold" :refresher-triggered="loading"
			@refresherpulling="onRefresherpulling" @refresherrefresh="onRefresherrefresh"
			@refresherrestore="onRefresherrestore" @scrolltolower="onScrolltolower">
			<view class="main">
				<!-- 下拉提示内容 -->
				<view class="content" :style="{top:`-${threshold}px`,height:`${threshold}px`}">
					<!-- 下拉或可释放状态 -->
					<image v-if="status<2" class="arrow"
						:src="status===0 ? '/static/arrow_down.png':'/static/arrow_up.png'" mode="widthFix"></image>
					<!-- 正在刷新中 -->
					<image v-else-if="status==2" class="arrow loading" src="/static/loading.png" mode="widthFix">
					</image>
					<view class="tip-view">
						<view :class="['text',{start:!updateTime}]">{{tipText}}</view>
						<view v-if="updateTime" class="update-time">上次更新 {{updateTime}}</view>
					</view>
				</view>
				<slot></slot>
			</view>
		</scroll-view>
	</view>
</template>

<script setup>
	import {
		ref,
		nextTick,
		computed
	} from 'vue'

	const props = defineProps({
		//下拉刷新阈值
		threshold: {
			type: Number,
			default: 80
		},
		//下拉刷新接口方法,cb:接口请求完成回调
		refreshMethod: {
			type: Function,
			default: cb => cb()
		},
		//下拉过程文案
		pullingText: {
			type: String,
			default: '下拉可以刷新'
		},
		//释放过程文案
		loosingText: {
			type: String,
			default: '释放立即刷新'
		},
		//刷新中文案
		loadingText: {
			type: String,
			default: '正在刷新...'
		},
	})

	const emits = defineEmits(['scrolltolower'])


	//是否正在刷新(加载数据)
	const loading = ref(false)
	/**
	 * 状态:0:下拉状态 1:可释放刷新状态 2:正在刷新状态
	 */
	const status = ref(0)
	//提示文字
	const tipText = computed(()=>{
		let tips={
			0:props.pullingText,
			1:props.loosingText,
			2:props.loadingText
		}
		return tips[status.value]||props.pullingText
	})
	//上一次刷新时间
	const updateTime = ref('')

	//控件被下拉触发回调
	const onRefresherpulling = (e) => {
		//微信小程dy字段,H5和app deltaY字段
		//#ifdef H5||APP
		//H5或APP端值判断是否到达阈值需要额外加10
		if (e.detail.deltaY-10 >= props.threshold ) {
			status.value = 1
		}
		// #endif

		//#ifndef H5||APP
		if (e.detail.dy >= props.threshold) {
			status.value = 1
		}
		// #endif
		else {
			status.value = 0
		}
	}

	//下拉刷新被触发回调
	const onRefresherrefresh = (e) => {
		//到达下拉阈值刷新数据
		if (status.value === 1) {
			loading.value = true
			status.value = 2;
			//接口获取数据
			props.refreshMethod(() => {
				nextTick(() => {
					uni.showToast({
						title: '刷新成功',
						icon: 'none'
					})
					updateTime.value = formatDateTime()
					loading.value = false
				})

			})
		}
		  //发现误差在1左右未到达下拉刷新阈值H5或APP也会触发,兼容处理恢复初态
		else {
			loading.value = false
			status.value = 0
		}
	}



	//下拉刷新被复位回调
	const onRefresherrestore = () => {
		status.value = 0
	}

	//获取当前日期时间
	const formatDateTime = () => {
		let date = new Date()
		let month = (date.getMonth() + 1).toString().padStart(2, '0')
		let day = date.getDate().toString().padStart(2, '0')
		let hour = date.getHours().toString().padStart(2, '0')
		let minus = date.getMinutes().toString().padStart(2, '0')
		let second = date.getSeconds().toString().padStart(2, '0')
		return `${month}-${day} ${hour}:${minus}`
	}

	//触底
	const onScrolltolower = () => {
		emits('scrolltolower')
	}
</script>

<style lang="scss" scoped>
	.pull-refresh {
		height: 100%;
		width: 100%;
		position: relative;
	}

	.main {
		position: relative;
	}

	.content {
		width: 100%;
		display: flex;
		align-items: center;
		justify-content: center;
		position: absolute;
		top: -80px;
		height: 80px;
		color: #000;
		z-index: 999;
		padding-bottom: 15px;
		box-sizing: border-box;

		.arrow {
			width: 45rpx;
			height: auto;

			&.loading {
				animation: loadingFrames 1s linear infinite;
			}
		}

		.tip-view {
			width: 10em;
			display: flex;
			font-size: 22rpx;
			flex-direction: column;
			align-items: center;
			margin-left: 20rpx;

			.text {
				font-size: 28rpx;
				color: #666;
				&.start{
					align-self: flex-start;
				}
			}

			.update-time {
				font-size: 22rpx;
				margin-top: 10rpx;
				color: #808080;

			}
		}
	}

	@keyframes loadingFrames {
		from {
			transform: rotate(0deg);
		}

		to {
			transform: rotate(360deg);
		}

	}
</style>

页面调用:

<template>
	<view class="container">
		<PullRefresh :threshold="80" :refreshMethod="getData" @scrolltolower="handleScrolltolower">
			<view class="item" v-for="(item,index) in 20">{{item}}</view>
		</PullRefresh>
		
	</view>
</template>

<script setup>
	import PullRefresh from '@/components/pullRefresh.vue';

	/**
	 * 获取数据
	 * cb:接口数据获取完成回调函数
	 */
	const getData=(cb)=>{
		//模拟接口请求数据
		setTimeout(()=>{
			cb()
		},2000)

	}
	
	//触底回调
	const handleScrolltolower=()=>{
		console.log('触底')
	}
	
</script>

<style lang="scss" scoped>
	.container {
		height: 100vh;
		background-color: #f2f2f2;

	}

	.item {
		height: 90rpx;
		line-height: 90rpx;
		text-align: center;
		margin-top: 20rpx;
	}
</style>

H5或APP端运行效果:
请添加图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/927212.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

2、Three.js初步认识场景Scene、相机Camera、渲染器Renderer三要素

三要素之间关系&#xff1a; 有了虚拟场景Scene&#xff0c;相机录像Camera&#xff0c;在相机小屏幕上看到的Renderer Scene当前空间 Mesh人在场景 Camera相机录像 Renderer显示器上 首先先描述下Scene&#xff1a; 这个场景为三要素之一&#xff0c;一切需要展示的东西都需…

Unity中的数学应用 之 插值函数处理角色朝向 (初中难度 +Matlab)

CodeMonkey教程&#xff1a; https://www.youtube.com/watch?vQDWlGOocKm8 Siki学院汉化教程&#xff1a;如何使用Unity开发分手厨房&#xff08;胡闹厨房&#xff09;-Unity2023 - SiKi学院|SiKi学堂 - unity|u3d|虚幻|ue4/5|java|python|人工智能|视频教程|在线课程 版本&am…

2-2-18-7 QNX 系统架构-动态链接

阅读前言 本文以QNX系统官方的文档英文原版资料为参考&#xff0c;翻译和逐句校对后&#xff0c;对QNX操作系统的相关概念进行了深度整理&#xff0c;旨在帮助想要了解QNX的读者及开发者可以快速阅读&#xff0c;而不必查看晦涩难懂的英文原文&#xff0c;这些文章将会作为一个…

PPT不能编辑,按钮都是灰色,怎么办?

PPT文件打开之后&#xff0c;发现无法编辑&#xff0c;再仔细查看发现工具栏中的功能按钮都是灰色的&#xff0c;无法使用&#xff0c;这是什么原因&#xff1f;该如何解决&#xff1f; 原因&#xff1a;无法编辑PPT文件&#xff0c;并且功能按钮都是灰色&#xff0c;这是因为…

PMP–一、二、三模、冲刺–分类–8.质量管理

文章目录 技巧五、质量管理 一模8.质量管理--质量管理计划--质量管理计划包括项目采用的质量标准&#xff0c;到底有没有满足质量需求&#xff0c;看质量标准即可。6、 [单选] 自项目开始以来&#xff0c;作为项目经理同事的职能经理一直公开反对该项目&#xff0c;在讨论项目里…

深度学习中的生成对抗网络(GAN)原理与应用

引言 生成对抗网络&#xff08;Generative Adversarial Network&#xff0c;简称GAN&#xff09;是由Ian Goodfellow等人在2014年提出的一种深度学习模型&#xff0c;它通过对抗训练的方式生成与真实数据分布相似的假数据。GAN的出现极大地推动了深度学习和生成模型的研究&…

【CSS in Depth 2 精译_063】10.2 深入理解 CSS 容器查询中的容器

当前内容所在位置&#xff08;可进入专栏查看其他译好的章节内容&#xff09; 【第十章 CSS 容器查询】 ✔️ 10.1 容器查询的一个简单示例 10.1.1 容器尺寸查询的用法 10.2 深入理解容器 ✔️ 10.2.1 容器的类型 ✔️10.2.2 容器的名称 ✔️10.2.3 容器与模块化 CSS ✔️ 10.3…

macOS无法打开未验证安装包的解决方案:无法打开‘XXX.pkg’,因为无法验证其是否包含可能危害Mac安全或泄漏隐私的恶意软件

macOS无法打开未验证安装包的解决方案&#xff1a;无法打开‘XXX.pkg’&#xff0c;因为无法验证其是否包含可能危害Mac安全或泄漏隐私的恶意软件 在macOS Ventura及以上版本中&#xff0c;系统安全性进一步加强&#xff0c;默认情况下不允许运行未验证或未签名的应用程序。当…

Springboot项目搭建(8)-用户登出与个人中心修改

1.提要信息 1.1 catch和then方法 then和catch是JavaScript中Promise对象的两个方法&#xff0c;用于处理异步操作的成功&#xff08;成功回调&#xff09;和失败&#xff08;失败回调&#xff09;情况。这两个方法通常与async/await语法一起使用&#xff0c;但也可以单独使用…

Android Studio 使用插件Database Navigation 连接 sqlite数据库

文章目录 Database Navigation 简介一&#xff0c;Database Navigation 下载二&#xff0c;将sqlite数据库文件存放到本地三&#xff0c;连接sqlite数据库四&#xff0c;使用SQL语句查看数据 Database Navigation 简介 Database Navigation 是一款在 Android Studio 开发环境中…

springboot kafka在kafka server AUTH变动后consumer自动销毁

前言 笔者使用了kafka用来传输数据&#xff0c;笔者在今年10月写了文章&#xff0c;怎么使用配置化实现kafka的装载&#xff1a;springboot kafka多数据源&#xff0c;通过配置动态加载发送者和消费者-CSDN博客 不过在实际运行中&#xff0c;kafka broker是加密的&#xff0c…

ansible使用说明

将安装包拷贝到主控端主机 在主控端主机安装ansible&#xff0c;sh setup.sh 确认安装成功后&#xff0c;编辑hosts文件&#xff08;按步骤逐个添加主机组&#xff0c;不要一开始全部配置好&#xff09; [site-init]下的主机列表为被控制的主机&#xff08;按照当前ai建模方案…

5G学习笔记之PRACH

即使是阴天&#xff0c;也要记得出门晒太阳哦 目录 1. 概述 2. PRACH Preamble 3. PRACH Preamble 类型 3.1 长前导码 3.2 短前导码 3.3 前导码格式与小区覆盖 4. PRACH时频资源 4.1 小区所有可用PRACH资源 4.2 SSB和RACH的关系 4.3 PRACH时频资源配置 1. 概述 随机接入…

单点登录深入详解之技术方案总结

技术方案之CAS认证 概述 CAS 是耶鲁大学的开源项目&#xff0c;宗旨是为 web 应用系统提供一种可靠的单点登录解决方案。 CAS 从安全性角度来考虑设计&#xff0c;用户在 CAS 输入用户名和密码之后通过ticket进行认证&#xff0c;能够有效防止密码泄露。 CAS 广泛使用于传统应…

不开流也可以知道文件大小(File类)file.length():long

但是文件的toString是这个东西&#xff0c;所以当你把一个文件对象转json&#xff0c;大概率只有paXXXXX” 这一个key&#xff0c;想要自动转成输出其他的文件大小或者文件名什么的&#xff0c;就自己封装file类&#xff0c;封装fiel的方法

数据结构 (16)特殊矩阵的压缩存储

前言 特殊矩阵的压缩存储是数据结构中的一个重要概念&#xff0c;它旨在通过找出特殊矩阵中值相同的矩阵元素的分布规律&#xff0c;把那些呈现规律性分布的、值相同的多个矩阵元素压缩存储到一个存储空间中&#xff0c;从而节省存储空间。 一、特殊矩阵的定义 特殊矩阵是指具有…

试题转excel;试题整理工具;试卷转excel;word转excel

一、问题描述 我父亲是一名教师&#xff0c;偶尔会需要将试卷转excel&#xff0c;方便管理处理一些特别重要的题目 于是&#xff0c;就抽空写一个专门将试题转excel的工具&#xff0c;便于各位教师从业者和教育行业的朋友更好的整理试题&#xff0c;减少一点重复枯燥的工作 …

CSP/信奥赛C++语法基础刷题训练(36):洛谷P11229:[CSP-J 2024] 小木棍

CSP/信奥赛C语法基础刷题训练&#xff08;36&#xff09;&#xff1a;洛谷P11229&#xff1a;[CSP-J 2024] 小木棍 题目描述 小 S 喜欢收集小木棍。在收集了 n n n 根长度相等的小木棍之后&#xff0c;他闲来无事&#xff0c;便用它们拼起了数字。用小木棍拼每种数字的方法如…

【NLP 4、数学基础】

此去经年&#xff0c;应是良辰美景虚设 —— 24.11.28 一、线性代数 1.标量和向量 ① 标量 Scalar 一个标量就是一个单独的数 ② 向量 Vector 一个向量是一列数 可以把向量看作空间中的点&#xff0c;每个元素是不同坐标轴上的坐标 向量中有几个数&#xff0c;就叫作几维…

IOC控制反转DI依赖注入(Java EE 学习笔记06)

1 IoC 控制反转 控制反转&#xff08;Inversion of Control&#xff0c;缩写为IoC&#xff09;是面向对象编程中的一个设计原则&#xff0c;用来降低程序代码之间的耦合度。在传统面向对象编程中&#xff0c;获取对象的方式是用new关键字主动创建一个对象&#xff0c;也就是说…