当前位置: 首页 > 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;逐步逼近最优解。与坐标下…...

浅谈 React Hooks

React Hooks 是 React 16.8 引入的一组 API&#xff0c;用于在函数组件中使用 state 和其他 React 特性&#xff08;例如生命周期方法、context 等&#xff09;。Hooks 通过简洁的函数接口&#xff0c;解决了状态与 UI 的高度解耦&#xff0c;通过函数式编程范式实现更灵活 Rea…...

超短脉冲激光自聚焦效应

前言与目录 强激光引起自聚焦效应机理 超短脉冲激光在脆性材料内部加工时引起的自聚焦效应&#xff0c;这是一种非线性光学现象&#xff0c;主要涉及光学克尔效应和材料的非线性光学特性。 自聚焦效应可以产生局部的强光场&#xff0c;对材料产生非线性响应&#xff0c;可能…...

FFmpeg 低延迟同屏方案

引言 在实时互动需求激增的当下&#xff0c;无论是在线教育中的师生同屏演示、远程办公的屏幕共享协作&#xff0c;还是游戏直播的画面实时传输&#xff0c;低延迟同屏已成为保障用户体验的核心指标。FFmpeg 作为一款功能强大的多媒体框架&#xff0c;凭借其灵活的编解码、数据…...

腾讯云V3签名

想要接入腾讯云的Api&#xff0c;必然先按其文档计算出所要求的签名。 之前也调用过腾讯云的接口&#xff0c;但总是卡在签名这一步&#xff0c;最后放弃选择SDK&#xff0c;这次终于自己代码实现。 可能腾讯云翻新了接口文档&#xff0c;现在阅读起来&#xff0c;清晰了很多&…...

Bean 作用域有哪些?如何答出技术深度?

导语&#xff1a; Spring 面试绕不开 Bean 的作用域问题&#xff0c;这是面试官考察候选人对 Spring 框架理解深度的常见方式。本文将围绕“Spring 中的 Bean 作用域”展开&#xff0c;结合典型面试题及实战场景&#xff0c;帮你厘清重点&#xff0c;打破模板式回答&#xff0c…...

通过 Ansible 在 Windows 2022 上安装 IIS Web 服务器

拓扑结构 这是一个用于通过 Ansible 部署 IIS Web 服务器的实验室拓扑。 前提条件&#xff1a; 在被管理的节点上安装WinRm 准备一张自签名的证书 开放防火墙入站tcp 5985 5986端口 准备自签名证书 PS C:\Users\azureuser> $cert New-SelfSignedCertificate -DnsName &…...

如何配置一个sql server使得其它用户可以通过excel odbc获取数据

要让其他用户通过 Excel 使用 ODBC 连接到 SQL Server 获取数据&#xff0c;你需要完成以下配置步骤&#xff1a; ✅ 一、在 SQL Server 端配置&#xff08;服务器设置&#xff09; 1. 启用 TCP/IP 协议 打开 “SQL Server 配置管理器”。导航到&#xff1a;SQL Server 网络配…...

ubuntu22.04 安装docker 和docker-compose

首先你要确保没有docker环境或者使用命令删掉docker sudo apt-get remove docker docker-engine docker.io containerd runc安装docker 更新软件环境 sudo apt update sudo apt upgrade下载docker依赖和GPG 密钥 # 依赖 apt-get install ca-certificates curl gnupg lsb-rel…...

​​企业大模型服务合规指南:深度解析备案与登记制度​​

伴随AI技术的爆炸式发展&#xff0c;尤其是大模型&#xff08;LLM&#xff09;在各行各业的深度应用和整合&#xff0c;企业利用AI技术提升效率、创新服务的步伐不断加快。无论是像DeepSeek这样的前沿技术提供者&#xff0c;还是积极拥抱AI转型的传统企业&#xff0c;在面向公众…...

React核心概念:State是什么?如何用useState管理组件自己的数据?

系列回顾&#xff1a; 在上一篇《React入门第一步》中&#xff0c;我们已经成功创建并运行了第一个React项目。我们学会了用Vite初始化项目&#xff0c;并修改了App.jsx组件&#xff0c;让页面显示出我们想要的文字。但是&#xff0c;那个页面是“死”的&#xff0c;它只是静态…...