当前位置: 首页 > news >正文

uniapp小程序实现弹幕不重叠

uniapp小程序实现弹幕不重叠

1、在父组件中引入弹幕组件

<template><!-- 弹幕 --><barrage ref="barrage" class="barrage-content" @reloadDanmu="reloadDanmu"></barrage>
</template>
<script>import barrage from './components/barrage.vue'import {getBarrageListApi} from '@/api/voteApi.js'export default {components: {barrage},data() {return {danmuList: [], // 弹幕列表danmuContion: { // 弹幕查询条件page: 1,size: 200}},onLoad(){this.getBarrageList()},methods: {async getBarrageList(isInit) {try {let res = await getBarrageListApi(this.danmuContion)let resData = (res && res.data) || {}let list = Array.isArray(resData.records) ? resData.records : []list.map((item) => {item.color = '#fff'item.timestampt = new Date().getTime()item.image = {head: {src: item.avatarUrl,width: 44,height: 44}, // 弹幕头部添加图片gap: 8 // 图片与文本间隔}item.content = `{${item.nickname}} 已为《${item.voteName}》投下宝贵的一票`})let danmuLength = this.danmuList.lengththis.danmuList = listthis.addBarrage(isInit || danmuLength === 0)} catch (e) {uni.showToast({title: (e && e.message) || '查询弹幕列表失败',icon: 'none',during: 2000})}},addBarrage(isInit) {if (!isInit || !this.danmuList.length) {return}const barrageComp = this.$refs && this.$refs.barrage || {}barrageComp.getBarrageInstance({duration: 15, // 弹幕动画时长 (移动 1500px 所需时长)lineHeight: 2.4, // 弹幕行高padding: [0, 0, 0, 0], // 弹幕区四周留白alpha: 1, // 全局透明度font: '10px PingFang SC', // 全局字体range: [0, 1], // 弹幕显示的垂直范围,支持两个值。[0,1]表示弹幕整个随机分布,tunnelShow: false, // 显示轨道线tunnelMaxNum: 200, // 隧道最大缓冲长度maxLength: 5000, // 弹幕最大字节长度,汉字算双字节safeGap: 20, // 发送时的安全间隔enableTap: false, // 点击弹幕停止动画高亮显示danmuList: this.danmuList})},async reloadDanmu(type) {const barrageComp = this.$refs && this.$refs.barrage || {}if(type === 'addDanmu') {await this.getBarrageList(false)barrageComp.open()barrageComp.addData(this.danmuList)return}await this.getBarrageList(true)}, }
</script><style lang="less" scoped>.barrage-conten {width: 100%;height: 156rpx;position: absolute;top: 192rpx;box-sizing: border-box;}
</style>

2、弹幕组件

 <template><view class="barrage-area" :style="{'opacity': alpha, 'font-size': fontSize*2 + 'rpx', 'padding': padding}"><block v-for="(tunnel, tunnelId) in tunnels" :key="tunnelId"><view class="barrage-tunnel":style="{'height': tunnel.height*2 + 'rpx', 'border-top-width': (tunnelShow ? 1 : 0) + 'px'}"><view class="tunnel-tips" :style="{'display': !tunnelShow ? 'none' : 'block'}">轨道{{tunnelId}}</view><block v-for="(bullet, bulletId) in tunnel.bullets" :key="bullet.timestampt + bulletId"><view :data-tunnelid="{tunnelId}" :data-bulletid="{bulletId}":class="['bullet-item', bullet.duration > 0 ? 'bullet-move' : '', bullet.paused ? 'paused' : '']":style="{'color': bullet.paused ? '#fff' : bullet.color, 'line-height': tunnel.height*2 + 'rpx', 'animation-duration': bullet.duration + 's', 'animation-play-state': bullet.paused ? 'paused' : 'running'}"@animationend="onAnimationend" @tap="onTapBullet"><image class="bullet-item_img" v-if="bullet.image && bullet.image.head":style="{'width': bullet.image.head.width + 'rpx', 'height': bullet.image.head.height + 'rpx'}"mode="aspectFill" :src="bullet.image.head.src"></image><view class="bullet-item_text":style="{'margin':'0 ' + (bullet.image && bullet.image.gap || 0) + 'rpx', opacity: 1}"><text>{{bullet.content}}</text></view></view></block></view></block></view>
</template><script>export default {data() {return {fontSize: 10, // 字体大小,单位pxwidth: 375, // 弹幕区域宽度height: 80, // 弹幕区域高度duration: 15, // 弹幕动画时长lineHeight: 3, // 弹幕行高padding: [0, 0, 0, 0], // 弹幕区四周留白alpha: 1, // 全局透明度font: '10px PingFang SC', // 全局字体range: [0, 1], // 弹幕显示的垂直范围,支持两个值。[0,1]表示弹幕整个随机分布,tunnelShow: false, // 显示轨道线tunnelMaxNum: 200, // 轨道最大缓冲长度maxLength: 5000, // 弹幕最大字节长度,汉字算双字节safeGap: 20, // 发送时的安全间隔enableTap: false, // 点击弹幕停止动画高亮显示tunnelHeight: 0,tunnelNum: 0,tunnels: [],idleTunnels: null,enableTunnels: {},distance: 1500, // 移动距离, 单位pxsystemInfo: {},danmuList: []};},methods: {init() {this.fontSize = this.getFontSize(this.font)this.idleTunnels = new Set()this.enableTunnels = new Set()this.tunnels = []this.availableHeight = (this.height - this.padding[0] - this.padding[2])this.tunnelHeight = this.fontSize * this.lineHeight// 轨道行数 = 弹幕区域高度/(单个弹幕高度+下边距)this.tunnelNum = Math.floor(this.availableHeight / (this.tunnelHeight + 15))// tunnel(轨道)class Tunnel {constructor(opt = {}) {const defaultTunnelOpt = {tunnelId: 0,height: 0, // 轨道高度width: 0, // 轨道宽度safeGap: 4, // 相邻弹幕安全间隔maxNum: 10, // 缓冲队列长度bullets: [], // 弹幕last: -1, // 上一条发送的弹幕序号bulletStatus: [], // 0 空闲,1 占用中disabled: false, // 禁用中sending: false, // 弹幕正在发送}Object.assign(this, defaultTunnelOpt, opt)this.bulletStatus = new Array(this.maxNum).fill(0)class Bullet {constructor(opt = {}) {this.bulletId = opt.bulletId}/*** image 结构* {*   head: {src, width, height},*   gap: 4 // 图片与文本间隔* }*/addContent(opt = {}) {const defaultBulletOpt = {duration: 0, // 动画时长passtime: 0, // 弹幕穿越右边界耗时content: '', // 文本color: '#000000', // 默认黑色width: 0, // 弹幕宽度height: 0, // 弹幕高度image: {}, // 图片paused: false // 是否暂停}Object.assign(this, defaultBulletOpt, opt)}removeContent() {this.addContent({})}}for (let i = 0; i < this.maxNum; i++) {this.bullets.push(new Bullet({bulletId: i,}))}}disable() {this.disabled = truethis.last = -1this.sending = falsethis.bulletStatus = new Array(this.maxNum).fill(1)this.bullets.forEach(bullet => bullet.removeContent())}enable() {if (this.disabled) {this.bulletStatus = new Array(this.maxNum).fill(0)}this.disabled = false}clear() {this.last = -1this.sending = falsethis.bulletStatus = new Array(this.maxNum).fill(0)this.bullets.forEach(bullet => bullet.removeContent())}getIdleBulletIdx() {return this.bulletStatus.indexOf(0)}getIdleBulletNum() {let count = 0this.bulletStatus.forEach(status => {if (status === 0) count++})return count}addBullet(opt) {if (this.disabled) returnconst idx = this.getIdleBulletIdx()if (idx >= 0) {this.bulletStatus[idx] = 1this.bullets[idx].addContent(opt)}}removeBullet(bulletId) {if (this.disabled) returnthis.bulletStatus[bulletId] = 0const bullet = this.bullets[bulletId]bullet.removeContent()}}for (let i = 0; i < this.tunnelNum; i++) {this.idleTunnels.add(i) // 空闲的轨道id集合this.enableTunnels.add(i) // 可用的轨道id集合this.tunnels.push(new Tunnel({ // 轨道集合width: this.width,height: this.tunnelHeight,safeGap: this.safeGap,maxNum: this.tunnelMaxNum,tunnelId: i,}))}// 筛选符合范围的轨道this.setRange()},resize() {const query = uni.createSelectorQuery().in(this)query.select('.barrage-area').boundingClientRect((res) => {res = res || {}let systemInfo = uni.getSystemInfoSync()this.systemInfo = systemInfo || {}this.width = res.width || systemInfo.windowWidththis.height = res.height || 300this.last = -1this.$emit('reloadDanmu')}).exec()},// 设置显示范围 range: [0,1]setRange(range) {range = range || this.rangeconst top = range[0] * this.tunnelNumconst bottom = range[1] * this.tunnelNum// 释放符合要求的轨道// 找到目前空闲的轨道const idleTunnels = new Set()const enableTunnels = new Set()this.tunnels.forEach((tunnel, tunnelId) => {if (tunnelId >= top && tunnelId < bottom) {const disabled = tunnel.disabledtunnel.enable()enableTunnels.add(tunnelId)if (disabled || this.idleTunnels.has(tunnelId)) {idleTunnels.add(tunnelId)}} else {tunnel.disable()}})this.idleTunnels = idleTunnelsthis.enableTunnels = enableTunnelsthis.range = range},setFont(font) {this.font = font},setAlpha(alpha) {if (typeof alpha !== 'number') returnthis.alpha = alpha},setDuration(duration) {if (typeof duration !== 'number') returnthis.duration = durationthis.clear()},// 开启弹幕open() {this._isActive = true},// 关闭弹幕,清除所有数据close(cb) {this._isActive = falsethis.clear(cb)},clear(cb) {this.tunnels.forEach(tunnel => tunnel.clear())this.idleTunnels = new Set(this.enableTunnels)if (typeof cb === 'function') {cb()}},// 添加一批弹幕,轨道满时会被丢弃addData(data = []) {if (!this._isActive || !data || !data.length) returndata.forEach((item, index) => {item.timestampt = new Date().getTime()item.content = item.content || ''item.content = this.substring(item.content, this.maxLength)if (!item.width) {// 一个弹幕总长度=头像(包含边框)+文本+内边距+外边距item.width = (44 + 4) + item.content.length * this.fontSize * 2 + (8 + 20) + 60item.width = Math.ceil(((this.systemInfo.windowWidth || 375) / 375) * (item.width / 2))}this.addBullet2Tunnel(item, index)})// 更新弹幕this.updateBullets()},// 添加至轨道addBullet2Tunnel(opt = {}, index) {const tunnel = this.getIdleTunnel(index)if (tunnel === null) returnconst tunnelId = tunnel.tunnelIdtunnel.addBullet(opt)if (tunnel.getIdleBulletNum() === 0) {this.idleTunnels.delete(tunnelId)}},updateBullets() {if (!this.tunnels || !this.tunnels.length) {return}this.tunnels.map((a) => {a.batchTime = 0 // 通过一批弹幕花费(即一次addData添加的所有弹幕)的时间a.lastBulletIndex = a.lastBulletIndex >= 0 ? a.lastBulletIndex : -1 // 轨道最后通过的弹幕下标a.bullets && a.bullets.map((b, bIndex) => {if ((a.lastBulletIndex === -1 || bIndex > a.lastBulletIndex) && b.content) {a.lastBulletIndex = bIndexconst duration = this.distance * this.duration / (this.distance + b.width)const passDistance = b.width + a.safeGap// 等上一条通过右边界b.passtime1 = Math.ceil(passDistance * this.duration * 1000 / this.distance)a.batchTime += b.passtime1}})this.tunnelAnimate(a)})let list = JSON.parse(JSON.stringify(this.tunnels))list.sort((a, b) => {return b.batchTime - a.batchTime})let lastBullet = list[0].bullets[list[0].lastBulletIndex]// 最后一条弹幕通过屏幕的时间let lastPassTime = list[0].batchTime + Math.ceil((this.width) * this.duration * 1000 / this.distance)console.log('最后一条弹幕通过屏幕的时间:', lastPassTime)let reloadDanmuTimer = setTimeout(() => {// 轨道已满,重置轨道并重新加载弹幕if (!this.idleTunnels || this.idleTunnels.size === 0) {this.last = -1this.$emit('reloadDanmu')} else {this.$emit('reloadDanmu', 'addDanmu')}clearTimeout(reloadDanmuTimer)}, lastPassTime)},tunnelAnimate(tunnel) {if (tunnel.disabled || tunnel.sending) returnconst next = (tunnel.last + 1) % tunnel.maxNumconst bullet = tunnel.bullets[next]if (!bullet) returnif (bullet.content || bullet.image) {tunnel.sending = truetunnel.last = nextconst duration = this.distance * this.duration / (this.distance + bullet.width)const passDistance = bullet.width + tunnel.safeGapbullet.duration = this.duration// 等上一条通过右边界bullet.passtime = Math.ceil(passDistance * bullet.duration * 1000 / this.distance)let sendTimer = setTimeout(() => {tunnel.sending = falsethis.tunnelAnimate(tunnel)clearTimeout(sendTimer)}, bullet.passtime)}},// 从还有余量的轨道中随机挑选一个getIdleTunnel(addIndex) {if (!this.idleTunnels || this.idleTunnels.size === 0) return nullconst idleTunnels = Array.from(this.idleTunnels)let index = -1if (this.tunnelNum == 2 && (addIndex || addIndex === 0)) { // 只有两个轨道的情况下,优先手动分发轨道index = addIndex % 2 === 0 ? 0 : 1}if (index === -1 || (!idleTunnels[index] && idleTunnels[index] !== 0)) { // 随机选轨道index = this.getRandom(idleTunnels.length)}return this.tunnels[idleTunnels[index]]},animationend(opt) {const {tunnelId,bulletId} = optconst tunnel = this.tunnels[tunnelId]const bullet = tunnel && tunnel.bullets && tunnel.bullets[bulletId]if (!tunnel || !bullet) returntunnel.removeBullet(bulletId)this.idleTunnels.add(tunnelId)},tapBullet(opt) {if (!this.enableTap) returnconst {tunnelId,bulletId} = optconst tunnel = this.tunnels[tunnelId]const bullet = tunnel.bullets[bulletId]bullet.paused = !bullet.paused},// 初始化弹幕组件数据getBarrageInstance(opt) {for (let key in opt) {this[key] = opt[key]}const query = uni.createSelectorQuery().in(this)query.select('.barrage-area').boundingClientRect((res) => {res = res || {}let systemInfo = uni.getSystemInfoSync()this.systemInfo = systemInfo || {}this.width = res.width || systemInfo.windowWidththis.height = res.height || 80this.init()this.open()this.addData(this.danmuList)}).exec()},onAnimationend(e) {const {tunnelid,bulletid} = e.currentTarget.datasetthis.animationend({tunnelId: tunnelid,bulletId: bulletid})},onTapBullet(e) {const {tunnelid,bulletid} = e.currentTarget.datasetthis.tapBullet({tunnelId: tunnelid,bulletId: bulletid})},// 获取字节长度,中文算2个字节getStrLen(str) {// eslint-disable-next-line no-control-regexreturn str.replace(/[^\x00-\xff]/g, 'aa').length},// 截取指定字节长度的子串substring(str, n) {if (!str) return ''const len = this.getStrLen(str)if (n >= len) return strlet l = 0let result = ''for (let i = 0; i < str.length; i++) {const ch = str.charAt(i)// eslint-disable-next-line no-control-regexl = /[^\x00-\xff]/i.test(ch) ? l + 2 : l + 1result += chif (l >= n) break}return result},getRandom(max = 10, min = 0) {return Math.floor(Math.random() * (max - min) + min)},getFontSize(font) {const reg = /(\d+)(px)/iconst match = font.match(reg)return (match && match[1]) || 10},}}
</script><style scoped>.barrage-area {position: relative;box-sizing: border-box;width: 100%;height: 100%;z-index: 2;pointer-events: auto;overflow-x: hidden;}.barrage-tunnel {box-sizing: border-box;position: relative;display: flex;align-items: center;border-top: 1px solid #CCB24D;width: 100%;margin-bottom: 30rpx;}.tunnel-tips {display: inline-block;margin-left: 60px;}.bullet-item {position: absolute;display: flex;align-items: center;top: 0;left: 100%;white-space: nowrap;background: rgba(0, 0, 0, 0.3);border-radius: 80rpx;padding: 0 20rpx 0 0;}.bullet-item.paused {background: #000;opacity: 0.6;padding: 0 10px;z-index: 2;}.bullet-item_img {max-height: 100%;border-radius: 50%;border: 2px solid #FFFFFF;}.bullet-item_text {display: inline-block;margin: 0;}.bullet-move {animation: 0s linear slidein}@keyframes slidein {0% {transform: translate3d(0, 0, 0)}100% {transform: translate3d(-1500px, 0, 0)}}
</style>

相关文章:

uniapp小程序实现弹幕不重叠

uniapp小程序实现弹幕不重叠 1、在父组件中引入弹幕组件 <template><!-- 弹幕 --><barrage ref"barrage" class"barrage-content" reloadDanmu"reloadDanmu"></barrage> </template> <script>import barr…...

快速排序学习优化

首先&#xff0c;上图。 ‘’’ cpp int partSort(int *a ,int left,int right) {int keyi left; //做左侧基准while(left<right){while(left<right && a[right]>a[keyi]){right--;}while(left<right && a[left]<a[keyi]){left;}swap(a[left…...

微信流量主挑战:三天25用户!功能未完善?(新纪元4)

&#x1f389;【小程序上线第三天&#xff01;突破25用户大关&#xff01;】&#x1f389; 嘿&#xff0c;大家好&#xff01;今天是我们小程序上线的第三天&#xff0c;我们的用户量已经突破了25个&#xff01;昨天还是16个&#xff0c;今天一觉醒来竟然有25个&#xff01;这涨…...

jetson 无显示器配置WIFI

我使用的 jetpack 版本是 6.1&#xff0c;发现自带 NetworkManager 软件包&#xff0c;此软件包包含一个守护程序、一个命令行界面&#xff08;nmcli&#xff09;和一个基于 curses 的界面&#xff08;nmtui&#xff09;。 可以使用 nmcli 命令配置wifi&#xff0c;nmcli 示例…...

SpringCloudAlibaba实战入门之路由网关Gateway断言(十二)

上一节课中我们初步讲解了网关的基本概念、基本功能,并且带大家实战体验了一下网关的初步效果,这节课我们继续学习关于网关的一些更高级有用功能,比如本篇文章的断言。 一、网关主要组成部分 上图中是核心的流程图,最主要的就是Route、Predicates 和 Filters 作用于特定路…...

【ES6复习笔记】ES6的模块化(18)

模块化的概念 模块化是指将一个复杂的系统分解为多个模块&#xff0c;每个模块完成一个特定的功能&#xff0c;模块之间通过接口进行通信。模块化的目的是提高代码的可读性、可维护性和可重用性。 模块化规范产品&#xff0c; ES6 之前的模块化规范有&#xff1a; CommonJS …...

兰亭妙微:专注医疗 UI 设计,点亮数字化医疗新视界

医疗行业界面解决方案以医患使用者为中心&#xff0c;遵循行业使用习惯和表达方式&#xff0c;优化使用流程、设计简洁、人性化的操作界面&#xff0c;采用插画、三维动画、微动效的创作方法&#xff0c;让用户感受到愉悦易用美观的使用体验。蓝蓝设计与知名企业合作项目有&…...

c# 线程 AutoResetEvent 的Set()函数多次调用

本文部分内容摘自ChatGPT 在 C# 中&#xff0c;AutoResetEvent 是一种用于线程同步的机制&#xff0c;它的行为类似于一个信号量&#xff0c;主要用于在多线程环境中发出信号并控制线程的执行。AutoResetEvent 的主要特点是每当调用 Set() 方法时&#xff0c;信号会被设置&…...

汽车行业的MES系统方案(附案例资料合集)

针对汽车行业的MES系统方案&#xff0c;以下是一些关键点和实施案例&#xff1a; 核心功能&#xff1a; 实时监控&#xff1a;MES系统通过传感器和物联网技术实时监控生产线上的每一个环节&#xff0c;确保信息的及时传递。数据分析&#xff1a;系统对收集的数据进行深度分析&a…...

基于监督学习的神经网络控制算法详细介绍和例程

基于监督学习的神经网络控制算法通常用于对已有数据进行训练&#xff0c;以学习输入与输出之间的映射关系。下面我将详细介绍这种算法的原理和流程&#xff0c;并提供一个简单的例程&#xff1a; 算法原理&#xff1a; 输入&#xff1a;给定一组已知的输入信号和对应的输出控制…...

springMVC-请求响应

springmvc——一 站式web框架&#xff0c;核心是处理http请求响应。 前后端分离&#xff1a;需要序列化&#xff0c;服务端把数据序列化成字符串或者流给前端&#xff0c;前端又把json转成对象&#xff0c;前端的叫反序列化。前端把数据序列化转成字符串给服务器&#xff0c;服…...

数据交易和联邦学习的背景下的安全属性

数据交易和联邦学习的背景下的安全属性 在数据交易和联邦学习的背景下,安全属性对于保护数据隐私、确保系统可靠性和维护交易公平性至关重要。以下将分析文章中涉及的安全属性以及分析这些属性的目的。 涉及的安全属性 双向认证:文章虽未明确提及传统意义上的双向认证机制,…...

顶顶通呼叫中心中间件mod_cti模块安全增强,预防盗打风险(mod_cti基于FreeSWITCH)

文章目录 前言联系我们mod_cti版本支持安全加强说明 前言 FreeSWITCH暴露在公网最大的风险就是被不法之人盗打 出现盗打的主要原因以下几点&#xff1a; 分机密码太简单或者密码泄露了拨号方案配置不合理sofia配置错误 所以我们给顶顶通呼叫中心中间件添加了安全加强功能&am…...

Datawhale-AI冬令营二期

目录 一、番茄时钟&#xff08;1&#xff09;输入Prompt&#xff08;2&#xff09;创建 HTML 文件解析1&#xff1a;HTML结构解析2&#xff1a;计时器内容解析3&#xff1a;按钮区域解析4&#xff1a;脚本引用 &#xff08;3&#xff09;使用JavaScript实现时钟功能解析1&#…...

Python的秘密基地--[章节7] Python 并发与多线程编程

第7章&#xff1a;Python 并发与多线程编程 随着计算机硬件的发展&#xff0c;多核处理器已经成为主流。为了更好地利用多核资源&#xff0c;提高程序的运行效率&#xff0c;Python 提供了并发&#xff08;Concurrency&#xff09;和并行&#xff08;Parallelism&#xff09;编…...

每天五分钟机器学习:凸函数

一、凸函数的定义:何为“凸”? 在数学上,凸函数的概念源于几何直观——想象一个平面上的曲线,如果在这条曲线上的任意两点之间连线段总是位于曲线的下方(或恰好与曲线重合),则这条曲线所对应的函数即为凸函数。更正式地,对于定义在实数集(或某个子集)上的函数f(x),…...

Merry Christmas HTML

简单分享 Merry Christmas HTML 设计的核心代码 HTML: <body class"card"> <div class"dialog"><div class"dialog-in"><div class"dialog-msg"><div class"heading">Youve got a post card!…...

JavaScript甘特图 dhtmlx-gantt

背景 需求是在后台中&#xff0c;需要用甘特图去展示管理任务相关视图&#xff0c;并且不用依赖vue&#xff0c;兼容JavaScript原生开发。最终使用dhtmlx-gantt&#xff0c;一个半开源的库&#xff0c;基础功能免费&#xff0c;更多功能付费。 甘特图需求如图&#xff1a; 调…...

阿里云-将旧服务器数据与配置完全迁移至新服务器

文章目录 一&#xff1a;创建镜像二&#xff1a;将创建好的镜像复制到新服务器所在的目标地域&#xff08;如果新服务器与镜像在同一地域就不用进行这一操作&#xff09;三&#xff1a;将镜像配置到新服务器上四&#xff1a;导出安全组&#xff08;如果新服务器与旧服务器使用同…...

以EM算法为例介绍坐标上升(Coordinate Ascent)算法:中英双语

中文版 什么是 Coordinate Ascent 算法&#xff1f; Coordinate Ascent&#xff08;坐标上升&#xff09;是一种优化算法&#xff0c;它通过在每次迭代时优化一个变量&#xff08;或一个坐标&#xff09;&#xff0c;并保持其他变量不变&#xff0c;逐步逼近最优解。与坐标下…...

(LeetCode 每日一题) 3442. 奇偶频次间的最大差值 I (哈希、字符串)

题目&#xff1a;3442. 奇偶频次间的最大差值 I 思路 &#xff1a;哈希&#xff0c;时间复杂度0(n)。 用哈希表来记录每个字符串中字符的分布情况&#xff0c;哈希表这里用数组即可实现。 C版本&#xff1a; class Solution { public:int maxDifference(string s) {int a[26]…...

第19节 Node.js Express 框架

Express 是一个为Node.js设计的web开发框架&#xff0c;它基于nodejs平台。 Express 简介 Express是一个简洁而灵活的node.js Web应用框架, 提供了一系列强大特性帮助你创建各种Web应用&#xff0c;和丰富的HTTP工具。 使用Express可以快速地搭建一个完整功能的网站。 Expre…...

ubuntu搭建nfs服务centos挂载访问

在Ubuntu上设置NFS服务器 在Ubuntu上&#xff0c;你可以使用apt包管理器来安装NFS服务器。打开终端并运行&#xff1a; sudo apt update sudo apt install nfs-kernel-server创建共享目录 创建一个目录用于共享&#xff0c;例如/shared&#xff1a; sudo mkdir /shared sud…...

智慧工地云平台源码,基于微服务架构+Java+Spring Cloud +UniApp +MySql

智慧工地管理云平台系统&#xff0c;智慧工地全套源码&#xff0c;java版智慧工地源码&#xff0c;支持PC端、大屏端、移动端。 智慧工地聚焦建筑行业的市场需求&#xff0c;提供“平台网络终端”的整体解决方案&#xff0c;提供劳务管理、视频管理、智能监测、绿色施工、安全管…...

JVM垃圾回收机制全解析

Java虚拟机&#xff08;JVM&#xff09;中的垃圾收集器&#xff08;Garbage Collector&#xff0c;简称GC&#xff09;是用于自动管理内存的机制。它负责识别和清除不再被程序使用的对象&#xff0c;从而释放内存空间&#xff0c;避免内存泄漏和内存溢出等问题。垃圾收集器在Ja…...

Robots.txt 文件

什么是robots.txt&#xff1f; robots.txt 是一个位于网站根目录下的文本文件&#xff08;如&#xff1a;https://example.com/robots.txt&#xff09;&#xff0c;它用于指导网络爬虫&#xff08;如搜索引擎的蜘蛛程序&#xff09;如何抓取该网站的内容。这个文件遵循 Robots…...

用docker来安装部署freeswitch记录

今天刚才测试一个callcenter的项目&#xff0c;所以尝试安装freeswitch 1、使用轩辕镜像 - 中国开发者首选的专业 Docker 镜像加速服务平台 编辑下面/etc/docker/daemon.json文件为 {"registry-mirrors": ["https://docker.xuanyuan.me"] }同时可以进入轩…...

什么是Ansible Jinja2

理解 Ansible Jinja2 模板 Ansible 是一款功能强大的开源自动化工具&#xff0c;可让您无缝地管理和配置系统。Ansible 的一大亮点是它使用 Jinja2 模板&#xff0c;允许您根据变量数据动态生成文件、配置设置和脚本。本文将向您介绍 Ansible 中的 Jinja2 模板&#xff0c;并通…...

VM虚拟机网络配置(ubuntu24桥接模式):配置静态IP

编辑-虚拟网络编辑器-更改设置 选择桥接模式&#xff0c;然后找到相应的网卡&#xff08;可以查看自己本机的网络连接&#xff09; windows连接的网络点击查看属性 编辑虚拟机设置更改网络配置&#xff0c;选择刚才配置的桥接模式 静态ip设置&#xff1a; 我用的ubuntu24桌…...

免费PDF转图片工具

免费PDF转图片工具 一款简单易用的PDF转图片工具&#xff0c;可以将PDF文件快速转换为高质量PNG图片。无需安装复杂的软件&#xff0c;也不需要在线上传文件&#xff0c;保护您的隐私。 工具截图 主要特点 &#x1f680; 快速转换&#xff1a;本地转换&#xff0c;无需等待上…...