鸿蒙OSUniApp开发富文本编辑器组件#三方框架 #Uniapp
使用UniApp开发富文本编辑器组件
富文本编辑在各类应用中非常常见,无论是内容创作平台还是社交软件,都需要提供良好的富文本编辑体验。本文记录了我使用UniApp开发一个跨平台富文本编辑器组件的过程,希望对有类似需求的开发者有所启发。
背景
前段时间接到一个需求,要求在我们的跨平台应用中加入富文本编辑功能,支持基础的文本格式化、插入图片、链接等功能。考虑到项目使用UniApp开发,需要兼容多个平台,市面上现成的富文本编辑器要么不支持跨平台,要么功能过于复杂。于是我决定自己动手,开发一个功能适中、性能良好的富文本编辑器组件。
技术选型
为何不直接使用现有组件?
首先,我调研了几个流行的富文本编辑器:
- quill.js - 功能强大,但在小程序环境中存在兼容性问题
- wangeditor - 针对Web端优化,小程序支持不佳
- mp-html - 专注于小程序,但编辑功能有限
UniApp官方提供的rich-text组件只具备富文本展示能力,不支持编辑。所以最终决定基于原生能力自己封装一个轻量级的富文本编辑器组件。
核心技术点
- 使用uni.createSelectorQuery获取DOM节点
- 基于contenteditable特性实现编辑功能
- 自定义文本选区和格式化操作
- 跨平台样式处理
- 图片上传和展示
开发实现
1. 创建基础组件结构
首先,我们需要创建一个基础的编辑器组件结构:
<template><view class="rich-editor"><view class="toolbar"><view v-for="(item, index) in tools" :key="index"class="tool-item":class="{active: activeFormats[item.format]}"@tap="handleFormat(item.format, item.value)"><text class="iconfont" :class="item.icon"></text></view></view><!-- 编辑区域 --><view class="editor-container":style="{ height: editorHeight + 'px' }"><viewclass="editor-body"contenteditable="true"@input="onInput"@blur="onBlur"@focus="onFocus"id="editor"ref="editor"></view></view><!-- 底部工具栏 --><view class="bottom-tools"><view class="tool-item" @tap="insertImage"><text class="iconfont icon-image"></text></view><view class="tool-item" @tap="insertLink"><text class="iconfont icon-link"></text></view></view></view>
</template><script>
export default {name: 'RichEditor',props: {value: {type: String,default: ''},height: {type: Number,default: 300},placeholder: {type: String,default: '请输入内容...'}},data() {return {editorHeight: 300,editorContent: '',selectionRange: null,activeFormats: {bold: false,italic: false,underline: false,strikethrough: false,alignLeft: true,alignCenter: false,alignRight: false},tools: [{ format: 'bold', icon: 'icon-bold', value: 'bold' },{ format: 'italic', icon: 'icon-italic', value: 'italic' },{ format: 'underline', icon: 'icon-underline', value: 'underline' },{ format: 'strikethrough', icon: 'icon-strikethrough', value: 'line-through' },{ format: 'alignLeft', icon: 'icon-align-left', value: 'left' },{ format: 'alignCenter', icon: 'icon-align-center', value: 'center' },{ format: 'alignRight', icon: 'icon-align-right', value: 'right' }]}},created() {this.editorHeight = this.heightthis.editorContent = this.value},mounted() {this.initEditor()},methods: {initEditor() {const editor = this.$refs.editorif (editor) {editor.innerHTML = this.value || `<p><br></p>`}// 设置placeholderif (!this.value && this.placeholder) {this.$nextTick(() => {editor.setAttribute('data-placeholder', this.placeholder)})}},// 监听输入onInput(e) {// 获取当前内容this.editorContent = e.target.innerHTMLthis.$emit('input', this.editorContent)this.saveSelection()},// 保存当前选区saveSelection() {const selection = window.getSelection()if (selection.rangeCount > 0) {this.selectionRange = selection.getRangeAt(0)}},// 恢复选区restoreSelection() {if (this.selectionRange) {const selection = window.getSelection()selection.removeAllRanges()selection.addRange(this.selectionRange)return true}return false},// 处理格式化handleFormat(format, value) {// 恢复选区if (!this.restoreSelection()) {console.log('No selection to format')return}// 根据不同格式执行不同操作switch(format) {case 'bold':case 'italic':case 'underline':case 'strikethrough':document.execCommand(format, false, null)breakcase 'alignLeft':case 'alignCenter':case 'alignRight':document.execCommand('justify' + format.replace('align', ''), false, null)breakdefault:console.log('未知格式:', format)}// 更新激活状态this.checkActiveFormats()// 触发内容变化this.editorContent = this.$refs.editor.innerHTMLthis.$emit('input', this.editorContent)},// 检查当前激活的格式checkActiveFormats() {this.activeFormats.bold = document.queryCommandState('bold')this.activeFormats.italic = document.queryCommandState('italic')this.activeFormats.underline = document.queryCommandState('underline')this.activeFormats.strikethrough = document.queryCommandState('strikethrough')const alignment = document.queryCommandValue('justifyLeft') ? 'alignLeft' :document.queryCommandValue('justifyCenter') ? 'alignCenter' :document.queryCommandValue('justifyRight') ? 'alignRight' : 'alignLeft'this.activeFormats.alignLeft = alignment === 'alignLeft'this.activeFormats.alignCenter = alignment === 'alignCenter'this.activeFormats.alignRight = alignment === 'alignRight'},// 焦点事件onFocus() {this.saveSelection()this.checkActiveFormats()},onBlur() {this.saveSelection()},// 插入图片insertImage() {uni.chooseImage({count: 1,success: (res) => {const tempFilePath = res.tempFilePaths[0]// 上传图片this.uploadImage(tempFilePath)}})},// 上传图片uploadImage(filePath) {// 这里应该是实际的上传逻辑uni.showLoading({ title: '上传中...' })// 模拟上传过程setTimeout(() => {// 假设这是上传后的图片URLconst imageUrl = filePath// 恢复选区并插入图片this.restoreSelection()document.execCommand('insertHTML', false, `<img src="${imageUrl}" style="max-width:100%;" />`)// 更新内容this.editorContent = this.$refs.editor.innerHTMLthis.$emit('input', this.editorContent)uni.hideLoading()}, 500)},// 插入链接insertLink() {uni.showModal({title: '插入链接',editable: true,placeholderText: 'https://',success: (res) => {if (res.confirm && res.content) {const url = res.content// 恢复选区this.restoreSelection()// 获取选中的文本const selection = window.getSelection()const selectedText = selection.toString()// 如果有选中文本,将其设为链接文本;否则使用URL作为文本const linkText = selectedText || url// 插入链接document.execCommand('insertHTML', false, `<a href="${url}" target="_blank">${linkText}</a>`)// 更新内容this.editorContent = this.$refs.editor.innerHTMLthis.$emit('input', this.editorContent)}}})},// 获取编辑器内容getContent() {return this.editorContent},// 设置编辑器内容setContent(html) {this.editorContent = htmlif (this.$refs.editor) {this.$refs.editor.innerHTML = html}this.$emit('input', html)}}
}
</script><style>
.rich-editor {width: 100%;border: 1rpx solid #eee;border-radius: 10rpx;overflow: hidden;
}.toolbar {display: flex;flex-wrap: wrap;padding: 10rpx;border-bottom: 1rpx solid #eee;background-color: #f8f8f8;
}.tool-item {width: 80rpx;height: 80rpx;display: flex;justify-content: center;align-items: center;font-size: 40rpx;color: #333;
}.tool-item.active {color: #007AFF;background-color: rgba(0, 122, 255, 0.1);border-radius: 8rpx;
}.editor-container {width: 100%;overflow-y: auto;
}.editor-body {min-height: 100%;padding: 20rpx;font-size: 28rpx;line-height: 1.5;outline: none;
}.editor-body[data-placeholder]:empty:before {content: attr(data-placeholder);color: #999;font-style: italic;
}.bottom-tools {display: flex;padding: 10rpx;border-top: 1rpx solid #eee;background-color: #f8f8f8;
}/* 引入字体图标库 (需要自行配置) */
@font-face {font-family: 'iconfont';src: url('data:font/woff2;charset=utf-8;base64,...') format('woff2');
}
.iconfont {font-family: "iconfont" !important;font-style: normal;
}
</style>
2. 处理平台差异
UniApp支持多个平台,但在富文本编辑方面存在平台差异,特别是小程序限制较多。下面是一些关键的跨平台适配处理:
// 跨平台选区处理
saveSelection() {// #ifdef H5const selection = window.getSelection()if (selection.rangeCount > 0) {this.selectionRange = selection.getRangeAt(0)}// #endif// #ifdef MP-WEIXIN// 微信小程序不支持DOM选区,需使用特殊方法this.getEditContext().getSelectionRange({success: (res) => {this.selectionRange = res}})// #endif
},// 获取编辑器上下文(微信小程序)
getEditContext() {// #ifdef MP-WEIXINreturn this.editorCtx || wx.createSelectorQuery().in(this).select('#editor').context(res => {this.editorCtx = res.context}).exec()// #endifreturn null
}
3. 增强图片处理能力
富文本编辑器的一个关键功能是图片处理,我们需要增强这方面的能力:
// 增强版图片上传处理
uploadImage(filePath) {uni.showLoading({ title: '上传中...' })// 压缩图片uni.compressImage({src: filePath,quality: 80,success: res => {const compressedPath = res.tempFilePath// 上传到服务器uni.uploadFile({url: 'https://your-upload-endpoint.com/upload',filePath: compressedPath,name: 'file',success: uploadRes => {try {const data = JSON.parse(uploadRes.data)const imageUrl = data.url// 插入图片this.insertImageToEditor(imageUrl)} catch (e) {uni.showToast({title: '上传失败',icon: 'none'})}},fail: () => {uni.showToast({title: '上传失败',icon: 'none'})},complete: () => {uni.hideLoading()}})},fail: () => {// 压缩失败,使用原图this.doUploadFile(filePath)}})
},// 插入图片到编辑器
insertImageToEditor(imageUrl) {// #ifdef H5this.restoreSelection()document.execCommand('insertHTML', false, `<img src="${imageUrl}" style="max-width:100%;" />`)// #endif// #ifdef MP-WEIXINthis.getEditContext().insertImage({src: imageUrl,width: '100%',success: () => {console.log('插入图片成功')}})// #endif// 更新内容this.$nextTick(() => {// #ifdef H5this.editorContent = this.$refs.editor.innerHTML// #endif// #ifdef MP-WEIXINthis.getEditContext().getContents({success: res => {this.editorContent = res.html}})// #endifthis.$emit('input', this.editorContent)})
}
4. 实现HTML与富文本互转
编辑器需要支持HTML格式的导入导出,以便存储和展示:
// HTML转富文本对象
htmlToJson(html) {const tempDiv = document.createElement('div')tempDiv.innerHTML = htmlconst parseNode = (node) => {if (node.nodeType === 3) { // 文本节点return {type: 'text',text: node.textContent}}if (node.nodeType === 1) { // 元素节点const result = {type: node.nodeName.toLowerCase(),children: []}// 处理元素属性if (node.attributes && node.attributes.length > 0) {result.attrs = {}for (let i = 0; i < node.attributes.length; i++) {const attr = node.attributes[i]result.attrs[attr.name] = attr.value}}// 处理样式if (node.style && node.style.cssText) {result.styles = {}const styles = node.style.cssText.split(';')styles.forEach(style => {if (style.trim()) {const [key, value] = style.split(':')if (key && value) {result.styles[key.trim()] = value.trim()}}})}// 递归处理子节点for (let i = 0; i < node.childNodes.length; i++) {const childResult = parseNode(node.childNodes[i])if (childResult) {result.children.push(childResult)}}return result}return null}const result = []for (let i = 0; i < tempDiv.childNodes.length; i++) {const nodeResult = parseNode(tempDiv.childNodes[i])if (nodeResult) {result.push(nodeResult)}}return result
},// 富文本对象转HTML
jsonToHtml(json) {if (!json || !Array.isArray(json)) return ''const renderNode = (node) => {if (node.type === 'text') {return node.text}// 处理元素节点let html = `<${node.type}`// 添加属性if (node.attrs) {Object.keys(node.attrs).forEach(key => {html += ` ${key}="${node.attrs[key]}"`})}// 添加样式if (node.styles) {let styleStr = ''Object.keys(node.styles).forEach(key => {styleStr += `${key}: ${node.styles[key]};`})if (styleStr) {html += ` style="${styleStr}"`}}html += '>'// 处理子节点if (node.children && node.children.length > 0) {node.children.forEach(child => {html += renderNode(child)})}// 关闭标签html += `</${node.type}>`return html}let result = ''json.forEach(node => {result += renderNode(node)})return result
}
实战案例:评论编辑器
下面是一个简化版的评论编辑器实现,可以在社区或博客应用中使用:
<template><view class="comment-editor"><view class="editor-title"><text>发表评论</text></view><rich-editorv-model="commentContent":height="200"placeholder="说点什么吧..."ref="editor"></rich-editor><view class="action-bar"><view class="action-btn cancel" @tap="cancel">取消</view><view class="action-btn submit" @tap="submitComment">发布</view></view></view>
</template><script>
import RichEditor from '@/components/rich-editor/rich-editor.vue'export default {components: {RichEditor},data() {return {commentContent: '',replyTo: null}},props: {articleId: {type: [String, Number],required: true}},methods: {cancel() {this.commentContent = ''this.$refs.editor.setContent('')this.$emit('cancel')},submitComment() {if (!this.commentContent.trim()) {uni.showToast({title: '评论内容不能为空',icon: 'none'})return}uni.showLoading({ title: '发布中...' })// 提交评论this.$api.comment.add({article_id: this.articleId,content: this.commentContent,reply_to: this.replyTo}).then(res => {uni.hideLoading()if (res.code === 0) {uni.showToast({title: '评论发布成功',icon: 'success'})// 清空编辑器this.commentContent = ''this.$refs.editor.setContent('')// 通知父组件刷新评论列表this.$emit('submit-success', res.data)} else {uni.showToast({title: res.msg || '评论发布失败',icon: 'none'})}}).catch(() => {uni.hideLoading()uni.showToast({title: '网络错误,请重试',icon: 'none'})})},// 回复某条评论replyComment(comment) {this.replyTo = comment.idthis.$refs.editor.setContent(`<p>回复 @${comment.user.nickname}:</p>`)this.$refs.editor.focus()}}
}
</script><style>
.comment-editor {padding: 20rpx;background-color: #fff;border-radius: 10rpx;
}.editor-title {margin-bottom: 20rpx;font-size: 32rpx;font-weight: bold;
}.action-bar {display: flex;justify-content: flex-end;margin-top: 20rpx;
}.action-btn {padding: 10rpx 30rpx;border-radius: 30rpx;font-size: 28rpx;margin-left: 20rpx;
}.cancel {color: #666;background-color: #f3f3f3;
}.submit {color: #fff;background-color: #007AFF;
}
</style>
踩坑记录
开发过程中遇到了不少坑,这里分享几个关键问题及解决方案:
1. 小程序富文本能力受限
小程序不支持通过contenteditable实现的富文本编辑,需要使用平台提供的editor组件。解决方案是使用条件编译,H5使用contenteditable,小程序使用官方editor组件。
<!-- H5编辑器 -->
<!-- #ifdef H5 -->
<div class="editor-body"contenteditable="true"@input="onInput"id="editor"ref="editor"
></div>
<!-- #endif --><!-- 小程序编辑器 -->
<!-- #ifdef MP-WEIXIN -->
<editor id="editor" class="editor-body" :placeholder="placeholder"@ready="onEditorReady"@input="onInput"
></editor>
<!-- #endif -->
2. 选区处理差异
不同平台的选区API差异很大,需要分别处理:
// 处理选区问题
getSelectionRange() {return new Promise((resolve) => {// #ifdef H5const selection = window.getSelection()if (selection.rangeCount > 0) {resolve(selection.getRangeAt(0))} else {resolve(null)}// #endif// #ifdef MP-WEIXINthis.editorCtx.getSelectionRange({success: (res) => {resolve(res)},fail: () => {resolve(null)}})// #endif})
}
3. 图片上传大小限制
多端应用中,图片上传和展示需要考虑不同平台的限制:
// 处理图片大小限制
async handleImageUpload(file) {// 检查文件大小if (file.size > 5 * 1024 * 1024) { // 5MBuni.showToast({title: '图片不能超过5MB',icon: 'none'})return null}// 压缩图片try {// H5与小程序压缩方式不同// #ifdef H5const compressedFile = await this.compressImageH5(file)return compressedFile// #endif// #ifdef MPconst compressedPath = await this.compressImageMP(file.path)return { path: compressedPath }// #endif} catch (e) {console.error('图片压缩失败', e)return file // 失败时使用原图}
}
性能优化
为了让编辑器运行更流畅,我做了以下优化:
- 输入防抖 - 减少频繁更新导致的性能问题
- 延迟加载图片 - 使用懒加载机制
- 减少DOM操作 - 尽量批量更新DOM
- 使用虚拟DOM - 在复杂场景下考虑使用Vue的虚拟DOM机制
// 输入防抖处理
onInput(e) {if (this.inputTimer) {clearTimeout(this.inputTimer)}this.inputTimer = setTimeout(() => {// #ifdef H5this.editorContent = this.$refs.editor.innerHTML// #endif// #ifdef MP-WEIXINthis.editorContent = e.detail.html// #endifthis.$emit('input', this.editorContent)}, 300)
}
总结
通过这次开发实践,我实现了一个跨平台的富文本编辑器组件,总结几点经验:
- 平台差异是最大挑战,需要利用条件编译提供各平台最佳实现
- 功能要适中,不是所有Web富文本功能都适合移动端
- 性能优化很重要,尤其是在低端设备上
- 良好的用户体验需要细节打磨,如适当的反馈、容错处理等
富文本编辑是一个复杂的课题,即使是成熟的Web编辑器也有各种问题。在移动端和小程序环境中,受限更多。我们的方案虽然不完美,但通过合理的取舍和平台适配,已经能满足大部分应用场景的需求。
后续还可以继续完善这个组件,比如添加表格支持、代码高亮、Markdown转换等高级功能。希望本文对你有所启发,欢迎在评论区交流讨论!
参考资料
- UniApp官方文档
- execCommand API参考
- ContentEditable详解
相关文章:
鸿蒙OSUniApp开发富文本编辑器组件#三方框架 #Uniapp
使用UniApp开发富文本编辑器组件 富文本编辑在各类应用中非常常见,无论是内容创作平台还是社交软件,都需要提供良好的富文本编辑体验。本文记录了我使用UniApp开发一个跨平台富文本编辑器组件的过程,希望对有类似需求的开发者有所启发。 背景…...

Axure设计的“广东省网络信息化大数据平台”数据可视化大屏
在数据驱动决策的时代,数据可视化大屏成为了展示数据、洞察趋势的重要工具。今天,让我们一同深入了解由Axure设计的“广东省网络信息化大数据平台”数据可视化大屏,看看它如何通过精心的布局和丰富的图表类型,将复杂的数据以直观易…...

2025认证杯数学建模第二阶段C题完整论文(代码齐全)化工厂生产流程的预测和控制
2025认证杯数学建模第二阶段C题完整论文(代码齐全)化工厂生产流程的预测和控制,详细信息见文末名片 第二阶段问题 1 分析 在第二阶段问题 1 中,由于在真实反应流程中输入反应物的量改变后,输出产物会有一定延时&#…...

Redis——底层数据结构
SDS(simple dynamic string): 优点: O1时间获取长度(char *需要ON)快速计算剩余空间(alloc-len),拼接时根据所需空间自动扩容,避免缓存区溢出(ch…...

ChatGPT 能“记住上文”的原因
原因如下 你把对话历史传给了它 每次调用 OpenAI 接口时,都会把之前的对话作为参数传入(messages 列表),模型“看见”了之前你说了什么。 它没有长期记忆 它不会自动记住你是谁或你说过什么,除非你手动保存历史并再次…...

大疆无人机自主飞行解决方案局限性及增强解决方案-AIBOX:特色行业无人机巡检解决方案
大疆无人机自主飞行解决方案局限性及增强解决方案-AIBOX:特色行业无人机巡检解决方案 大疆无人机是低空行业无人机最具性价比的产品,尤其是大疆机场3的推出,以及持续自身产品升级迭代,包括司空2、大疆智图以及大疆智运等专业软件和…...

医学影像系统性能优化与调试技术:深度剖析与实践指南
🧑 博主简介:CSDN博客专家、CSDN平台优质创作者,高级开发工程师,数学专业,10年以上C/C, C#, Java等多种编程语言开发经验,拥有高级工程师证书;擅长C/C、C#等开发语言,熟悉Java常用开…...

day 25
*被遗忘的一集 程序:二进制文件,文件存储在磁盘中,例如/usr/bin/目录下 进程:进程是已启动的可执行程序的运行实例。 *进程和程序并不是一一对应的关系,相同的程序运行在不同的数据集上就是不同的进程 *进程还具有并…...

吉客云数据集成到金蝶云星空的最佳实践
吉客云数据集成到金蝶云星空的技术案例分享 在本次技术案例中,我们将探讨如何通过仓库方案-I0132,将吉客云的数据高效集成到金蝶云星空。此方案旨在解决企业在数据对接过程中遇到的多种技术挑战,包括数据吞吐量、实时监控、异常处理和数据格…...
【Spark】-- DAG 和宽窄依赖的核心
目录 Spark DAG 和宽窄依赖的核心 一、什么是 DAG? 示例:WordCount 程序的 DAG 二、宽依赖与窄依赖 1. 窄依赖 2. 宽依赖 三、DAG 与宽窄依赖的性能优化 1. 减少 Shuffle 操作 2. 合理划分 Stage 3. 使用缓存机制 四、实际案例分析:同行车判断 五、总结 Spark D…...
原生的 XMLHttpRequest 和基于 jQuery 的 $.ajax 方法的异同之处以及使用场景
近期参与一个项目的开发,发现项目中的ajax请求有两种不同的写法,查询了下两种写法的异同之处以及使用场景。 下面将从以下两段简单代码进行异同之处的分析及使用场景的介绍: // 写法一: var xhr new XMLHttpRequest(); xhr.open…...
快速选择算法:优化大数据中的 Top-K 问题
在处理海量数据时,经常会遇到这样的需求:找出数据中最大的前 K 个数,而不必对整个数据集进行排序。这种场景下,快速选择算法(Quickselect)就成了一个非常高效的解决方案。本文将通过一个 C 实现的快速选择算…...
使用Frp搭建内网穿透,外网也可以访问本地电脑。
一、准备 1、服务器:需要一台外网可以访问的服务器,不在乎配置,宽带好就行。我用的是linux服务器。(一般买一个1核1g的云服务器就行),因为配置高的服务器贵,所以这是个择中办法。 2、客户端&a…...
【RabbitMQ】消息丢失问题排查与解决
RabbitMQ 消息丢失是一个常见的问题,可能发生在消息的生产、传输、消费或 Broker 端等多个环节。消息丢失的常见原因及对应的解决方案: 一、消息丢失的常见原因 1. 生产端(Producer)原因 (1) 消息未持久化 原因:生产…...
电子电路:被动电子元件都有哪些?
在电子电路中,被动元件(Passive Components)是指不需要外部电源即可工作且不具备信号放大或能量控制能力的元件。它们主要通过消耗、存储或传递能量来调节电路的电流、电压、频率等特性。以下是常见的被动元件及其核心作用: 一、基础被动元件 1. 电阻(Resistor) 功能:限…...

使用Mathematica制作Lorenz吸引子的轨道追踪视频
Lorenz奇异吸引子是混沌理论中最早被发现和研究的吸引子之一,它由Edward Lorenz在1963年研究确定性非周期流时提出。Lorenz吸引子以其独特的"蝴蝶"形状而闻名,是混沌系统和非线性动力学的经典例子。 L NDSolveValue[{x[t] -3 (x[t] - y[t]),…...
深入解析VPN技术原理:安全网络的护航者
在当今信息化迅速发展的时代,虚拟私人网络(VPN)技术成为了我们在互联网时代保护隐私和数据安全的重要工具。VPN通过为用户与网络之间建立一条加密的安全通道,确保了通讯的私密性与完整性。本文将深入解析VPN的技术原理、工作机制以…...
JavaScript性能优化实战(10):前端框架性能优化深度解析
引言 React、Vue、Angular等框架虽然提供了强大的抽象和开发效率,但不恰当的使用方式会导致严重的性能问题,针对这些问题,本文将深入探讨前端框架性能优化的核心技术和最佳实践。 React性能优化核心技术 React通过虚拟DOM和高效的渲染机制提供了出色的性能,但当应用规模…...
(for 循环) VS (LINQ) 性能比拼 ——c#
在大多数情况下,for 循环的原始性能会优于 LINQ,尤其是在处理简单遍历、数据筛选或属性提取等场景时。这是由两者的实现机制和抽象层次决定的。以下是具体分析: 一、for 循环与 LINQ 的性能差异原因 1. 抽象层次与执行机制 for 循环&#…...
《Spring Boot 4.0新特性深度解析》
Spring Boot 4.0的发布标志着Java生态向云原生与开发效能革命的全面迈进。作为企业级应用开发的事实标准框架,此次升级在运行时性能、云原生支持、开发者体验及生态兼容性四大维度实现突破性创新。本文深度解析其核心技术特性,涵盖GraalVM原生镜像支持、…...
【大模型面试每日一题】Day 20:大模型出现“幻觉”(Hallucination)的可能原因有哪些?如何从数据或训练层面缓解?
【大模型面试每日一题】Day 20:大模型出现“幻觉”(Hallucination)的可能原因有哪些?如何从数据或训练层面缓解? 📌 题目重现 🌟🌟 面试官:大模型出现“幻觉”…...

简单图像自适应亮度对比度调整
一、背景介绍 继续在刷对比度调整相关算法,偶然间发现了这个简单的亮度/对比度自适应调整算法,做个简单笔记记录。也许后面用得到。 二、自适应亮度调整 1、基本原理 方法来自论文:Adaptive Local Tone Mapping Based on Retinex for High Dynamic Ran…...
CompletableFuture统计任务
ApiOperation(value "首页统计")GetMapping("/statistics")public UnifyResponse<List<BusinessStatisticsVO>> statistics() throws Exception {StatisticsPermissionQuery permissionQuery getPermission();ThreadPoolExecutor executor …...
neo4j框架:ubuntu系统中neo4j安装与使用教程
在使用图数据库的时候,经常需要用到neo4j这一图数据库处理框架。本文详细介绍了neo4j安装使用过程中的问题与解决方法。 一、安装neo4j 在安装好了ubuntu系统、docker仓库和java的前提下 在ubuntu系统命令行依次输入如下命令: # 安装依赖库 sudo apt-…...
ECPF 简介
ECPF(Embedded CPU Function,嵌入式CPU功能)是NVIDIA BlueField DPU特有的一种功能类型,和PF(Physical Function,物理功能)、VF(Virtual Function,虚拟功能)密…...
eSwitch manager 简介
eSwitch manager 的定义和作用 eSwitch manager 通常指的是能够配置和管理 eSwitch(嵌入式交换机)的实体或接口。在 NVIDIA/Mellanox 的网络架构中,Physical Function(PF)在 switchdev 模式下充当 eSwitch manager&am…...

深入理解二叉树:遍历、存储与算法实现
在之前的博客系列中,我们系统地探讨了多种线性表数据结构,包括顺序表、栈和队列等经典结构,并通过代码实现了它们的核心功能。从今天开始,我们将开启一个全新的数据结构篇章——树结构。与之前讨论的线性结构不同,树形…...
Python3 简易DNS服务器实现
使用Python3开发一个简单的DNS服务器,支持配置资源记录(RR),并能通过dig命令进行查询。 让自己理解DNS原理 实现方案 我们将使用socketserver和dnslib库来构建这个DNS服务器。dnslib库能帮助我们处理DNS协议的复杂细节。 1. 安装依赖 首先确保安装了d…...

【Win32 API】 lstrcmpA()
作用 比较两个字符字符串(比较区分大小写)。 lstrcmp 函数通过从第一个字符开始检查,若相等,则检查下一个,直到找到不相等或到达字符串的末尾。 函数 int lstrcmpA(LPCSTR lpString1, LPCSTR lpString2); 参数 lpStr…...

(C语言)超市管理系统 (正式版)(指针)(数据结构)(清屏操作)(文件读写)
目录 前言: 源代码: product.h product.c fileio.h fileio.c main.c 代码解析: 一、程序结构概述 二、product.c 函数详解 1. 初始化商品列表 Init_products 2. 添加商品 add_product 3. 显示商品 display_products 4. 修改商品 mo…...