uniapp音乐播放整理

news2024/9/27 17:36:58

一、前置知识点

1.1 音频组件控制-uni.createInnerAudioContext()

创建并返回内部 audio 上下文 innerAudioContext 对象。

主要用于当前音乐播放;

1.1.1 innerAudioContext属性
属性类型说明只读平台差异说明
srcString音频的数据链接,用于直接播放。微信小程序不支持本地路径
startTimeNumber开始播放的位置(单位:s),默认 0
autoplayBoolean是否自动开始播放,默认 falseH5端部分浏览器不支持
loopBoolean是否循环播放,默认 false
obeyMuteSwitchBoolean是否遵循系统静音开关,当此参数为 false 时,即使用户打开了静音开关,也能继续发出声音,默认值 true微信小程序、百度小程序、抖音小程序、飞书小程序、京东小程序、快手小程序(仅在 iOS 上生效)
durationNumber当前音频的长度(单位:s),只有在当前有合法的 src 时返回,需要在onCanplay中获取
currentTimeNumber当前音频的播放位置(单位:s),只有在当前有合法的 src 时返回,时间不取整,保留小数点后 6 位
pausedBoolean当前是是否暂停或停止状态,true 表示暂停或停止,false 表示正在播放
bufferedNumber音频缓冲的时间点,仅保证当前播放时间点到此时间点内容已缓冲。
volumeNumber音量。范围 0~1。
sessionCategoryString设置音频播放模式,可取值:“ambient” - 不中止其他声音播放,不能后台播放,静音后无声音; “soloAmbient” - 中止其他声音播放,不能后台播放,静音后无声音; “playback” - 中止其他声音,可以后台播放,静音后有声音。 默认值为"playback"。App 3.3.7+
playbackRateNumber播放的倍率。可取值:0.5/0.8/1.0/1.25/1.5/2.0,默认值为1.0App 3.4.5+(Android 需要 6 及以上版本)、微信小程序 2.11.0、支付宝小程序、抖音小程序 2.33.0+、快手小程序、百度小程序 3.120.2+
1.1.2 innerAudioContext方法列表
方法参数说明
play播放(H5端部分浏览器需在用户交互时进行)
pause暂停
stop停止
seekposition跳转到指定位置,单位 s
destroy销毁当前实例
onCanplaycallback音频进入可以播放状态,但不保证后面可以流畅播放
onPlaycallback音频播放事件
onPausecallback音频暂停事件
onStopcallback音频停止事件
onEndedcallback音频自然播放结束事件
onTimeUpdatecallback音频播放进度更新事件
onErrorcallback音频播放错误事件
onWaitingcallback音频加载中事件,当音频因为数据不足,需要停下来加载时会触发
onSeekingcallback音频进行 seek 操作事件
onSeekedcallback音频完成 seek 操作事件
offCanplaycallback取消监听 onCanplay 事件
offPlaycallback取消监听 onPlay 事件
offPausecallback取消监听 onPause 事件
offStopcallback取消监听 onStop 事件
offEndedcallback取消监听 onEnded 事件
offTimeUpdatecallback取消监听 onTimeUpdate 事件
offErrorcallback取消监听 onError 事件
offWaitingcallback取消监听 onWaiting 事件
offSeekingcallback取消监听 onSeeking 事件
offSeekedcallback取消监听 onSeeked 事件
1.1.3 简单示例
// 创建innerAudioContext对象
const innerAudioContext = uni.createInnerAudioContext();
// 开始自动播放
innerAudioContext.autoplay = true;
// 设置音频地址
innerAudioContext.src = 'url.mp3';
// 开始播放的回调函数
innerAudioContext.onPlay(() => {
  console.log('开始播放');
});
// 播放报错的事件监听
innerAudioContext.onError((res) => {
  console.log(res.errMsg);
  console.log(res.errCode);
});

1.2 背景音频控制-uni.getBackgroundAudioManager()

获取全局唯一的背景音频管理器 backgroundAudioManager

主要是实现后台播放功能,退出app或者小程序后还能继续播放,同时状态栏有控制播放状态控件;

1.2.1 backgroundAudioManager属性列表
属性类型说明只读
durationNumber当前音频的长度(单位:s),只有在当前有合法的 src 时返回
currentTimeNumber当前音频的播放位置(单位:s),只有在当前有合法的 src 时返回
pausedBoolean当前是是否暂停或停止状态,true 表示暂停或停止,false 表示正在播放
srcString音频的数据源,默认为空字符串,**当设置了新的 src 时,会自动开始播放,**目前支持的格式有 m4a, aac, mp3, wav
startTimeNumber音频开始播放的位置(单位:s)
bufferedNumber音频缓冲的时间点,仅保证当前播放时间点到此时间点内容已缓冲。
titleString音频标题,用于做原生音频播放器音频标题。原生音频播放器中的分享功能,分享出去的卡片标题,也将使用该值。
epnameString专辑名,原生音频播放器中的分享功能,分享出去的卡片简介,也将使用该值。
singerString歌手名,原生音频播放器中的分享功能,分享出去的卡片简介,也将使用该值。
coverImgUrlString封面图url,用于做原生音频播放器背景图。原生音频播放器中的分享功能,分享出去的卡片配图及背景也将使用该图。
webUrlString页面链接,原生音频播放器中的分享功能,分享出去的卡片简介,也将使用该值。
protocolString音频协议。默认值为 ‘http’,设置 ‘hls’ 可以支持播放 HLS 协议的直播音频,App平台暂不支持
playbackRateNumber播放的倍率。可取值:0.5/0.8/1.0/1.25/1.5/2.0,默认值为1.0。(App 3.4.5+、微信基础库 2.11.0+、支付宝小程序、抖音小程序 2.33.0+、快手小程序、百度小程序 3.120.2+)
1.2.2 backgroundAudioManager方法列表
方法参数说明
play播放
pause暂停
stop停止
seekposition跳转到指定位置,单位 s
onCanplaycallback背景音频进入可以播放状态,但不保证后面可以流畅播放
onPlaycallback背景音频播放事件
onPausecallback背景音频暂停事件
onStopcallback背景音频停止事件
onEndedcallback背景音频自然播放结束事件
onTimeUpdatecallback背景音频播放进度更新事件
onPrevcallback用户在系统音乐播放面板点击上一曲事件(iOS only)
onNextcallback用户在系统音乐播放面板点击下一曲事件(iOS only)
onErrorcallback背景音频播放错误事件
onWaitingcallback音频加载中事件,当音频因为数据不足,需要停下来加载时会触发
1.2.3 简单示例
// 创建bgAudioManager对象
const bgAudioManager = uni.getBackgroundAudioManager();
bgAudioManager.title = '音乐标题';
bgAudioManager.singer = '作者';
bgAudioManager.coverImgUrl = '封面图片';
bgAudioManager.src = 'url.mp3';
// 开始播放的回调函数
bgAudioManager.onPlay(() => {
  console.log('开始播放');
});
// 播放报错的事件监听
bgAudioManager.onError((res) => {
  console.log(res.errMsg);
  console.log(res.errCode);
});
1.2.4 注意点

注意 因为背景音频播放耗费手机电量,所以平台都有管控,需在manifest中填写申请。

  • ios App平台,背景播放需在manifest.json -> app-plus -> distribute -> ios 节点添加 "UIBackgroundModes":["audio"] 才能保证音乐可以后台播放(打包成ipa生效)
  • 小程序平台,需在manifest.json 对应的小程序节点下,填写"requiredBackgroundModes": [“audio”]。发布小程序时平台会审核

二、音乐功能点

2.1 实现效果

  1. 控制播放暂停;
  2. 实现上一首,下一首;
  3. 展示当前音乐当前进度时间,结束时间;展示当前音乐当前进度时间,结束时间;
  4. 可以通过进度条去控制音乐跳转到对应时间点;
  5. 实现倍速播放;
  6. 后台播放;

2.2 获取音乐信息

  1. 当前音乐播放状态;
  2. 音乐列表数据,便于实现上一首下一首;
  3. 当前音乐播放时长,与结束时长,播放速度;
  4. 音乐的地址、封面图片、名称等基础信息;
  5. 歌词展示,到达当前歌词时歌词高亮;

三、实现步骤

3.1 技术选型

通过前置知识点我们了解到了uni.createInnerAudioContext()和uni.getBackgroundAudioManager()的实例属性方法等。

可以根据需求去选择性调用实例,前者可以在小程序中调用来播放音乐;而如果想要退出小程序或者app后依然可以让音乐继续播放,这个时候就可以使用后者来生成悬浮框,以及状态栏中显示;

结论:

  1. 小程序或app中使用uni.createInnerAudioContext();
  2. 退出小程序或app时使用uni.getBackgroundAudioManager();

3.2 实现思路

根据前面整理的音乐所需功能点,我们需要使用store存储一些全局音乐状态信息;便于切换到其他界面的时候可以同步得到最新的音乐信息。

  1. 首先在程序初始化时,实例化一个audio对象挂载到vue原型上;
  2. 用于实时获取当前播放信息;
  3. 初始化时就可以把需要的监听事件挂载,配合实际业务场景;

3.3 简易代码示例

3.3.1 实例化挂载audio对象

入口文件实例化-main.js

// 新建音乐对象挂载到原型上
const innerAudioContext = uni.createInnerAudioContext();
// 音乐播放报错监听
innerAudioContext.onError((res) => {
  console.log("音乐播放报错监听", res);
});
// 音乐加载中监听
innerAudioContext.onWaiting((res) => {
  console.log("音乐加载中监听", res);
});
Vue.prototype.$AudioContext = innerAudioContext;
3.3.2 定义一个简单的音乐列表
{
// 滚动条信息
playInfo: {
        progressWidth: 2, 	// 滚动条
        currentTime: 0,			// 当前音乐时间s
        currentValue: '00:00', // 转换成时间展示
        duration: 0,				// 当前音乐总时间s
        durationValue: '00:00',	// 总时间转换展示 
    },
// 简易歌曲列表
audioList: [ 
	{
		title: '未完成之前',
		src: 'https://music.163.com/song/media/outer/url?id=1453946527.mp3',
		id: 1453946527,
	}, 
	{
		title: '鲜花',
		src: 'https://music.163.com/song/media/outer/url?id=2086327879.mp3',
		id: 2086327879,
	},
	{
		title: '水星记',
		src: 'https://music.163.com/song/media/outer/url?id=441491828.mp3',
		id: 441491828,
	}, 
	{
		title: '人生有时候懂得放弃',
		src: 'https://music.163.com/song/media/outer/url?id=2139388989.mp3',
		id: 2139388989,
	},
	{
		title: '精卫',
		src: 'https://music.163.com/song/media/outer/url?id=1951069525.mp3',
		id: 1951069525,
	},
],
}
3.3.3 实现暂停播放、切换音乐

在这里插入图片描述

要实现播放音乐首先要给$AudioContext设置音乐地址src,这样才能通过地址去获取对应的音乐信息。

首选需要在页面一加载时默认配置列表中第一首歌的地址:

onLoad() {
	this.$AudioContext.playbackRate = 2;
	if (this.audioList.length) {
		this.$AudioContext.src = this.audioList[this.currentIndex].src;
		this.currentTitle = this.audioList[this.currentIndex].title;
		this.setPlayInfo();
	}
    // 开始播放获取音乐信息
	this.$AudioContext.onPlay((e) => {
		this.setPlayInfo();
	});
	this.$AudioContext.onEnded((e) => {
		// 结束播放去播放下一首
		this.hanleAudioChange();
	});
},

播放按钮: 判断paused的状态选择性去调用播放和暂停方法;

切换音乐: 点击音乐列表行更新音乐地址src,停止当前音乐,最后调用播放方法即可;

// 音乐播放
handlePlay() {
	this.$AudioContext.paused ? this.$AudioContext.play() : this.$AudioContext.pause();
	this.paused = this.$AudioContext.paused;
	this.recursionDeep();
},
// 选择目标音乐播放
handleCurrentAudio(index) {
	this.currentIndex = index;
	this.currentTitle = this.audioList[index].title;
	// 先停止当前音乐
	this.$AudioContext.stop();
	// 更换播放地址
	this.$AudioContext.src = this.audioList[index].src;
	// 播放音乐
	this.handlePlay();
},
3.3.4 进度条功能实现

首先明确功能点:

  1. 根据音乐播放进度条增加,显示当前播放时长和总时长(可以根据定时任务获取最新音乐播放信息);
  2. 可以拖动选择特定位置播放(通过touchmove与touchend事件监听实现);
  3. 点击某一位置直接跳转对应位置播放(通过点击事件获取x轴位置)
// 递归循环获取最新音乐进度信息
recursionDeep() {
	clearTimeout(this.timer);
	if (this.paused) {
		return
	};
	this.timer = setTimeout(() => {
		if (!this.isMove) {
			this.setPlayInfo();
			this.recursionDeep();
		}
	}, 500)
},
// 进度条点击事件
progressClick(event) {
	const {
		x
	} = event.detail;
	const progressWidth = Math.floor(x / this.progressParentWidth * 100);
	this.playInfo.progressWidth = progressWidth > 100 ? 100 : progressWidth;
	console.log("event", event);
	this.progressMouseDown();
},
// 音乐进度条移动监听
progressMouseMove(event) {
	if (!this.$AudioContext.src) {
		return;
	}
	this.isMove = true;
	const {
		pageX
	} = event.changedTouches[0];
	const progressWidth = Math.floor(pageX / this.progressParentWidth * 100);
	this.playInfo.progressWidth = progressWidth > 100 ? 100 : progressWidth;
},
// 音乐进度条停止监听
progressMouseDown(event) {
	this.isMove = false;
	const currentTime = Math.floor(this.$AudioContext.duration * (this.playInfo.progressWidth / 100));
	this.$AudioContext.seek(currentTime);
	this.setPlayInfo();
	if (!this.$AudioContext.paused) {
		this.$AudioContext.pause();
	}
	this.handlePlay();
},

四、完整源码示例

4.1 示例图

在这里插入图片描述

4.2 main.js入口函数

import App from './App'

import Vue from 'vue'
import './uni.promisify.adaptor'
Vue.config.productionTip = false
App.mpType = 'app'

// 新建音乐对象挂载到原型上
const innerAudioContext = uni.createInnerAudioContext();
// 音乐播放报错监听
innerAudioContext.onError((res) => {
  console.log("音乐播放报错监听", res);
});
// 音乐加载中监听
innerAudioContext.onWaiting((res) => {
  console.log("音乐加载中监听", res);
});
Vue.prototype.$AudioContext = innerAudioContext;


const app = new Vue({
  ...App
})
app.$mount()

4.3 index.vue界面

<template>
	<view class="content">
		<scroll-view class="main-container" scroll-y>
			<view class="line_box" :class="currentIndex === index ? 'line_box bgc_line' : 'line_box'"
				v-for="(item, index) in audioList" :key="item.id" @click="handleCurrentAudio(index)">
				{{item.title}}
			</view>
		</scroll-view>
		<view class="audio_box">
			<view class="current_title" v-show="currentTitle">
				当前播放歌曲:{{currentTitle}}
			</view>

			<view class="music-progress-bar" @click="progressClick">
				<view class="progress-bar-line" :style="{width: playInfo.progressWidth + '%'}" @touchmove="progressMouseMove"
					@touchend="progressMouseDown"></view>
			</view>
			<view class="show_time">
				<view>{{playInfo.currentValue}}</view>
				<view>{{playInfo.durationValue}}</view>
			</view>
			<view class="audio_control">
				<view @click="hanleAudioChange('pre')">上一首</view>
				<view @click="handlePlay">{{ paused ? '播放' : '暂停'}}</view>
				<view @click="hanleAudioChange('next')">下一首</view>
			</view>
		</view>

	</view>
</template>

<script>
	export default {
		data() {
			return {
				timer: null,
				currentTitle: '未完成之前',
				currentIndex: 0,
				paused: true,
				isMove: false,
				playInfo: {
					progressWidth: 2, // 滚动条
					currentTime: 0, // 当前音乐时间s
					currentValue: '00:00', // 转换成时间展示
					duration: 0, // 当前音乐总时间s
					durationValue: '00:00', // 总时间转换展示 
				},
				audioList: [{
						title: '未完成之前',
						src: 'https://music.163.com/song/media/outer/url?id=1453946527.mp3',
						id: 1453946527,
					},
					{
						title: '鲜花',
						src: 'https://music.163.com/song/media/outer/url?id=2086327879.mp3',
						id: 2086327879,
					},
					{
						title: '水星记',
						src: 'https://music.163.com/song/media/outer/url?id=441491828.mp3',
						id: 441491828,
					},
					{
						title: '人生有时候懂得放弃',
						src: 'https://music.163.com/song/media/outer/url?id=2139388989.mp3',
						id: 2139388989,
					},
					{
						title: '精卫',
						src: 'https://music.163.com/song/media/outer/url?id=1951069525.mp3',
						id: 1951069525,
					},
				],
				progressParentWidth: 0,
			}
		},
		onLoad() {
			this.$AudioContext.playbackRate = 2;
			if (this.audioList.length) {
				this.$AudioContext.src = this.audioList[this.currentIndex].src;
				this.currentTitle = this.audioList[this.currentIndex].title;
				this.setPlayInfo();
			}
			this.$AudioContext.onPlay((e) => {
				// 开始播放获取音乐信息
				this.setPlayInfo();
			});
			this.$AudioContext.onEnded((e) => {
				// 结束播放去播放下一首
				this.hanleAudioChange();
			});
		},
		onShow() {
			this.$nextTick(async () => {
				const query = uni.createSelectorQuery().in(this);
				query.select('.music-progress-bar').boundingClientRect(data => {
					this.progressParentWidth = data ? Math.floor(data.width) : 0;
				}).exec();
			});

		},
		onUnload() {
			// 卸载时关闭监听
			this.$AudioContext.offPlay();
			this.$AudioContext.offPlay();
		},
		methods: {
			// 进度条点击事件
			progressClick(event) {
				const {
					x
				} = event.detail;
				const progressWidth = Math.floor(x / this.progressParentWidth * 100);
				this.playInfo.progressWidth = progressWidth > 100 ? 100 : progressWidth;
				console.log("event", event);
				this.progressMouseDown();
			},
			// 音乐进度条移动监听
			progressMouseMove(event) {
				if (!this.$AudioContext.src) {
					return;
				}
				this.isMove = true;
				const {
					pageX
				} = event.changedTouches[0];
				const progressWidth = Math.floor(pageX / this.progressParentWidth * 100);
				this.playInfo.progressWidth = progressWidth > 100 ? 100 : progressWidth;
			},
			// 音乐进度条停止监听
			progressMouseDown(event) {
				this.isMove = false;
				const currentTime = Math.floor(this.$AudioContext.duration * (this.playInfo.progressWidth / 100));
				this.$AudioContext.seek(currentTime);
				this.setPlayInfo();
				if (!this.$AudioContext.paused) {
					this.$AudioContext.pause();
				}
				this.handlePlay();
			},
			// 音乐播放
			handlePlay() {
				this.$AudioContext.paused ? this.$AudioContext.play() : this.$AudioContext.pause();
				this.paused = this.$AudioContext.paused;
				this.recursionDeep();
			},
			// 选择目标音乐播放
			handleCurrentAudio(index) {
				this.currentIndex = index;
				this.currentTitle = this.audioList[index].title;
				// 先停止当前音乐
				this.$AudioContext.stop();
				// 更换播放地址
				this.$AudioContext.src = this.audioList[index].src;
				// 播放音乐
				this.handlePlay();
			},
			// 递归循环获取最新音乐进度信息
			recursionDeep() {
				clearTimeout(this.timer);
				if (this.paused) {
					return
				};
				this.timer = setTimeout(() => {
					if (!this.isMove) {
						this.setPlayInfo();
						this.recursionDeep();
					}
				}, 500)
			},
			// 秒转换为分钟
			secondsToMinutesWithSeconds(seconds) {
				const minutes = Math.floor(seconds / 60);
				const remainingSeconds = Math.floor(seconds % 60);
				return `${this.padZero(minutes)}:${this.padZero(remainingSeconds)}`;
			},
			// 补零
			padZero(number, length = 2) {
				var str = "" + number;
				while (str.length < length) {
					str = "0" + str;
				}
				return str;
			},
			// 设置播放对象
			setPlayInfo() {
				const currentTime = this.$AudioContext.currentTime || 0;
				const duration = this.$AudioContext.duration || 0;
				const progressWidth = duration === 0 ? '2' : Math.floor((currentTime / duration) * 100);
				const currentValue = this.secondsToMinutesWithSeconds(currentTime);
				const durationValue = this.secondsToMinutesWithSeconds(duration);
				this.playInfo = {
					currentTime,
					duration,
					progressWidth,
					currentValue,
					durationValue
				};
			},
			// 切换歌曲
			hanleAudioChange(type = 'next') {
				if (type === 'pre') {
					this.currentIndex = this.currentIndex === 0 ? this.audioList.length - 1 : this.currentIndex - 1;
				} else {
					this.currentIndex = this.currentIndex === this.audioList.length - 1 ? 0 : this.currentIndex + 1;
				};
				this.$AudioContext.src = this.audioList[this.currentIndex].src;
				this.currentTitle = this.audioList[this.currentIndex].title;
				// 播放歌曲
				this.handlePlay();
			},
		}
	}
</script>

<style>
	.content {
		width: 100vw;
		height: calc(100vh - 44px - env(safe-area-inset-top));
		background-color: #1A262D;
		color: #fff;
	}

	.main-container {
		width: 100vw;
		height: 46vh;
	}

	.line_box {
		display: flex;
		align-items: center;
		justify-content: center;
		width: 92%;
		height: 60px;
		border-radius: 8px;
		margin: 10px auto;
		border: 2px solid #eee;
		background-color: aquamarine;
		color: #333;
		font-weight: bold;
	}

	.audio_control {
		display: flex;
		align-items: center;
		justify-content: space-around;
		color: #333;
		margin-top: 40px;
	}

	.audio_control view {
		width: 100px;
		height: 40px;
		text-align: center;
		line-height: 40px;
		background: #edeeab;
		border: 1px solid #eee;
		border-radius: 6px;
	}

	.audio_box {
		width: 90%;

		margin: 30px auto;
	}

	.current_title {
		margin-bottom: 20px;
		font-weight: bold;
		font-size: 18px;
	}

	.bgc_line {
		background-color: #e1964b;
	}

	.show_time {
		width: 100%;
		display: flex;
		justify-content: space-between;
		margin-top: 12rpx;
	}

	// 音乐进度条
	.music-progress-bar {
		position: relative;
		width: 100%;
		height: 6rpx;
		border-radius: 6rpx;
		background-color: #f3e7d9;

		.progress-bar-line {
			position: absolute;
			top: 0%;
			left: 0%;
			width: 2%;
			height: 100%;
			border-radius: 6rpx;
			background-color: #e1964b;
		}

		.progress-bar-line::after {
			content: "";
			display: inline-block;
			position: absolute;
			right: 0%;
			top: 50%;
			transform: translateY(-50%);
			width: 20rpx;
			height: 20rpx;
			background-color: #fff;
			border-radius: 50%;
		}
	}
</style>

4.4 项目源码地址

https://gitee.com/yangdacongming/implementation-of-uniapp-music.git

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Milvus Cloud:打造向量数据库的Airtable级体验

向量数据库Milvus Cloud是一种用于处理和存储向量数据的数据库,它通常用于机器学习、图像和视频检索、自然语言处理等领域。要将其升级为类似Airtable那样易用且一体化的系统,需要考虑以下几个关键方面: 1. 用户界面(UI)设计 Airtable之所以用户友好,很大程度上归功于其直…

Java 日期类 API

1. jdk8 之前的日期 API 1.1. System 类 currentTimeMillis(); Test public void test1() { long timeMillis System.currentTimeMillis(); System.out.println("timeMillis " timeMillis); }1.2. java.util.Date 和 java.sql.Date java.sql.Date 是 jav…

vue2项目升级到vue3经历分享5

写到第5篇了&#xff0c;解决了很多问题&#xff0c;还有一些需要调整 1 el-input-number指令兼容性调整 下面这个可编辑的表格&#xff0c;全是0&#xff0c;于是需要一个指令&#xff0c;让它自己实现如果是0&#xff0c;就置空&#xff1b;如果是数字就是格式化为千分位&…

男士内裤哪个品牌好穿?男士内裤品牌测评推荐,干货满满

随着时代的进步和发展&#xff0c;男士内裤现在普遍分为三角、平角、四角的三个大类&#xff0c;不过大多数男性朋友都是穿平角四角为主。虽然男士内裤款式众多&#xff0c;但大部分男同胞每一条内裤都是穿非常久的&#xff0c;实际上男士内裤需要定期更换才能保持更换的舒适性…

《十日终焉》中的定律整理-向虫队学习(举例+持续更新)

1、二八定律 二八定律&#xff0c;又称帕累托法则&#xff0c;也叫巴莱多定律。 是19世纪末20世纪初意大利经济学家巴莱多发明的。其中指出&#xff0c;约仅有20%的因素影响80%的结果。也就是说&#xff1a;所有变因中&#xff0c;最重要的仅有20%&#xff0c;虽然剩余的80%占…

第二证券今日投资参考:银保渠道合作限制松绑 低空旅游借势起飞

昨日&#xff0c;两市股指盘中震动上扬&#xff0c;沪指一度涨近1%续创年内新高&#xff0c;创业板指一度涨超2%。到收盘&#xff0c;沪指涨0.83%报3154.32点&#xff0c;深证成指涨1.55%报9788.07点&#xff0c;创业板指涨1.87%报1900.01点&#xff0c;科创50指数涨2.26%&…

如何让组织充满活力?你需要做好这七步

组织活力&#xff0c;通俗点说就是&#xff1a; 从竞争对手角度看&#xff0c;组织活力强的组织能做到竞争对手做不到的事情&#xff1b; 从客户角度看&#xff0c;组织活力强的组织&#xff0c;客户感受好&#xff1b; 从员工角度看&#xff0c;组织活力强的组织&#xff0c…

【速看】软考架构考前复习20问!你能答出多少?

马上就要进行今年的软考了&#xff0c;大家都准备得怎么样了呢&#xff0c;2024上半年的软考架构得分点你知道了吗&#xff1f; 目标不光是把历年母题的考点规律吃透&#xff0c;还要规划好各类题型的做题时间&#xff0c;除了纸质版还要上机模拟&#xff0c;更好的适应机考&am…

将java项目上传到GitHub步骤

文章目录 一、GitHub 作用二、github如何修改默认分支为master三、手把手教你把项目上传github上四、github怎么删除仓库或项目五、github配置ssh key密钥的步骤六、执行到push时报错的解决办法七、github怎么修改仓库语言 一、GitHub 作用 GitHub 是一个存放软件代码的网站&a…

上海计算机学会2023年9月月赛C++丙组T2Z形填充

题目描述 给定一个整数 n&#xff0c;再给定 n2 个字符&#xff0c;请将这些字符以 z 形排成一个 nn 的矩阵。 z 形的定义是&#xff0c;第一个字符在左上角&#xff0c;然后沿对角线以 z 形放置字符。对于 n4 &#xff0c;z 形排列的先后顺序标记如下&#xff1a; 输入格式 …

基于Spring Boot的网页即时聊天系统

目录 一、系统总体功能设计 二、开发工具及环境 三、前台系统主要功能实现界面展示 1.登入模块 2.主页模块 3.好友设置模块 4.好友动态模块 5.个人中心模块 6.好友设置详情 7.视频通话 8.语音通话 9.对消息操作 四、后台系统主要功能实现界面展示 1.登入模块 2.后…

Git 分支命令操作详解

目录 1、分支的特点 2、分支常用操作 3、分支的使用 3.1、查看分支 3.2、创建分支 3.3、修改分支 3.4、切换分支 3.5、合并分支 3.6、产生冲突 3.7、解决冲突 3.8、创建分支和切换分支说明 1、分支的特点 同时并行推进多个功能开发&#xff0c;提高开发效率。各个分…

show profile

功能 当你执行一个复杂的 SQL 查询时&#xff0c;这个命令可以帮助你了解查询的各个部分花费了多少时间&#xff0c;从而找到可能的性能瓶颈。默认情况下&#xff0c;参数处于关闭状态&#xff0c;并保存最近15次的运行结果 开启 查看是否支持 SHOW VARIABLES LIKE profili…

如何给文件和文件夹添加备注信息

1. 给文件添加备注信息 1. 打开文件夹&#xff0c;点击查看 → 选项 → 更改文件夹和搜索选项 → 勾除隐藏受保护的操作系统文件 → 勾选显示隐藏的文件、文件夹和驱动器&#xff1b; 2. listary工具搜索desktop.ini&#xff0c;随便点击一个desktop.ini文件&#xff0c;即可…

Java String转JSONObject时保持字段顺序不变

Java String转JSONObject时保持字段顺序不变 问题背景解决方案 问题背景 在业务接口开发过程中&#xff0c;有一个新增接口&#xff0c;需要支持批量新增数据&#xff0c;这时入参就需要用到 json 格式数据&#xff0c;且包含 list 集合&#xff0c;比如这样的数据格式&#x…

ZeptoMail邮箱API发送邮件的参数如何配置?

ZeptoMail邮箱API发送邮件的步骤&#xff1f;怎么使用API接口&#xff1f; 在使用ZeptoMail邮箱API发送邮件时&#xff0c;正确的参数配置是确保邮件能够成功发送的关键。下面&#xff0c;AokSend将详细介绍如何配置ZeptoMail邮箱API发送邮件的参数。 ZeptoMail邮箱API发送邮…

Web界面加持!数据库备份神器,助你轻松备份数据!

使用这款带有Web界面的数据库备份神器&#xff0c;你可以轻松设置定时备份&#xff0c;确保数据安全无忧。备份结果即时通知&#xff0c;让你随时掌握备份状态。备份完成后&#xff0c;你将收到备份结果通知。无论是成功备份还是出现错误&#xff0c;你都能及时了解备份情况&am…

Failed to start tomcat.service: Unit is not loaded properly: Bad message 如何解决?

错误 “Failed to start tomcat.service: Unit is not loaded properly: Bad message” 通常意味着的 tomcat.service systemd 配置文件存在语法错误或配置不正确。为了解决这个问题&#xff0c;一步步检查和修正这个服务文件。 1. 检查 tomcat.service 文件 首先&#xff0c…

初识 Linux线程

再学习完Linux进程后,本期,我们来讲解Linux线程 1.为什么需要线程 在之前学习进程前,我们写的所有代码几乎都是单个执行流的,也就是说我们的代码只有一条路走. 在学习进程后,我们可以通过fork进行进程创建,给进程分配任务进行多执行流执行任务,问题来了 那我们为什么还需要…

会员卡积分收银源码系统 支持多门店系统 带完整的安装代码包以及安装搭建教程

在数字化浪潮的推动下&#xff0c;传统零售行业面临着巨大的转型压力。为了满足现代消费者多样化的需求&#xff0c;提高门店管理效率和顾客满意度&#xff0c;小编给大家分享一款会员卡积分收银源码系统——支持多门店系统&#xff0c;并附带了完整的安装代码包以及安装搭建教…