【HarmonyOS】富文本编辑器RichEditor详解

一、前言

在信息化高速发展的今天,普通的文本容器,已经不能够承载用户丰富的表达欲。富文本展示已经是移动开发中,必备要解决的问题,在鸿蒙中,通过在系统层提供RichEditor控件,来解决富文本展示的问题。

HarmonyOS推出的RichEditor控件,提供了从基础文本输入到复杂图文混排的完整解决方案。

从API version 10开始支持的RichEditor控件,不仅具备文本输入、样式设置等基础能力,还创新性地支持自定义键盘、图文混排、事件回调等高级特性。

随着版本迭代,RichEditor不断进化,从API version 11开始支持元服务调用,到API version 20引入AI菜单和撤销样式保留等功能,已发展为一个成熟稳定的富文本解决方案。

本文将从实际使用流程和完整实战Demo出发,详细解析RichEditor控件的核心功能与应用场景,帮助开发者快速掌握这一强大工具的使用方法。

二、使用流程

1、组件创建方式

RichEditor控件提供了两种创建方式:

(1)使用属性字符串构建

在这里插入图片描述

这种方式一般用于比较简单的富文本场景,例如上图颜色不同的一段话。
基于属性字符串(StyledString/MutableStyledString)构建,持有属性字符串对象来管理数据,通过修改属性字符串对象的内容、样式,再传递给组件,实现对富文本组件内容的更新。
相比于使用controller接口进行内容样式更新,使用起来更加灵活便捷。


@Entry
@Component
struct Index {// 定义字体样式对象,设置字体颜色为粉色fontStyle: TextStyle = new TextStyle({fontColor: Color.Pink});// 创建可变样式字符串,用于存储富文本内容及其样式// 初始文本为"使用属性字符串构建的RichEditor组件"// 并为前5个字符("使用属性字")应用上面定义的粉色字体样式mutableStyledString: MutableStyledString = new MutableStyledString("使用属性字符串构建的RichEditor组件",[{start: 0,          // 样式起始位置(从0开始)length: 5,         // 样式作用的字符长度styledKey: StyledStringKey.FONT,  // 样式类型为字体样式styledValue: this.fontStyle       // 具体的样式值}]);// 初始化属性字符串模式的RichEditor控制器// 该控制器专门用于处理基于属性字符串的富文本操作controller: RichEditorStyledStringController = new RichEditorStyledStringController();// 配置RichEditor组件的选项,将控制器传入options: RichEditorStyledStringOptions = { controller: this.controller };build() {Column() {// 构建RichEditor组件,使用上面配置的选项RichEditor(this.options)// 组件初始化完成回调// 当RichEditor组件准备好后,将之前创建的可变样式字符串设置到编辑器中.onReady(() => {this.controller.setStyledString(this.mutableStyledString);})}.height('100%')  // Column高度占满整个父容器.width('100%')   // Column宽度占满整个父容器.justifyContent(FlexAlign.Center)  // 垂直方向居中对齐子组件}
}
(2)使用RichEditorController构建

在这里插入图片描述

这种方式一般用于复杂内容场景,通过RichEditorController提供的接口实现内容、样式的管理。


@Entry
@Component
struct IndexPage2 {// 初始化富文本编辑器控制器,用于管理RichEditor组件controller: RichEditorController = new RichEditorController();// 配置RichEditor组件选项,传入控制器实例options: RichEditorOptions = { controller: this.controller };build() {Column() {Column() {// 创建RichEditor组件并应用配置选项RichEditor(this.options)// 组件初始化完成回调,用于设置初始内容.onReady(() => {// 1. 添加第一段文本内容// 使用addTextSpan方法添加文本,并设置橙色字体、16px大小this.controller.addTextSpan('使用RichEditorController', {style: {fontColor: Color.Orange,fontSize: 16}});// 2. 添加符号内容// 使用addSymbolSpan方法添加系统内置符号(篮球图标)// 设置符号大小为30pxthis.controller.addSymbolSpan($r("sys.symbol.basketball_fill"), {style: {fontSize: 30}});// 3. 添加第二段文本内容// 使用addTextSpan方法添加文本,并设置红色字体、20px大小this.controller.addTextSpan('构建富文本!!!', {style: {fontColor: Color.Red,fontSize: 20}});})}.width('100%')  // 内部Column宽度占满父容器}.height('100%')  // 外部Column高度占满父容器}
}

2、组件的属性配置参数效果

RichEditor提供了丰富的属性来定制编辑体验,下面介绍几个常用属性的配置方法。

(1)自定义选择菜单

通过bindSelectionMenu属性可以设置自定义选择菜单,替代组件默认的文本选择菜单,实现更丰富的菜单功能,如翻译、加粗等。

// 自定义菜单构建器
@Builder
CustomMenu() {Column() {Menu() {MenuItemGroup() {MenuItem({startIcon: $r('app.media.icon_bold'),content: "加粗"})MenuItem({startIcon: $r('app.media.icon_italic'),content: "斜体"})MenuItem({startIcon: $r('app.media.icon_underline'),content: "下划线"})}}.radius(8).backgroundColor(Color.White).width(200)}
}// 在RichEditor中绑定自定义菜单
RichEditor(this.options).onReady(() => {this.controller.addTextSpan('长按触发自定义菜单', {style: {fontColor: Color.Black,fontSize: 16}})}).bindSelectionMenu(RichEditorSpanType.TEXT, this.CustomMenu, ResponseType.LongPress).width(300).height(200)
(2)光标和手柄颜色设置

通过caretColor属性可以设置输入框光标和手柄的颜色,提高视觉辨识度,使光标颜色与应用整体风格相协调。

RichEditor(this.options).onReady(() => {this.controller.addTextSpan('设置了橙色光标和手柄的富文本', {style: {fontColor: Color.Black,fontSize: 16}})}).caretColor(Color.Orange).width(300).height(100)
(3)占位文本设置

通过placeholder属性可以设置无输入时的提示文本,引导用户正确操作。

RichEditor(this.options).placeholder("请输入您的内容...", {fontColor: Color.Gray,font: {size: 14,family: "HarmonyOS Sans"}}).width(300).height(80)

3、组件的事件监听与交互控制逻辑

RichEditor提供了丰富的事件监听接口,实现更灵活的编辑交互逻辑。

(1)初始化完成事件

初始化回调函数,一般在这里进行数据的加载,或者组件文本的拼接等。

RichEditor(this.options).onReady(() => {console.info('RichEditor初始化完成');})
(2)选择变化事件

内容选择区域或光标位置变化时触发,可用于实时更新工具栏状态。

RichEditor(this.options).onSelectionChange((range) => {console.info(`选中范围变化: start=${range.start}, end=${range.end}`);// 根据选中范围更新工具栏按钮状态this.updateToolbarState(range);})
(3)粘贴事件

粘贴操作前触发,可用于自定义粘贴内容处理。

RichEditor(this.options).onPaste((event) => {// 阻止默认粘贴行为event.preventDefault();// 自定义粘贴处理逻辑this.handleCustomPaste(event);})

4、内容操作与管理

通过控制器可以实现对编辑内容的程序化操作。

添加文本内容
// 添加普通文本
this.controller.addTextSpan('新添加的文本内容', {style: {fontSize: 16,fontColor: Color.Blue}
});// 在指定位置添加文本
this.controller.addTextSpan('在指定位置添加的文本', {style: {fontSize: 16,fontStyle: FontStyle.Italic},offset: 10 // 在偏移量10的位置添加
});
5、添加图片内容
this.controller.addImageSpan($r('app.media.image'), {imageStyle: {size: [300, 200], // 图片大小objectFit: ImageFit.Contain, // 图片缩放类型verticalAlign: ImageSpanAlignment.MIDDLE // 垂直对齐方式}
});
6、更新文本样式
// 更新指定范围的文本样式
this.controller.updateSpanStyle({start: 0,end: 5,textStyle: {fontWeight: 700, // 加粗decoration: {type: TextDecorationType.Underline, // 下划线color: Color.Red}}
});

三、DEMO源码

DEMO实现了一个富文本编辑器界面,支持字体样式设置、段落缩进控制、内容选中与编辑等功能,并通过自定义标记生成器实现列表缩进的可视化展示。
在这里插入图片描述

const canvasWidth = 1000;
const canvasHeight = 100;
const Indentation = 40;// 段落缩进标记生成器类
class LeadingMarginCreator {private settings: RenderingContextSettings = new RenderingContextSettings(true); // 渲染上下文设置private offscreenCanvas: OffscreenCanvas = new OffscreenCanvas(canvasWidth, canvasHeight); // 离屏画布private offContext: OffscreenCanvasRenderingContext2D = this.offscreenCanvas.getContext("2d", this.settings); // 离屏画布渲染上下文public static instance: LeadingMarginCreator = new LeadingMarginCreator(); // 单例实例// 获得字体字号级别(0-4级)public getFontSizeLevel(fontSize: number) {const fontScaled: number = Number(fontSize) / 16; // 字体缩放比例(相对于16px基准)enum FontSizeScaleThreshold {SMALL = 0.9,      // 小字体阈值NORMAL = 1.1,     // 正常字体阈值LEVEL_1_LARGE = 1.2, // 1级大字体阈值LEVEL_2_LARGE = 1.4, // 2级大字体阈值LEVEL_3_LARGE = 1.5  // 3级大字体阈值}let fontSizeLevel: number = 1; // 初始字号级别为1// 根据缩放比例确定字号级别if (fontScaled < FontSizeScaleThreshold.SMALL) {fontSizeLevel = 0;} else if (fontScaled < FontSizeScaleThreshold.NORMAL) {fontSizeLevel = 1;} else if (fontScaled < FontSizeScaleThreshold.LEVEL_1_LARGE) {fontSizeLevel = 2;} else if (fontScaled < FontSizeScaleThreshold.LEVEL_2_LARGE) {fontSizeLevel = 3;} else if (fontScaled < FontSizeScaleThreshold.LEVEL_3_LARGE) {fontSizeLevel = 4;} else {fontSizeLevel = 1;}return fontSizeLevel;}// 获得缩进级别比例(根据缩进宽度计算比例)public getmarginLevel(width: number) {let marginlevel: number = 1; // 初始缩进比例为1// 根据不同缩进宽度设置对应的比例if (width === 40) {marginlevel = 2.0;} else if (width === 80) {marginlevel = 1.0;} else if (width === 120) {marginlevel = 2/3;} else if (width === 160) {marginlevel = 0.5;} else if (width === 200) {marginlevel = 0.4;}return marginlevel;}// 生成文本标记(将文本转换为像素图)public genStrMark(fontSize: number, str: string): PixelMap {this.offContext = this.offscreenCanvas.getContext("2d", this.settings); // 重新获取渲染上下文this.clearCanvas(); // 清空画布this.offContext.font = fontSize + 'vp sans-serif'; // 设置字体样式this.offContext.fillText(str + '.', 0, fontSize * 0.9); // 绘制文本(末尾加点以确保宽度)// 获取像素图(根据文本长度计算宽度)return this.offContext.getPixelMap(0, 0, fontSize * (str.length + 1) / 1.75, fontSize);}// 生成方形标记(绘制正方形并转换为像素图)public genSquareMark(fontSize: number): PixelMap {this.offContext = this.offscreenCanvas.getContext("2d", this.settings); // 重新获取渲染上下文this.clearCanvas(); // 清空画布const coordinate = fontSize * (1 - 1 / 1.5) / 2; // 计算起始坐标const sideLength = fontSize / 1.5; // 计算正方形边长this.offContext.fillRect(coordinate, coordinate, sideLength, sideLength); // 绘制正方形// 获取正方形像素图return this.offContext.getPixelMap(0, 0, fontSize, fontSize);}// 生成圆圈符号标记(根据缩进级别、字体大小等参数绘制圆形标记)public genCircleMark(fontSize: number, width: number, level?: number): PixelMap {const indentLevel = level ?? 1; // 缩进级别(默认1)const offsetLevel = [22, 28, 32, 34, 38]; // 不同字号级别的垂直偏移量const fontSizeLevel = this.getFontSizeLevel(fontSize); // 获取字号级别const marginlevel = this.getmarginLevel(width); // 获取缩进比例const newCanvas = new OffscreenCanvas(canvasWidth, canvasHeight); // 创建新的离屏画布const newOffContext: OffscreenCanvasRenderingContext2D = newCanvas.getContext("2d", this.settings); // 新画布的渲染上下文const centerCoordinate = 50; // 圆心水平坐标基准const radius = 10; // 圆半径基准this.clearCanvas(); // 清空画布// 绘制椭圆(根据参数计算位置和大小)newOffContext.ellipse(100 * (indentLevel + 1) - centerCoordinate * marginlevel, // 圆心x坐标offsetLevel[fontSizeLevel], // 圆心y坐标(根据字号级别)radius * marginlevel, // 水平半径(根据缩进比例)radius, // 垂直半径0, 0, 2 * Math.PI // 椭圆参数(起始角度、结束角度));newOffContext.fillStyle = '66FF0000'; // 填充颜色(半透明红色)newOffContext.fill(); // 填充图形// 获取圆形标记的像素图(根据缩进级别计算宽度)return newOffContext.getPixelMap(0, 0, 100 + 100 * indentLevel, 100);}private clearCanvas() {this.offContext.clearRect(0, 0, canvasWidth, canvasHeight); // 清空画布}
}@Entry
@Component
struct IndexPage3 {// 富文本控制器(用于操作编辑器内容和样式)controller: RichEditorController = new RichEditorController();options: RichEditorOptions = { controller: this.controller }; // 富文本编辑器选项// 缩进标记生成器实例(使用单例模式)private leadingMarkCreatorInstance = LeadingMarginCreator.instance;private fontNameRawFile: string = 'MiSans-Bold'; // 自定义字体名称// 状态变量(用于界面交互和数据展示)@State fs: number = 30; // 字体大小@State cl: number = Color.Black; // 字体颜色@State start: number = -1; // 选中起始位置@State end: number = -1; // 选中结束位置@State message: string = "[-1, -1]"; // 选中范围提示信息@State content: string = ""; // 选中内容private leftMargin: Dimension = 0; // 左缩进量private richEditorTextStyle: RichEditorTextStyle = {}; // 富文本样式// 新增:光标颜色和选中背景色状态@State cursorColor: Color|string = Color.Black; // 光标颜色@State selectionColor: Color|string = Color.Gray; // 选中背景色aboutToAppear() {// 注册自定义字体(应用启动时加载字体文件)this.getUIContext().getFont().registerFont({familyName: 'MiSans-Bold',familySrc: '/font/MiSans-Bold.ttf'});}build() {Scroll() {Column() {// 颜色控制区域(切换界面主题颜色)Row() {Button("红色主题").onClick(() => {this.cursorColor = Color.Red; // 设置红色光标this.selectionColor = "#FFCCCC"; // 设置红色选中背景}).width("30%");Button("绿色主题").onClick(() => {this.cursorColor = Color.Green; // 设置绿色光标this.selectionColor = "#CCFFCC"; // 设置绿色选中背景}).width("30%");Button("蓝色主题").onClick(() => {this.cursorColor = Color.Blue; // 设置蓝色光标this.selectionColor = "#CCCCFF"; // 设置蓝色选中背景}).width("30%");}.width("100%").justifyContent(FlexAlign.SpaceBetween).margin({ bottom: 10 });// 选中范围和内容显示区域(展示当前选中的位置和内容)Column() {Text("selection range:").width("100%").fontSize(16); // 选中范围标题Text() {Span(this.message) // 显示选中范围信息}.width("100%").fontSize(16);Text("selection content:").width("100%").fontSize(16); // 选中内容标题Text() {Span(this.content) // 显示选中内容}.width("100%").fontSize(16);}.borderWidth(1).borderColor(Color.Red).width("100%").padding(10).margin({ bottom: 10 });// 样式操作按钮区域(对选中内容进行样式修改)Row() {Button("加粗").onClick(() => {// 更新选中区域文本样式(设置为加粗)this.controller.updateSpanStyle({start: this.start,end: this.end,textStyle: { fontWeight: FontWeight.Bolder }});}).width("25%");Button("获取选中内容").onClick(() => {this.content = ""; // 清空内容显示// 获取选中范围内的所有文本片段this.controller.getSpans({ start: this.start, end: this.end }).forEach(item => {if (typeof(item as RichEditorImageSpanResult)['imageStyle'] !== 'undefined') {// 处理图片片段this.content += (item as RichEditorImageSpanResult).valueResourceStr + "\n";} else {if (typeof(item as RichEditorTextSpanResult)['symbolSpanStyle'] !== 'undefined') {// 处理符号片段(显示字号)this.content += (item as RichEditorTextSpanResult).symbolSpanStyle?.fontSize + "\n";} else {// 处理普通文本片段(显示文本内容)this.content += (item as RichEditorTextSpanResult).value + "\n";}}});}).width("25%");Button("删除选中内容").onClick(() => {// 删除选中区域内容this.controller.deleteSpans({ start: this.start, end: this.end });this.start = -1; // 重置选中起始位置this.end = -1; // 重置选中结束位置this.message = "[" + this.start + ", " + this.end + "]"; // 更新选中范围提示}).width("25%");Button("设置样式1").onClick(() => {// 设置输入时的默认样式this.controller.setTypingStyle({fontWeight: 'medium', // 中等粗细fontFamily: this.fontNameRawFile, // 自定义字体fontColor: Color.Blue, // 蓝色fontSize: 50, // 字号50fontStyle: FontStyle.Italic, // 斜体decoration: { type: TextDecorationType.Underline, color: Color.Green } // 绿色下划线});}).width("25%");}.borderWidth(1).borderColor(Color.Red).width("100%").height("10%").margin({ bottom: 10 });// 富文本编辑器区域(核心编辑界面)Column() {RichEditor(this.options).onReady(() => {// 编辑器准备就绪时初始化内容this.controller.addTextSpan("0123456789\n", {style: {fontWeight: 'medium', // 中等粗细fontFamily: this.fontNameRawFile, // 自定义字体fontColor: Color.Red, // 红色fontSize: 50, // 字号50fontStyle: FontStyle.Italic, // 斜体decoration: { type: TextDecorationType.Underline, color: Color.Green } // 绿色下划线}});this.controller.addTextSpan("abcdefg", {style: {fontWeight: FontWeight.Lighter, // 更细fontFamily: 'HarmonyOS Sans', // HarmonyOS默认字体fontColor: 'rgba(0,128,0,0.5)', // 半透明绿色fontSize: 30, // 字号30fontStyle: FontStyle.Normal, // 正常样式decoration: { type: TextDecorationType.Overline, color: 'rgba(169, 26, 246, 0.50)' } // 半透明紫色上划线}});}).onSelect((value: RichEditorSelection) => {// 选中事件回调(更新选中范围状态)this.start = value.selection[0];this.end = value.selection[1];this.message = "[" + this.start + ", " + this.end + "]";}).caretColor(this.cursorColor)  // 设置光标颜色(来自状态变量).selectedBackgroundColor(this.selectionColor)  // 设置选中背景色(来自状态变量).borderWidth(1).borderColor(Color.Green).width("100%").height("30%").margin({ bottom: 10 });}.borderWidth(1).borderColor(Color.Red).width("100%").padding(10);// 缩进操作按钮区域(控制段落缩进)Column() {Row({ space: 5 }) {Button("向右列表缩进").onClick(() => {let margin = Number(this.leftMargin); // 当前左缩进量if (margin < 200) {margin += Indentation; // 增加缩进量(40像素)this.leftMargin = margin;}// 更新段落样式(设置带标记的缩进)this.controller.updateParagraphStyle({start: -10,end: -10,style: {leadingMargin: {pixelMap: this.leadingMarkCreatorInstance.genCircleMark(100, margin, 1), // 圆形缩进标记size: [margin, 40] // 缩进标记大小}}});}).width("48%");Button("向左列表缩进").onClick(() => {let margin = Number(this.leftMargin); // 当前左缩进量if (margin > 0) {margin -= Indentation; // 减少缩进量(40像素)this.leftMargin = margin;}// 更新段落样式(设置带标记的缩进)this.controller.updateParagraphStyle({start: -10,end: -10,style: {leadingMargin: {pixelMap: this.leadingMarkCreatorInstance.genCircleMark(100, margin, 1), // 圆形缩进标记size: [margin, 40] // 缩进标记大小}}});}).width("48%");}.margin({ bottom: 10 });Row({ space: 5 }) {Button("向右空白缩进").onClick(() => {let margin = Number(this.leftMargin); // 当前左缩进量if (margin < 200) {margin += Indentation; // 增加缩进量(40像素)this.leftMargin = margin;}// 更新段落样式(设置纯空白缩进)this.controller.updateParagraphStyle({start: -10,end: -10,style: { leadingMargin: margin } // 仅设置缩进宽度});}).width("48%");Button("向左空白缩进").onClick(() => {let margin = Number(this.leftMargin); // 当前左缩进量if (margin > 0) {margin -= Indentation; // 减少缩进量(40像素)this.leftMargin = margin;}// 更新段落样式(设置纯空白缩进)this.controller.updateParagraphStyle({start: -10,end: -10,style: { leadingMargin: margin } // 仅设置缩进宽度});}).width("48%");}.margin({ bottom: 10 });Button("获取当前样式").onClick(() => {this.richEditorTextStyle = this.controller.getTypingStyle();console.info("RichEditor getTypingStyle:" + JSON.stringify(this.richEditorTextStyle));}).width("100%").margin({ bottom: 10 });}.width("100%").padding(10);}.width("100%").padding(10);}}
}

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

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【MySQL进阶】在一台机器上运行多个MySQL实例

目录 1.使用MySQL Installer安装MySQL实例 1.1.去官网下载MySQL Installer 1.2.停止mysql服务 1.3.为不同的版本指定不同的安装目录 2.配置不同版本的选项文件 2.1.修改数据目录 2.2.修改基本目录 2.3.修改端口号 2.4.设置⽇志⽬录 2.5.配置临时目录 2.6.修改绑定地…

verilog中timescale指令的使用

1.timescale指令格式timescale <时间单位> / <时间精度>时间单位&#xff1a;它确定了仿真中时间值的基本单位。比如 1ns 就意味着时间值是以纳秒为单位来计量的。 时间精度&#xff1a;该参数决定了时间值能够表示的最小分辨率。例如 1ps 表示时间可以精确到皮秒级…

08_Excel 导入 - 用户信息批量导入

08_Excel 导入 - 用户信息批量导入 1. VO 类 java复制编辑Data AllArgsConstructor NoArgsConstructor public class UserInfoBatch4ExcelReq {ExcelProperty(value "用户姓名")Schema(description "用户姓名")private String userName;ExcelProperty(va…

【深度学习新浪潮】什么是世界模型?

世界模型(World Model)是人工智能领域中一类通过构建环境的抽象表示来理解和预测外部世界的系统。它通过整合多模态数据(如视觉、语言、传感器信号)形成对环境的动态认知,并支持智能体在复杂场景中进行决策与规划。以下从核心概念、解决的问题、关键研究、技术路线、现状与…

React + Express 传输加密以及不可逆加密

一、传输加密这里用 对称加密模式 ASE实现。React 前端const CryptoJS require("crypto-js");// 示例1&#xff1a;ECB模式&#xff08;无需IV&#xff09; const encryptECB (plainText, key) > {return CryptoJS.AES.encrypt(plainText, key, {mode: CryptoJS…

浏览器(Chrome /Edge)高效使用 - 内部命令/快捷键/启动参数

今天在CSDN上传文件,提交总是提示续传失败,重试了五六次才想到获取是科学上网的问题,这个时候其实只要重启浏览器即可,但如果手动关闭浏览器再次打开,浏览器不会恢复之前的多开窗口(会恢复最后一个窗口内多开的标签页,但不会恢复其他窗口)。想了想记得 Chrome 流行的时…

【PTA数据结构 | C语言版】连续子序列最大和

本专栏持续输出数据结构题目集&#xff0c;欢迎订阅。 文章目录 题目代码 题目 给定 n 个整数组成的序列 { a1 ,a2 ,⋯,an }&#xff0c;“连续子序列”被定义为 { ai ,ai1 ,⋯,aj }&#xff0c;其中 1≤i≤j≤n。“连续子序列最大和”则被定义为所有连续子序列元素的和中最大…

Vrrp配置和原理

Vrrp配置和原理 文章目录Vrrp配置和原理概述物理与逻辑拓扑重点vrid虚拟路由器虚拟IP地址及虚拟MAC地址超时时间计算-MASTER_DOWNvip 管理员手动指定方法Master路由器Backup路由器PriorityVRRP报文格式VRRP状态机从Backup到masterVRRP协议状态二.优先级一样比较接口IPVRRP优先级…

可编辑59页PPT | 某大型集团人工智能数字化转型SAP解决方案

荐言摘要&#xff1a;某大型集团人工智能数字化转型中&#xff0c;SAP解决方案扮演着智能中枢角色&#xff0c;深度融合AI技术与核心业务场景&#xff0c;破解传统系统“数据孤岛流程僵化”双重困局。针对集团跨产业、多业态特点&#xff0c;方案以SAP S/4HANA为数据底座&#…

【RK3568 驱动开发:实现一个最基础的网络设备】

RK3568 驱动开发&#xff1a;实现一个最基础的网络设备一、引言二、编写网络设备驱动代码1. 核心数据结构与接口2. 核心功能实现3. 网络命名空间管理4.源代码三、编译与验证1.加载模块2.验证网络四、注意事项一、引言 RK3568 作为一款高性能 ARM 架构处理器&#xff0c;广泛应…

CAIDCP系列对话:AI 驱动安全

数字时代&#xff0c;AI浪潮翻涌&#xff0c;网络安全攻防战已悄然升级&#xff1a; 某工业控制系统遭AI驱动勒索攻击&#xff1a;攻击者借 AI 精准捕捉异常网络扫描、远程 PowerShell 痕迹&#xff0c;瞬间加密文件索要赎金&#xff1b; 另一边&#xff0c;某大型科技公司用AI…

ARMv8 没开mmu执行memset引起的非对齐访问异常

最近在haps上验证一个新的芯片&#xff0c;记录一下memset访问出错的问题。在没开mmu和cache的情况下&#xff0c;对全局变量指针进行memset清零操作&#xff0c;发现每次都会出现异常。最后发现是没开mmu导致出现了数据非对齐访问导致报错。排查EC区域发现是0x25&#xff0c;产…

基于LiveKit Go 实现腾讯云实时音视频功能

详细的生产部署建议&#xff0c;适用于 LiveKit Go 服务器 Web 客户端 TURN/HTTPS。 1. 服务器准备 推荐使用云服务器&#xff08;如阿里云、腾讯云、AWS、Azure等&#xff09;&#xff0c;公网IP&#xff0c;带宽建议≥10Mbps。系统推荐 Ubuntu 20.04/22.04 或 CentOS 7/8&…

三位一体:Ovis-U1如何以30亿参数重构多模态AI格局?

1. 时代命题&#xff1a;多模态统一模型的破局之战当GPT-4o以万亿级参数构建多模态帝国时&#xff0c;中国AI军团正在书写另一种答案。Ovis-U1用30亿参数证明&#xff1a;参数量并非决定性因素&#xff0c;架构创新与训练策略的化学反应&#xff0c;同样能催生出改变游戏规则的…

图像处理基础:镜像、缩放与矫正

在图像处理中&#xff0c;镜像、缩放和矫正操作是常见的图像变换手段。这些操作可以帮助我们对图像进行调整&#xff0c;以满足不同的需求。本文将详细介绍这三种操作的原理和实现方法&#xff0c;并通过代码示例展示它们的实际应用。一、图片镜像旋转1.1 什么是镜像旋转&#…

「Java案例」猜数游戏

案例实现 猜数字游戏 设计一个三位数的猜数游戏,三位数随机生成。程序提示用户输入一个三位的数字,依照以下的规则决定赢取多少奖金:1) 如果用户输入的数字和随机数字完全一致,输出:“恭喜恭喜!完全猜对了!获得三个赞!”2) 如果用户输入的数字覆盖了随机生成的所有数…

创客匠人解析创始人 IP 内卷:知识变现时代的生存逻辑与破局路径

当知识付费行业进入 “存量竞争” 阶段&#xff0c;创始人 IP 的 “内卷” 已非选择而是必然。创客匠人在服务数万知识创业者的实践中发现&#xff0c;那些实现逆势增长的案例&#xff0c;其核心差异往往在于创始人是否具备 “从幕后走到台前” 的决心与能力 —— 这种内卷并非…

250705-Debian12-sudo apt update加速+配置RDP远程桌面环境+设置FRP服务为开机启动项

A. 实现sudo apt update加速 在 Debian 12 上运行 sudo apt update 很慢的常见原因包括&#xff1a; &#x1f50d; 一、常见原因分析 使用了国外的软件源 默认 Debian 安装源多数是国际服务器&#xff0c;国内访问会非常慢。 DNS 解析慢或失败 软件源地址解析时间长&#xf…

数学视频动画引擎Python库 -- Manim Voiceover 语音服务 Speech Services

文中内容仅限技术学习与代码实践参考&#xff0c;市场存在不确定性&#xff0c;技术分析需谨慎验证&#xff0c;不构成任何投资建议。 Manim Voiceover 是一个为 Manim 打造的专注于语音旁白的插件&#xff1a; 直接在 Python 中添加语音旁白&#xff1a; 无需使用视频编辑器&…

C++11 forward_list 从基础到精通:原理、实践与性能优化

文章目录一、为什么需要 forward_list&#xff1f;二、基础篇&#xff1a;forward_list 的核心特性与接口2.1 数据结构与迭代器2.2 常用接口速览2.3 基础操作示例&#xff1a;从初始化到遍历2.3.1 初始化与遍历2.3.2 插入与删除&#xff1a;before_begin 的关键作用三、进阶篇&…