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

鸿蒙OSUniApp 开发的一键分享功能#三方框架 #Uniapp

使用 UniApp 开发的一键分享功能

在移动应用开发中,分享功能几乎是必不可少的一环。一个好的分享体验不仅能带来更多用户,还能提升产品的曝光度。本文将详细讲解如何在 UniApp 框架下实现一个简单高效的一键分享功能,适配多个平台。

各平台分享机制分析

首先我们需要了解不同平台的分享机制:

微信小程序的分享主要通过以下两种方式:

  1. 页面内分享:通过在页面中定义 onShareAppMessage 函数,用户点击右上角菜单的转发按钮时触发。

  2. 按钮分享:通过 button 组件,设置 open-type="share",用户点击按钮时触发页面的 onShareAppMessage 函数。

  3. 直接分享:可以通过 Web Share API (仅部分现代浏览器支持)。

  4. 社交平台 SDK:如微信 JSSDK、QQ分享等。

  5. 复制链接:生成分享链接供用户手动复制。

了解了这些区别后,我们就可以开始实现我们的一键分享功能了。

实现通用的分享工具

首先,我们先创建一个通用的分享工具类,封装各平台的分享逻辑:

// utils/share.js/*** 通用分享工具类*/
class ShareUtil {/*** 分享到社交平台* @param {Object} options 分享参数* @param {string} options.title 分享标题* @param {string} options.summary 分享摘要* @param {string} options.imageUrl 分享图片* @param {string} options.targetUrl 分享链接* @param {Function} options.success 成功回调* @param {Function} options.fail 失败回调*/static share(options) {// 默认参数const defaultOptions = {title: '这是默认的分享标题',summary: '这是默认的分享摘要',imageUrl: 'https://your-website.com/default-share-image.png',targetUrl: 'https://your-website.com',success: () => {},fail: () => {}};// 合并参数const shareOptions = Object.assign({}, defaultOptions, options);// 根据平台执行不同的分享逻辑switch (uni.getSystemInfoSync().platform) {case 'android':case 'ios':// App平台使用uni.sharethis.appShare(shareOptions);break;case 'devtools':case 'mp-weixin':// 微信小程序平台,返回分享对象给onShareAppMessage使用return this.getWxShareOptions(shareOptions);default:// H5平台this.h5Share(shareOptions);break;}}/*** App平台分享实现*/static appShare(options) {// #ifdef APP-PLUSuni.share({provider: 'weixin', // 可选: weixin、sinaweibo、qqtype: 0, // 0:图文 1:纯文字 2:纯图片 3:音乐 4:视频 5:小程序title: options.title,summary: options.summary,imageUrl: options.imageUrl,href: options.targetUrl,scene: 'WXSceneSession', // WXSceneSession:会话 WXSceneTimeline:朋友圈 WXSceneFavorite:收藏success: (res) => {console.log('分享成功');options.success && options.success(res);},fail: (err) => {console.error('分享失败', err);options.fail && options.fail(err);}});// #endif}/*** 获取微信小程序分享参数*/static getWxShareOptions(options) {return {title: options.title,path: `/pages/index/index?targetUrl=${encodeURIComponent(options.targetUrl)}`,imageUrl: options.imageUrl,success: options.success,fail: options.fail};}/*** H5平台分享实现*/static h5Share(options) {// #ifdef H5// 检查浏览器是否支持 Web Share APIif (navigator.share) {navigator.share({title: options.title,text: options.summary,url: options.targetUrl,}).then(() => {console.log('分享成功');options.success && options.success();}).catch((err) => {console.error('分享失败', err);options.fail && options.fail(err);// 降级处理:不支持分享时复制链接this.copyShareLink(options);});} else {// 降级处理:不支持 Web Share API 时复制链接this.copyShareLink(options);}// #endif}/*** 复制分享链接(H5降级方案)*/static copyShareLink(options) {// #ifdef H5uni.setClipboardData({data: options.targetUrl,success: () => {uni.showToast({title: '链接已复制,请粘贴给好友',icon: 'none'});options.success && options.success();},fail: (err) => {uni.showToast({title: '复制失败,请长按链接复制',icon: 'none'});options.fail && options.fail(err);}});// #endif}
}export default ShareUtil;

在页面中使用分享功能

接下来,我们在页面中使用上面封装的分享工具:

<!-- pages/article/detail.vue -->
<template><view class="article-container"><!-- 文章内容 --><view class="article-content"><view class="article-title">{{ article.title }}</view><view class="article-info"><text class="author">{{ article.author }}</text><text class="time">{{ article.publishTime }}</text></view><rich-text :nodes="article.content"></rich-text></view><!-- 底部分享栏 --><view class="share-bar"><button class="share-btn" @tap="handleShare"><text class="iconfont icon-share"></text><text>一键分享</text></button><!-- 微信小程序专用分享按钮 --><!-- #ifdef MP-WEIXIN --><button class="share-btn" open-type="share"><text class="iconfont icon-wechat"></text><text>分享给好友</text></button><!-- #endif --></view></view>
</template><script>
import ShareUtil from '@/utils/share.js';export default {data() {return {article: {id: '',title: '如何成为一名优秀的前端开发者',author: '前端小菜鸟',publishTime: '2023-12-20',content: '<p>这是文章内容...</p>',coverImg: 'https://example.com/cover.jpg'},shareUrl: ''};},onLoad(options) {// 获取文章IDthis.article.id = options.id || '1';// 实际项目中这里通常会请求文章详情this.loadArticleDetail();// 生成分享链接this.shareUrl = this.generateShareUrl();},// 微信小程序分享配置onShareAppMessage() {return ShareUtil.share({title: this.article.title,summary: this.article.title,imageUrl: this.article.coverImg,targetUrl: this.shareUrl});},// App端分享到朋友圈配置(仅微信小程序支持)// #ifdef MP-WEIXINonShareTimeline() {return {title: this.article.title,imageUrl: this.article.coverImg,query: `id=${this.article.id}`};},// #endifmethods: {// 加载文章详情loadArticleDetail() {// 实际项目中这里会请求后端APIconsole.log('加载文章ID:', this.article.id);// uni.request({...})},// 生成分享链接generateShareUrl() {// 根据环境生成不同的分享链接let baseUrl = '';// #ifdef H5baseUrl = window.location.origin;// #endif// #ifdef MP-WEIXINbaseUrl = 'https://your-website.com';// #endif// #ifdef APP-PLUSbaseUrl = 'https://your-website.com';// #endifreturn `${baseUrl}/pages/article/detail?id=${this.article.id}`;},// 处理分享按钮点击handleShare() {// 微信小程序不需要处理,因为有专用的分享按钮// #ifndef MP-WEIXINShareUtil.share({title: this.article.title,summary: this.article.title,imageUrl: this.article.coverImg,targetUrl: this.shareUrl,success: () => {uni.showToast({title: '分享成功',icon: 'success'});},fail: (err) => {console.error('分享失败', err);uni.showToast({title: '分享失败',icon: 'none'});}});// #endif}}
};
</script><style lang="scss">
.article-container {padding: 30rpx;.article-content {margin-bottom: 100rpx;.article-title {font-size: 36rpx;font-weight: bold;margin-bottom: 20rpx;}.article-info {display: flex;font-size: 24rpx;color: #999;margin-bottom: 30rpx;.author {margin-right: 20rpx;}}}.share-bar {position: fixed;bottom: 0;left: 0;right: 0;display: flex;justify-content: space-around;padding: 20rpx;background-color: #fff;border-top: 1px solid #eee;.share-btn {display: flex;flex-direction: column;align-items: center;font-size: 24rpx;background-color: transparent;padding: 10rpx 30rpx;&::after {border: none;}.iconfont {font-size: 40rpx;margin-bottom: 5rpx;}}}
}
</style>

实现分享海报功能

除了直接分享功能外,在一些场景下,我们还需要生成分享海报,这在社交软件中非常常见,可以增强分享的辨识度。下面我们实现一个简单的海报生成和保存功能:

<!-- components/share-poster.vue -->
<template><view class="poster-container" v-if="visible"><view class="mask" @tap="hide"></view><view class="poster-content"><view class="poster-card"><image class="poster-image" :src="posterUrl" mode="widthFix"></image></view><view class="button-group"><button class="poster-btn cancel" @tap="hide">取消</button><button class="poster-btn save" @tap="savePoster">保存到相册</button></view></view></view>
</template><script>
export default {props: {visible: {type: Boolean,default: false},articleInfo: {type: Object,default: () => ({})}},data() {return {posterUrl: '',generating: false};},watch: {visible(val) {if (val && !this.posterUrl && !this.generating) {this.generatePoster();}}},methods: {// 隐藏海报hide() {this.$emit('update:visible', false);},// 生成海报async generatePoster() {try {this.generating = true;// 创建画布const ctx = uni.createCanvasContext('posterCanvas', this);// 画布尺寸const canvasWidth = 600;const canvasHeight = 900;// 绘制背景ctx.fillStyle = '#ffffff';ctx.fillRect(0, 0, canvasWidth, canvasHeight);// 绘制文章标题ctx.fillStyle = '#333333';ctx.font = 'bold 30px sans-serif';this.drawText(ctx, this.articleInfo.title, 40, 80, 520, 30);// 绘制封面图await this.drawImage(ctx, this.articleInfo.coverImg, 40, 150, 520, 300);// 绘制文章摘要ctx.fillStyle = '#666666';ctx.font = '26px sans-serif';this.drawText(ctx, this.articleInfo.summary, 40, 480, 520, 26);// 绘制二维码提示ctx.fillStyle = '#999999';ctx.font = '24px sans-serif';ctx.fillText('扫描二维码阅读全文', 150, 800);// 绘制二维码await this.drawImage(ctx, this.articleInfo.qrCodeUrl, 200, 600, 200, 200);// 完成绘制ctx.draw(true, () => {setTimeout(() => {// 将画布导出为图片uni.canvasToTempFilePath({canvasId: 'posterCanvas',success: (res) => {this.posterUrl = res.tempFilePath;this.generating = false;},fail: (err) => {console.error('导出海报失败', err);this.generating = false;uni.showToast({title: '生成海报失败',icon: 'none'});}}, this);}, 300);});} catch (error) {console.error('生成海报错误', error);this.generating = false;uni.showToast({title: '生成海报失败',icon: 'none'});}},// 绘制文本,支持多行截断drawText(ctx, text, x, y, maxWidth, lineHeight, maxLines = 3) {if (!text) return;let lines = [];let currentLine = '';for (let i = 0; i < text.length; i++) {currentLine += text[i];const currentWidth = ctx.measureText(currentLine).width;if (currentWidth > maxWidth) {lines.push(currentLine.slice(0, -1));currentLine = text[i];}}if (currentLine) {lines.push(currentLine);}// 限制最大行数if (lines.length > maxLines) {lines = lines.slice(0, maxLines);lines[maxLines - 1] += '...';}// 绘制每一行lines.forEach((line, index) => {ctx.fillText(line, x, y + index * lineHeight);});},// 绘制图片,返回PromisedrawImage(ctx, url, x, y, width, height) {return new Promise((resolve, reject) => {if (!url) {resolve();return;}uni.getImageInfo({src: url,success: (res) => {ctx.drawImage(res.path, x, y, width, height);resolve();},fail: (err) => {console.error('获取图片信息失败', err);reject(err);}});});},// 保存海报到相册savePoster() {if (!this.posterUrl) {uni.showToast({title: '海报还未生成完成',icon: 'none'});return;}// 获取保存到相册权限uni.authorize({scope: 'scope.writePhotosAlbum',success: () => {uni.saveImageToPhotosAlbum({filePath: this.posterUrl,success: () => {uni.showToast({title: '保存成功',icon: 'success'});this.hide();},fail: (err) => {console.error('保存图片失败', err);uni.showToast({title: '保存失败',icon: 'none'});}});},fail: () => {uni.showModal({title: '提示',content: '需要您授权保存图片到相册',confirmText: '去授权',cancelText: '取消',success: (res) => {if (res.confirm) {uni.openSetting();}}});}});}}
};
</script><style lang="scss">
.poster-container {position: fixed;top: 0;left: 0;right: 0;bottom: 0;z-index: 999;.mask {position: absolute;top: 0;left: 0;right: 0;bottom: 0;background-color: rgba(0, 0, 0, 0.7);}.poster-content {position: absolute;top: 50%;left: 50%;transform: translate(-50%, -50%);width: 80%;.poster-card {background-color: #fff;border-radius: 12rpx;overflow: hidden;padding: 20rpx;.poster-image {width: 100%;}}.button-group {display: flex;justify-content: space-between;margin-top: 40rpx;.poster-btn {width: 45%;height: 80rpx;line-height: 80rpx;border-radius: 40rpx;font-size: 28rpx;&.cancel {background-color: #f5f5f5;color: #666;}&.save {background-color: #fa6400;color: #fff;}}}}
}
</style>

然后在文章详情页添加海报分享按钮和组件:

<!-- 在pages/article/detail.vue中添加 -->
<template><view class="article-container"><!-- 原有内容 --><!-- ... --><!-- 底部分享栏增加海报按钮 --><view class="share-bar"><!-- 原有按钮 --><!-- ... --><!-- 海报分享按钮 --><button class="share-btn" @tap="showPoster"><text class="iconfont icon-poster"></text><text>生成海报</text></button></view><!-- 海报组件 --><share-poster :visible.sync="posterVisible" :article-info="posterInfo"></share-poster></view>
</template><script>
import ShareUtil from '@/utils/share.js';
import SharePoster from '@/components/share-poster.vue';export default {components: {SharePoster},data() {return {// 原有数据// ...// 海报相关posterVisible: false,posterInfo: {}};},methods: {// 原有方法// ...// 显示海报showPoster() {// 准备海报数据this.posterInfo = {title: this.article.title,coverImg: this.article.coverImg,summary: '这是文章摘要,实际项目中可能需要从文章内容中提取...',qrCodeUrl: 'https://example.com/qrcode.jpg'  // 实际开发中需要动态生成};// 显示海报组件this.posterVisible = true;}}
};
</script>

常见问题与解决方案

1. 小程序分享无法携带太多参数

微信小程序在分享时,path参数有长度限制,无法携带过多的查询参数。

解决方案:使用短ID或者短链接,后端提供一个短链接服务。

// 使用短ID替代完整参数
return {title: this.article.title,path: `/pages/article/detail?sid=abc123`,  // 使用短IDimageUrl: this.article.coverImg
};

2. App端分享图片不显示

在App端分享时,如果图片是相对路径或者小程序专有路径,可能导致分享图片无法显示。

解决方案:确保分享的图片是完整的HTTP/HTTPS URL,必要时可以先将本地图片上传到服务器。

// 确保图片URL是完整路径
if (imageUrl.indexOf('http') !== 0) {// 如果不是以http开头,可能需要转换imageUrl = 'https://your-domain.com' + imageUrl;
}

3. H5端分享兼容性问题

Web Share API 目前并非所有浏览器都支持,特别是在较老的浏览器上。

解决方案:添加降级处理,不支持 Web Share API 时提供复制链接功能。

// 代码中已实现了降级处理
if (navigator.share) {// 使用 Web Share API
} else {// 降级为复制链接this.copyShareLink(options);
}

4. 海报保存权限问题

用户可能拒绝授予保存图片到相册的权限。

解决方案:添加权限说明和引导,如果用户拒绝权限,提供跳转到设置页面的选项。

// 代码中已实现了权限处理
uni.authorize({scope: 'scope.writePhotosAlbum',success: () => {// 有权限,直接保存},fail: () => {// 没有权限,提示用户并引导去设置页面uni.showModal({title: '提示',content: '需要您授权保存图片到相册',confirmText: '去授权',cancelText: '取消',success: (res) => {if (res.confirm) {uni.openSetting();}}});}
});

性能优化与体验提升

  1. 预加载分享图片:提前下载和缓存分享图片,避免分享时的延迟。
  2. 海报缓存:可以缓存已生成的海报,避免重复生成。
  3. 增加分享动画:添加简单的动画效果,提升用户体验。
  4. 跟踪分享数据:记录用户的分享行为,进行数据分析。
// 预加载分享图
onReady() {// 预加载分享图片uni.getImageInfo({src: this.article.coverImg,success: (res) => {// 缓存图片路径this.cachedImagePath = res.path;}});
}

总结

通过本文,我们详细讲解了如何在 UniApp 中实现一键分享功能,包括:

  1. 不同平台分享机制的分析
  2. 封装通用分享工具类
  3. 页面中集成分享功能
  4. 实现分享海报生成与保存
  5. 常见问题的解决方案
  6. 性能优化建议

分享功能看似简单,但要做好跨平台适配和用户体验,还是需要考虑很多细节。希望本文能给大家在开发 UniApp 分享功能时提供一些帮助和思路。

在实际项目中,你可能还需要根据具体业务需求进行更多定制,比如增加更多分享渠道、自定义分享内容等。欢迎在评论区分享你的经验和想法!

相关文章:

鸿蒙OSUniApp 开发的一键分享功能#三方框架 #Uniapp

使用 UniApp 开发的一键分享功能 在移动应用开发中&#xff0c;分享功能几乎是必不可少的一环。一个好的分享体验不仅能带来更多用户&#xff0c;还能提升产品的曝光度。本文将详细讲解如何在 UniApp 框架下实现一个简单高效的一键分享功能&#xff0c;适配多个平台。 各平台分…...

Hive PredicatePushDown 谓词下推规则的计算逻辑

1. PredicatePushDown 谓词下推 谓词下推的处理顺序是先处理子节点的操作&#xff0c;子节点都处理完&#xff0c;然后处理父节点。 select web_site_sk from (select web_site_sk,web_name from web_site where web_cityPleasant Hill ) t where web_name <> site_…...

2024东北四省ccpc

F题 解题思路 数论 有限小数的条件 p q \frac{p}{q} qp​ 在 k k k 进制下是有限小数&#xff0c;当且仅当 q q q 的所有质因数都是 p p p 或 k k k 的质因数。 即&#xff0c;若 q q q 的质因数分解为 q ∏ i p i a i q \prod_{i} p_i^{a_i} q∏i​piai​​&#x…...

【C语言】初阶数据结构相关习题(二)

&#x1f386;个人主页&#xff1a;夜晚中的人海 今日语录&#xff1a;知识是从刻苦劳动中得来的&#xff0c;任何成就都是刻苦劳动的结果。——宋庆龄 文章目录 &#x1f384;一、链表内指定区间翻转&#x1f389;二、从链表中删去总和值为零的节点&#x1f680;三、链表求和&…...

DeepSeek执行流程加速指南:跨框架转换与编译优化的核心策略全解析

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…...

解决 Conda 安装 PyTorch 1.1.0 报错:excluded by strict repo priority(附三种解决方案)

# &#x1f4a5;解决 Conda 安装 PyTorch 1.1.0 报错问题&#xff1a;excluded by strict repo priority在使用旧版本 PyTorch&#xff08;例如 1.1.0&#xff09;时&#xff0c;有些开发者会遇到以下 conda 安装报错&#xff1a;LibMambaUnsatisfiableError: package pytorch-…...

面试从微前端拓展到iframe是如何通信的

一、跨域通信 1、父页面发消息给 iframe const iframe document.getElementById(myIframe); iframe.contentWindow.postMessage(form parent, https://iframe-domain.com)// iframe 接收 window.addEventListener(message, (event) > {if (event.origin ! https://paren…...

PyTorch循环神经网络(Pytotch)

文章目录 循环神经网络&#xff08;RNN&#xff09;简单的循环神经网络长短期记忆网络&#xff08;LSTM&#xff09;门控循环单元&#xff08;GRU&#xff09; 循环神经网络&#xff08;RNN&#xff09; 循环神经网络&#xff08;RecurrentNeuralNetwork&#xff0c;RNN&#…...

django中用 InforSuite RDS 替代memcache

在 Django 项目中&#xff0c;InforSuite RDS&#xff08;关系型数据库服务&#xff09;无法直接替代 Memcached&#xff0c;因为两者的设计目标和功能定位完全不同&#xff1a; 特性MemcachedInforSuite RDS核心用途高性能内存缓存&#xff0c;临时存储键值对数据持久化关系型…...

Git 常用命令详解

Git 常用命令详解&#xff08;含详细示例&#xff09; 本文整理了 Git 日常使用中最常用的命令&#xff0c;适合初学者和日常查阅&#xff0c;如有错误&#xff0c;敬请指正&#xff0c;谢谢&#xff01; ☁️ Git 使用流程入门&#xff08;从 pull 和 push 开始&#xff09; …...

AI、机器学习、深度学习:一文厘清三者核心区别与联系

AI、机器学习、深度学习&#xff1a;一文厘清三者核心区别与联系 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;可以分享一下给大家。点击跳转到网站。 https://www.captainbed.cn/ccc 前言 在人工智能技术席卷全球的今天&…...

《数字藏品社交化破局:React Native与Flutter的创新实践指南》

NFT&#xff0c;这种非同质化代币&#xff0c;赋予了数字资产独一无二的身份标识&#xff0c;从数字艺术作品到限量版虚拟物品&#xff0c;每一件NFT数字藏品都承载着独特的价值与意义。当React Native和Flutter这两大跨平台开发框架遇上NFT数字藏品&#xff0c;一场技术与创意…...

工业操作系统核心技术揭秘

摘要 随着工业 4.0 与智能制造的深入推进&#xff0c;工业操作系统作为工业数字化转型的核心支撑&#xff0c;其技术发展备受关注。本文深入剖析工业操作系统的核心技术&#xff0c;包括实时性保障机制、硬件抽象层设计、多任务管理策略等&#xff0c;结合技术原理与实际应用场…...

Python logging模块使用指南

Python 的 logging 模块是一个灵活且强大的日志记录工具&#xff0c;广泛应用于应用程序的调试、运行监控和问题排查。它提供了丰富的功能&#xff0c;包括多级日志记录、多种输出方式、灵活的格式配置等。以下是详细介绍&#xff1a; 一、为什么使用 logging 模块&#xff1f;…...

沃伦森智能无功补偿系统解决电力电容器频繁投切的隐患

在现代电力系统中&#xff0c;无功补偿设备的稳定运行直接影响电网质量。然而&#xff0c;电力电容器的频繁投切问题长期存在&#xff0c;如同电网的“慢性病”&#xff0c;不仅加速设备老化&#xff0c;还可能引发系统性风险。作为电力电子领域的领军企业&#xff0c;沃伦森电…...

【HarmonyOS 5】鸿蒙mPaaS详解

【HarmonyOS 5】鸿蒙mPaaS详解 一、mPaaS是什么&#xff1f; mPaaS 是 Mobile Platform as a Service 的缩写&#xff0c;即移动开发平台。 蚂蚁移动开发平台mPaaS &#xff0c;融合了支付宝科技能力&#xff0c;可以为移动应用开发、测试、运营及运维提供云到端的一站式解决…...

PyTorch中.item()函数:提取单元素张量值

PyTorch中,.item()函数是什么 在PyTorch代码中,.item() 主要用于从一个只包含单个元素的张量(Tensor)中提取出对应的Python标量值 ,具体作用和使用场景如下: 作用 获取数值:当通过计算得到一个张量,且该张量仅包含一个元素时,使用 .item() 方法可以方便地将这个元素…...

PyTorch LSTM练习案例:股票成交量趋势预测

文章目录 案例介绍源码地址代码实现导入相关库数据获取和处理搭建LSTM模型训练模型测试模型绘制折线图主函数 绘制结果 案例介绍 本例使用长短期记忆网络模型对上海证券交易所工商银行的股票成交量做一个趋势预测&#xff0c;这样可以更好地掌握股票买卖点&#xff0c;从而提高…...

ARM A64 LDR指令

ARM A64 LDR指令 1 LDR (immediate)1.1 Post-index1.2 Pre-index1.3 Unsigned offset 2 LDR (literal)3 LDR (register)4 其他LDR指令变体4.1 LDRB (immediate)4.1.1 Post-index4.1.2 Pre-index4.1.3 Unsigned offset 4.2 LDRB (register)4.3 LDRH (immediate)4.3.1 Post-index…...

一些问题杂记

1. 在 SSH 会话/bash中仅使用cat命令查看文件后使用umount命令提示挂载点繁忙&#xff0c;lsof命令查看是bash有占用&#xff0c;但是并没有打开文件之类的情况 原因&#xff1a;当前工作目录仍在挂载点内&#xff0c;使用cat查看文件时&#xff0c;可能当前工作目录&#xff…...

【OpenGL学习】(一)创建窗口

文章目录 【OpenGL】&#xff08;一&#xff09;创建窗口 【OpenGL】&#xff08;一&#xff09;创建窗口 GLFW OpenGL 本身只是一套图形渲染 API&#xff0c;不提供窗口创建、上下文管理或输入处理的功能。 GLFW 是一个支持创建窗口、处理键盘鼠标输入和管理 OpenGL 上下文的…...

RTSP 播放器技术探究:架构、挑战与落地实践

RTSP 播放器为什么至今无法被淘汰&#xff1f; 在实时视频传输领域&#xff0c;RTSP&#xff08;Real-Time Streaming Protocol&#xff09;作为最基础、最常见的协议之一&#xff0c;至今依然被广泛用于监控设备、IP Camera、视频服务器等设备中。然而&#xff0c;要构建一个稳…...

【问题记录】08 MAC电脑,安装HP打印机驱动,提示:此更新需要macOS版本15.0或更低版本

问题描述&#xff1a; MAC电脑&#xff0c;升级了新系统之后&#xff08;v15.4.1&#xff09;。 这时&#xff0c;安装惠普&#xff08;HP&#xff09;打印机驱动&#xff0c;提示&#xff1a;This update requires macOS version 15.0 or earlier&#xff08;此更新需要macOS…...

场景新零售:基于开源AI大模型AI智能名片S2B2C商城小程序源码的商业本质回归与创新

摘要&#xff1a;本文聚焦场景新零售&#xff0c;探讨在新生代消费群体推动下传统零售模式的创新升级。通过分析新生代消费群体的特点以及场景新零售的发展趋势&#xff0c;阐述开源AI大模型AI智能名片S2B2C商城小程序源码在场景新零售中的应用优势&#xff0c;包括精准营销、供…...

16.2 VDMA视频转发实验之模拟源

文章目录 1 实验任务2 系统框图3 硬件设计3.1 IP核配置3.2 注意事项3.3 自定义IP核源码 1 实验任务 基于14.1&#xff0c;相较于16.1&#xff0c;使用自定义IP核vid_gen_motion替换Xilinx TPG IP核。 2 系统框图 基于14.1&#xff0c;添加自定义IP核vid_gen_motion作为视频源…...

PADS 9.5安装教程

1.安装包 https://pan.baidu.com/s/1bt6vE3y8VEmlFwJfoV32nA?pwdj2cg 2.PADS 9.5安装教程 PADS 9.5安装教程&#xff08;Windows11、超详细版&#xff09;_pads9.5-CSDN博客 3.出现的问题 1.打开无法使用鼠标滚轮 Win10 pads卡死问题解决&#xff0c;输入法的兼容性问…...

趣味编程:钟表

目录 1. 效果展示 2. 源码展示 3. 逻辑概述 3.1 表针绘制函数&#xff08;DrawHand&#xff09; 3.2 表盘绘制函数 3.3 主程序逻辑 4. 小结 概述&#xff1a;本篇博客主要介绍简易钟表的绘制。 1. 效果展示 该钟表会随着系统的时间变化而变化&#xff0c;动态的效…...

.NET 通过命令行解密web.config配置

在.NET应用系统中,保护数据库连接字符串的安全性至关重要。.NET 提供了一种通过 DataProtectionConfigurationProvider 加密连接字符串的方法,以防止敏感数据泄露。然而,在内网信息收集阶段,攻击者只需在目标主机上运行aspnet_regiis.exe这个命令行工具即可完成解密,获取数…...

【MySQL】多表连接查询

个人主页&#xff1a;Guiat 归属专栏&#xff1a;MySQL 文章目录 1. 多表连接查询概述1.1 连接查询的作用1.2 MySQL支持的连接类型 2. 内连接 (INNER JOIN)2.1 内连接的特点2.2 内连接语法2.3 内连接实例2.4 多表内连接 3. 左外连接 (LEFT JOIN)3.1 左外连接的特点3.2 左外连接…...

【AI论文】用于评估和改进大型语言模型中指令跟踪的多维约束框架

摘要&#xff1a;接下来的指令评估了大型语言模型&#xff08;LLMs&#xff09;生成符合用户定义约束的输出的能力。 然而&#xff0c;现有的基准测试通常依赖于模板化的约束提示&#xff0c;缺乏现实使用的多样性&#xff0c;并限制了细粒度的性能评估。 为了填补这一空白&…...

应用BERT-GCN跨模态情绪分析:贸易缓和与金价波动的AI归因

本文运用AI量化分析框架&#xff0c;结合市场情绪因子、宏观经济指标及技术面信号&#xff0c;对黄金与美元指数的联动关系进行解析&#xff0c;揭示本轮贵金属回调的深层驱动因素。 周三&#xff0c;现货黄金价格单日跌幅达2.1%&#xff0c;盘中触及3167.94美元/盎司关键价位&…...

低成本高效图像生成:GPUGeek和ComfyUI的强强联合

一、时代背景 在如今的数字化时代&#xff0c;图像生成技术正不断发展和演变&#xff0c;尤其是在人工智能领域。无论是游戏开发、虚拟现实&#xff0c;还是设计创意&#xff0c;图像生成已成为许多应用的核心技术之一。然而&#xff0c;随着图像质量需求的提升&#xff0c;生成…...

React 第四十二节 Router 中useLoaderData的用途详解

一、前言 useLoaderData&#xff0c;用于在组件中获取路由预加载的数据。它通常与路由配置中的 loader 函数配合使用&#xff0c;用于在页面渲染前异步获取数据&#xff08;如 API 请求&#xff09;&#xff0c;并将数据直接注入组件&#xff0c;从而简化数据流管理。 二、us…...

【NLP 74、最强提示词工程 Prompt Engineering 从理论到实战案例】

一定要拼尽全力&#xff0c;才能看起来毫不费劲 —— 25.5.15 一、提示词工程 1.提示词工程介绍 Ⅰ、什么是提示词 所谓的提示词其实就是一个提供给模型的文本片段&#xff0c;用于指导模型生成特定的输出或回答。提示词的目的是为模型提供一个任务的上下文&#xff0c;以便模…...

GPUGeek云平台实战:DeepSeek-R1-70B大语言模型一站式部署

随着人工智能技术的迅猛发展&#xff0c;特别是在自然语言处理领域&#xff0c;大型语言模型如DeepSeek-R1-70B的出现&#xff0c;推动了各行各业的变革。为了应对这些庞大模型的计算需求&#xff0c;云计算平台的普及成为了关键&#xff0c;特别是基于GPU加速的云平台&#xf…...

【抽丝剥茧知识讲解】引入mybtis-plus后,mapper实现方式

目录 前言一、传统 Mapper 接口方式二、继承 BaseMapper 的方式三、自定义通用 Mapper 的方式四、使用 MyBatis-Plus 的 ActiveRecord 模式五、使用 MyBatis-Plus 的 IService 接口六、使用建议 前言 mapper文件&#xff0c;作为Mybatis框架中定义SQL语句和映射关系的配置文件&…...

AI浪潮:开启科技新纪元

AI 的多面应用​ AI 的影响力早已突破实验室的围墙&#xff0c;在众多领域落地生根&#xff0c;成为推动行业变革的重要力量。 在医疗领域&#xff0c;AI 宛如一位不知疲倦的助手&#xff0c;助力医生提升诊疗效率与准确性。通过对海量医学影像的深度学习&#xff0c;AI 能够快…...

制造业工厂的三大核心系统:ERP+PLM+MES

对于一家制造业工厂来说,要实现数字化转型,哪几个系统最重要?答案是:ERP,PLM和MES这三个核心系统最为重要!本文就为你快速地概览地介绍一下这三个系统 以及 它们之间的关联关系。 ERP:企业资源计划 ERP的全称是Enterprise Resource Planning,即企业资源计划系统。 它…...

驱动-定时-秒-字符设备

文章目录 目的相关资料参考实验驱动程序-timer_dev.c编译文件-Makefile测试程序-timer.c分析 加载驱动-运行测试程序总结 目的 通过定时器timer_list、字符设备、规避竞争关系-原子操作&#xff0c;综合运用 实现一个程序&#xff0c;加深之前知识的理解。 实现字符设备驱动框…...

(面试)Handler消息处理机制原理

Handler是用于实现线程间通信和任务调度的一种机&#xff08;Handler、 Looper、MessageQueue、 Message&#xff09;。Handler 允许线程间发送Message或Runnable对象进行通信。在Android中UI修改只能通过UI Thread&#xff0c;子线程不能更新UI。如果子线程想更新UI&#xff0…...

WebRTC 通话原理:从协商到通信

在实时音视频通信领域&#xff0c;WebRTC&#xff08;Web Real-Time Communication&#xff09;凭借其开源、无需插件且能在浏览器中直接实现高质量通信的特性&#xff0c;成为开发者的热门选择。本文将深入解析 WebRTC 通话原理&#xff0c;涵盖媒体协商、网络协商、网络穿越&…...

InforSuite AS 可以发布django和vue项目是否可行

InforSuite AS 是浪潮推出的企业级中间件平台&#xff0c;主要用于应用集成、流程管理、数据交换等场景&#xff0c;其核心功能更偏向于 Java EE 应用的部署和管理&#xff08;如支持 WAR/EAR 包&#xff09;。关于能否直接发布 Django&#xff08;Python 框架&#xff09;和 V…...

【中级软件设计师】网络攻击(附软考真题)

【中级软件设计师】网络攻击&#xff08;附软考真题&#xff09; 目录 【中级软件设计师】网络攻击&#xff08;附软考真题&#xff09;一、历年真题二、考点&#xff1a;网络攻击1、拒绝服务攻击&#xff08;DoS攻击&#xff09;2、重放攻击3、特洛伊木马4、网络监听5、SQL注入…...

CSS图片垂直居中问题解决方案

在 CSS 中&#xff0c;使用 vertical-align: middle 导致图片略微向下偏移的现象&#xff0c;本质上是由于 行内元素的基线对齐规则 和 父容器上下文环境 共同作用的结果。以下是具体原因和解决方案&#xff1a; 原因详解 1. vertical-align: middle 的真实含义 该属性 不会让…...

P1601 A+B Problem(高精)

题目描述 高精度加法&#xff0c;相当于 ab problem&#xff0c;不用考虑负数。 输入格式 分两行输入。a,b≤10500。 输出格式 输出只有一行&#xff0c;代表 ab 的值。 输入输出样例 输入 1 1 输出 2 输入 1001 9099 输出 10100 说明/提示 20% 的测试数据…...

鸿蒙OSUniApp实现个性化的搜索框与搜索历史记录#三方框架 #Uniapp

使用UniApp实现个性化的搜索框与搜索历史记录 在移动端应用开发中&#xff0c;搜索功能几乎是标配&#xff0c;而一个好的搜索体验不仅仅是功能的实现&#xff0c;更是用户留存的关键。本文将分享如何在UniApp框架下打造一个既美观又实用的搜索框&#xff0c;并实现搜索历史记录…...

鸿蒙OSUniApp 制作自定义弹窗与模态框组件#三方框架 #Uniapp

UniApp 制作自定义弹窗与模态框组件 前言 在移动应用开发中&#xff0c;弹窗和模态框是用户交互的重要组成部分&#xff0c;它们用于显示提示信息、收集用户输入或确认用户操作。尽管 UniApp 提供了基础的交互组件如 uni.showModal() 和 uni.showToast()&#xff0c;但这些原…...

web第一次课后作业--运行一个java web项目

一、创建java web项目 1.新建java EE --> 模版&#xff1a;Web应用程序 2.选择版本&#xff1a;Java EE 8 3. 配置tomcat 二、页面效果 默认页面 跳转页面 三、代码 3.1 默认页面 <% page contentType"text/html; charsetUTF-8" pageEncoding"UTF-8…...

工业互联网

工业互联网全景解析 工业互联网是工业数字化、网络化、智能化转型升级的重要抓手&#xff0c;是实现中国制造 2025 战略目标的重要路径&#xff0c;对于推动我国实体经济高质量、可持续发展&#xff0c;建设制造强国、网络强国&#xff0c;意义重大。2017 年&#xff0c;我国提…...

论QT6多线程技术

前言 以前我多线程使用传统的继承qthread重写run()或者继承qrunable类把对象丢到线程池解决。经过昨天的面试让我了解到新的技术&#xff0c;我之前看到过只不过没有详细的去了解movetotread技术&#xff0c;这个技术是qt5推出的&#xff0c;qt6还在延续使用 代码结构 以下是…...