HarmonyOS开发(七):构建丰富页面
1、组件状态管理
1.1、概述
在应用中,界面一般都是动态的。界面会根据不同状态展示不一样的效果。
ArkUI作为一种声明式UI,具有状态驱动UI更新的特点,当用户进行界面交互或有外部事件引起状态改变时,状态的变会会触发组件的自动更新。这个时候南非要通过一个变量来记录状态。当改变态的时候,ArkUI则会自动更新界面中受影响的部分。

ArkUI框架提供了多种管理状态的装饰器来修饰变量,使用这些装饰器修饰的变量即称为状态变量。
在组件范围内传递的状态管理常见场景有如下一些:
| 场景 | 装饰器 |
| 组件内状态管理 | @State |
| 从父组件单向同步状态到子组件 | @Prop |
| 与父组件双向同步状态 | @Link |
| 跨组件层级双向同步状态 | @Provide和@Consume |
注意:在实际应用开发中,应用会根据需要封装数据模型。如果需要观察嵌套类对象属性变化,需要使用@Observed和@ObjectLink装饰器。因为上面表格中所说的装饰器只能观察到对象的第一层属性变化。
1.2、@State:组件内的状态管理
实际开发中由于交互,组件的内容呈现可能产生变化。当需要在组件内使用状态来控制UI的不同呈现方式时,可以使用@State装饰器。
@Entry
@Component
struct StateTest {private i: number = 0;@State text: string = '';build() {Row() {Column() {Button('切换',{type: ButtonType.Capsule, stateEffect: true}).width('50%').fontColor(Color.White).fontSize(16).margin({bottom:15}).onClick(() => {if(this.i % 2 === 0) {this.text = 'Harmony OS';} else {this.text = '鸿蒙系统';}this.i += 1;})Text(this.text).fontSize(16).fontWeight(FontWeight.Bold)}.width('100%')}.height('100%')}
}
上面的例子中,text被修饰为@State,那么它就是一个组件内的状态变量,当这个值变化时,其相应的组件展示也会同时更新。
1.3、@Prop:从父组件单向同步状态
当子组件中的状态依赖于父组件传递过来时,需要使用@Prop装饰器,@Prop修饰的变量可以和其父组件中的状态建立单向同步关系。当父组件中状态变化时,该状态值也会更新至@Prop修饰的变量;对@Prop修饰的变量的修改不会影响其父组件中的状态。
// 子组件 sub.ets
@Component
export struct sub {@Prop text: string;build(){Row(){Column(){Button('修改text值',{type:ButtonType.Capsule, stateEffect: true}).width('50%').margin({bottom:10}).fontSize(16).onClick(()=>{this.text = 'text在子组件中被修改了'})Text(this.text).fontSize(16)}.height(300)}.width('100%').justifyContent(FlexAlign.Center)}
}
// 父组件 PropTest.ets
import { sub } from '../components/sub'
@Entry
@Component
struct PropTest {@State text:string = '父组件中初始值'build() {Row() {Column() {Button('在父组件中修改text',{type:ButtonType.Capsule,stateEffect:true}).width('80%').fontSize(16).margin({bottom:10}).onClick(()=>{this.text = '父组件中修改text的值';})Text(this.text).fontSize(16).margin({bottom:30})sub({text:this.text});}.width('100%')}.height('100%')}
}
上面的例子在父组件中传递其text值给到子组件的text,当在父组件中修改这个值的时候子组件中相应的值也会同步变化,但是在子组件中修改这个值时,这个修改的结果不会同步到父组件。
@Prop修饰的变量是从父组件传递值来初始化的,所以在子组件中是不可以做本地初始化的只能接收来自父组件的值。
1.4、@Link:父子组件双向同步状态
如果父组件状态需要相互绑定进行双向同步时,可以使用@Link装饰。父亲组件中用于初始化子组件@Link变量的必须是在父组件中定义的状态变量。
// 子组件
@Component
export struct sub {@Link @Watch('OnTextChange') text: string ;@State Tip: string = ''OnTextChange(){if(this.text.indexOf('父组件') >= 0) {this.Tip = '使用父组件中的值';} else {this.Tip = '使用子组件中的值';}}build(){Row(){Column(){Button('修改text值',{type:ButtonType.Capsule, stateEffect: true}).width('50%').margin({bottom:10}).fontSize(16).onClick(()=>{this.text = 'text在子组件中被修改了'})Text(this.text).fontSize(16).margin({bottom:30})Text(`Tip:${this.Tip}`).fontSize(16)}.height(300)}.width('100%').justifyContent(FlexAlign.Center)}
}
// 父组件
import { sub } from '../components/sub'
@Entry
@Component
struct PropTest {@State text:string = '父组件中初始值'build() {Row() {Column() {Button('在父组件中修改text',{type:ButtonType.Capsule,stateEffect:true}).width('80%').fontSize(16).margin({bottom:10}).onClick(()=>{this.text = '父组件中修改text的值';})Text(this.text).fontSize(16).margin({bottom:30})sub({text:$text});}.width('100%')}.height('100%')}
}
说明:
1、在子组件中使用@Link修饰时,它就不可以本地化初始化只能通过父组件提供初始值
2、父组件中在给子组件@Link修饰变量进行初始化时需要使用$表示传递的是一个引用
3、@Watch装饰器其内提供的是一个回调函数,它监控变量的变化情况,当发生变化时会触发这个回调函数
1.5、@Provide和@Consume:跨组件层级双向同步状态
它们是用于与后代组件的双向数据同步,应用于数据在多层级之间的传递场景。
@Provide装饰的变量在祖先节点中,可以理解为被“提供”给后代的状态变量
@Consume装饰的变量是在后代组件中,去消费(绑定)祖先节点提供的变量
相关的特点:
- @Provide装饰的状态变量自动对其所有后代组件可用,开发者无需多次在组件之间传递变量
- 后代组件通过@Consume去获取@Provide提供的变量,建立@Provide与@Consume之间的双向数据同步,而@State/@Link则不能在多层级父子组件之间传递
- @Provide和@Consume可以通过相同的变量名或者相同的变量别名绑定,变量类型必须相同
// 通过相同的变量名绑定
@Provide a: number = 0;
@Consume a: number;// 通过变量别名绑定
@Provide('a') b: number = 0;
@Consume('a') c: number;
// 后代子组件S2
@Component
export struct S2 {@Consume a:number;build(){Row(){Column(){Text('S2').fontSize(16).fontWeight(FontWeight.Bold).margin({bottom:15})Text(`a = ${this.a}`).fontSize(16).fontWeight(FontWeight.Bold).margin({bottom:15})Button('后代修改a的值',{type:ButtonType.Capsule,stateEffect:true}).width('40%').onClick(() => {this.a += 10;})}}.width('100%').justifyContent(FlexAlign.Center)}}
// 后代子组件S1
import { S2 } from './S2';
@Component
export struct S1 {@Consume a:number;build(){Row(){Column(){Text('S1').fontSize(20).fontWeight(FontWeight.Bold).margin({bottom:15})Text(`a = ${this.a}`).fontSize(16).fontWeight(FontWeight.Bold).margin({bottom:15})Divider()S2()}}.width('100%').justifyContent(FlexAlign.Center)}}
父组件
import { S1 } from '../components/S1'
@Entry
@Component
struct ProvideTest {@Provide a: number = 100build() {Row() {Column() {Button('祖先修改a的值', {type:ButtonType.Capsule,stateEffect:true}).width('50%').margin({bottom:15}).onClick(() => {this.a += 100;})Text(`祖先>a = ${this.a}`).fontSize(24).fontWeight(FontWeight.Bold).margin({bottom:20})Divider()S1()}.width('100%')}.height('100%')}
}
2、Video组件
2.1、Video件用法介绍
Video组件的接口靛达形式为:
Video(value:{src?: string | Resource, currentProgressRate?:number | string | PlaybackSpeed, previewUri?: string | PixelMap | Resource, controller?: VideoController})
这其中包含四个可选参数:src,currentProgressRate,previewUri和controller。
- src:视频播放源的路径,支持本地或网络路径,如果是网络地址时,需要在module.json5中申请网络权限。在使用本地资源播放时,可以使用的媒体库管理模块medialibrary来查询公共媒体库中的视频文件。
- currentProgressRate:视频播放倍速,其参数类型是number,取值支持0.75,1.0,1.25,1.75,2.0,默认是.0
- previewUri:表示视频未播放时的预览图片路径
- controller:表示视频控制器
注意:支持的视频格式:mp4,mkv,webm,TS
2.2、Video组件属性
Video支持组件的尺寸设置、位置设置等通用属性外,Video还支持是否静音、是否自动播放、控制栏是否显示、视频显示模式及单个视频是否循环播放五个私有属性。
muted:参数类型为boolean,表示是否静音,默认值是false
autoPlay:参数类型为boolean,表示是否自动播放,默认值是false
controls:参数类型为boolean,控制视频播放的控制栏是否显示,默认值是true
objectFit:参数类型为ImageFit,设置视频显示模式。默认值是Cover
objectFit中显示模式可选值有:Contain,Cover,Auto,Fill,ScaleDown,None
默认情况一使用Cover(保持宽高比进行缩小或放大,使用图片两边都大于或等于显示边界)
loop:参数类型为boolean,控制单个视频是否循环播放。默认值是false
2.3、Video组件回调事件
| 事件名称 | 功能描述 |
| onStart(event:() => void) | 播放时触发这个事件 |
| onPause(event:()=> void) | 暂停时触发这个事件 |
| onFinish(event:()=> void) | 播放结束时触发这个事件 |
| onError(event:()=> void) | 播放失败时触发这个事件 |
| onPrepared(callback:(event?:{duration:number}) => void) | 视频准备完成时触发这个事件,通过duration可以获取视频时长s |
| onSeeking(callback:(event?:{time:number}) => void) | 操作进度条过程时上报时间信息,单位为s |
| onSeeked(callback:(event?:{time:number}) => void) | 操作进度条完成后上报时间信息,单位为s |
| onUpdate(callback:(event?:{time:number}) => void) | 播放进度变化时触发这个事件,单位为s,更新时间间隔为250ms |
| onFullscreenChange(callback:(event?:{fullscreen:boolean}) => void) | 在全屏和非全屏播放状态之间切换时触发这个事件 |
2.4、自定义控制器
Video组件的原生控制器样式相对固定,当需要对其做一些特殊的显示时则可能无法满足,此时则可以自下义控制器。
可以使用Row容器实现整理体的布局,Text组件来显示起始时间和视频总时长,最后通过Slider组件来实现视频进度条的效果
@Component
export struct VidoSlider {...build() {Row(...) {Image(...)Text(...)Slider(...)Text(...)}...}
}
3、弹窗
在日常使用应用时,在做一些风险或敏感操作时,应用会给出一个弹框提示,提示用户是否需要执行这些风险操作。
弹窗是一种模态框,常用来提示用户当前需要关注的信息或操作。由于是模态的用户无法操作其它界面内容。在非必要的情况下不推荐使用弹窗,这会打断用户交互的过程。
ArkUI提供了两类弹窗
- 确认类:比如警告弹窗 AlertDialog
- 选择类:包含文本选择窗TextPickerDialog、日期选择窗DatePickerDialog、时间滑动选择窗TimePickerDialog...
除了上述的一些弹框,如不满足业务上的需求,还可以自定义弹窗CustomDialog
3.1、警告窗
AlertDialog,它由三部分组件
- 标题:可选择
- 内容:显示提示信息
- 操作按钮:用户做确认或取消等操作

@Entry
@Component
struct DialogTest {build() {Row() {Column() {Button('点击显示弹窗',{type:ButtonType.Capsule, stateEffect:true}).width('50%').fontSize(16).onClick(() => {AlertDialog.show({title: '提示', // 标题message: '确定要删除所选择的记录?', // 内容autoCancel: false, // 点击遮罩层是否关闭弹窗alignment: DialogAlignment.Bottom, // 弹窗在竖直方向的对齐方式offset: {dx: 0, dy: -20}, // 弹窗相对alignment位置的偏移量primaryButton: {value: '取消',action: () => {console.info('点击了弹窗的取消按钮');}},secondaryButton: {value: '删除',fontColor: '#D94838',action: () => {console.info('点击了弹窗的删除按钮');}},cancel: () => {console.info('点击遮罩层关闭dailog时回调');}})})}.width('100%')}.height('100%')}
}
上面这个弹框中有两个按钮,也可以构建只包含一个按钮的确认弹框,这个时候使用confirm响应和按钮回调
@Entry
@Component
struct DialogTest {build() {Row() {Column() {Button('点击显示弹窗',{type:ButtonType.Capsule, stateEffect:true}).width('50%').fontSize(16).onClick(() => {AlertDialog.show({title: '提示', // 标题message: '确定要删除所选择的记录?', // 内容autoCancel: false, // 点击遮罩层是否关闭弹窗alignment: DialogAlignment.Bottom, // 弹窗在竖直方向的对齐方式offset: {dx: 0, dy: -20}, // 弹窗相对alignment位置的偏移量/*primaryButton: {value: '取消',action: () => {console.info('点击了弹窗的取消按钮');}},secondaryButton: {value: '删除',fontColor: '#D94838',action: () => {console.info('点击了弹窗的删除按钮');}},*/confirm: {value: '确认',fontColor: Color.Blue,action: () => {console.info('点击了确认按钮');}},cancel: () => {console.info('点击遮罩层关闭dailog时回调');}})})}.width('100%')}.height('100%')}
}
3.2、选择类弹窗
选择类弹窗用于方便用户选择相关数据
3.2.1、文本选择弹窗
TextPickerDialog,它是文本滑动选择器弹窗,根据指定的选择范围创建文本选择器,展示在弹窗上。
@Entry
@Component
struct TextPickerTest {@State text: string = ''@State index: number = 0;private lans: string[] = ['C','C++','Java','Typescript','ArkUI']build() {Column() {Text(`你的选择是:${this.text}`).fontSize(18).fontWeight(FontWeight.Bold).fontColor('#4169E1').margin({bottom:15})Button('请选择语言', {type:ButtonType.Capsule,stateEffect:true}).margin({bottom:15}).width('50%').onClick(() => {TextPickerDialog.show({range: this.lans, // 设置文本选择器的选择范围selected: this.index, // 设置初始选中项的索引值onAccept: (value: TextPickerResult) => { // 点击弹窗中的“确定”按钮时触发该回调this.text = value.value;this.index = value.index;console.info('TextPickerDialog:onAccept()' + JSON.stringify(value));},onCancel: () => { // 点击弹窗中的“取消”按钮时触发该回调console.info('TextPickerDialog:onCancel()');},onChange: (value: TextPickerResult) => { // 滑动弹窗中的选择器使当前选中项改变时触发该回调console.info('TextPickerDialog:onChange' + JSON.stringify(value))}})})}.width('100%').height('100%').justifyContent(FlexAlign.Center)}
}
3.2.2、日期选择弹窗
DatePickerDialog,它是日期滑动选择器弹窗,根据指定的日期范围创建日期滑动选择器,展示在弹窗上。
@Entry
@Component
struct DatePickerTest {@State selectedDate: string = ''build() {Row() {Column() {Text(`你选择的日期是:${this.selectedDate}`).fontSize(18).fontWeight(FontWeight.Bold).fontColor('#4169E1').margin({ bottom: 15 })Button('选择日期', { type: ButtonType.Capsule, stateEffect: true }).width('50%').margin({ bottom: 15 }).onClick(() => {DatePickerDialog.show({start: new Date("1900-1-1"), // 设置选择器的起始日期end: new Date("2023-12-31"), // 设置选择器的结束日期selected: this.selectedDate === '' ? new Date() : new Date(this.selectedDate), // 设置当前选中的日期lunar: false,onAccept: (value: DatePickerResult) => { // 点击弹窗中的“确定”按钮时触发该回调this.selectedDate = `${value.year}-${value.month + 1}-${value.day}`console.info("DatePickerDialog:onAccept()" + JSON.stringify(value))},onCancel: () => { // 点击弹窗中的“取消”按钮时触发该回调console.info("DatePickerDialog:onCancel()")},onChange: (value: DatePickerResult) => { // 滑动弹窗中的滑动选择器使当前选中项改变时触发该回调console.info("DatePickerDialog:onChange()" + JSON.stringify(value))}})})}.width('100%')}.height('100%')}
}
3.3、自定义弹窗
在自定义弹窗中可以自定义弹窗内容,用来构建丰富的弹窗界面。
自定义弹窗可以通过装饰器@CustomDialog定义组件来实现,然后结合CustomDialogController来控制自定义弹窗显示和隐藏。
在resources/base/element/下新增json文件:stringarray.json
{"strarray": [{"name": "hobbies_data","value": [{"value": "Soccer"},{"value": "Badminton"},{"value": "Travelling"}]}]
}
同步在en_US,zh_CN目录下也需要新增
ets目录下新增目录viewmodel目录,并在其下新增一个HobbyBean的数据结构
export default class HobbyBean {label: string;isChecked: boolean;constructor(label:string, isChecked:boolean) {this.label = label;this.isChecked = isChecked}
}
ets目录下新增目录components,并在其下新增CustomDialogWidget.ets
import HobbyBean from '../viewmodel/HobbyBean'
@CustomDialog
export struct CustomDialogWidget {@State hobbyBeans: HobbyBean[] = [];@Link hobbies: string;private controller: CustomDialogController;aboutToAppear(){let context: Context = getContext(this);let manager = context.resourceManager;manager.getStringArrayValue($r('app.strarray.hobbies_data'),(error, hobbyResult)=>{hobbyResult.forEach((hobbyItem:string) =>{let hobbyBean = new HobbyBean(hobbyItem,false);this.hobbyBeans.push(hobbyBean);})})}setHobbiesValue(hobbyBeans: HobbyBean[]) {let hobbiesText: string = '';hobbiesText = hobbyBeans.filter((isCheckItem: HobbyBean) => isCheckItem?.isChecked).map((checkedItem:HobbyBean) => {return checkedItem.label;}).join(',');this.hobbies = hobbiesText;}build(){Column(){Text('兴趣爱好').fontSize(16).fontWeight(FontWeight.Bold).margin({bottom:10}).textAlign(TextAlign.Start)List() {ForEach(this.hobbyBeans,(itemHobby:HobbyBean) => {ListItem(){Row(){Text(itemHobby.label).fontSize(14)Toggle({type: ToggleType.Checkbox,isOn:false}).onChange((isCheck)=>{itemHobby.isChecked = isCheck;})}}},itemHobby => itemHobby.label)}Row() {Button('取消').onClick(() => {this.controller.close();}).width('40%')Button('确定').onClick(() => {this.setHobbiesValue(this.hobbyBeans);this.controller.close();}).width('40%')}}.width('95%')}
}
pages目录下新增一个页面:CustomDialogTest
import { CustomDialogWidget } from '../components/CustomDialogWidget'
import HobbyBean from '../viewmodel/HobbyBean';
@Entry
@Component
struct CustomDialogTest {@State hobbies:string = '';customDialogController: CustomDialogController = new CustomDialogController({builder: CustomDialogWidget({hobbies:$hobbies}),alignment: DialogAlignment.Bottom,customStyle: true,offset: { dx: 0,dy: -20 }});setHobbiesValue(hobbyArray: HobbyBean[]) {}build() {Row() {Column(){Text(this.hobbies).fontSize(16).margin({bottom:15})Button('点击打开').onClick(()=>{this.customDialogController.open();})}.width('100%')}.height('100%')}
}
相关文章:
HarmonyOS开发(七):构建丰富页面
1、组件状态管理 1.1、概述 在应用中,界面一般都是动态的。界面会根据不同状态展示不一样的效果。 ArkUI作为一种声明式UI,具有状态驱动UI更新的特点,当用户进行界面交互或有外部事件引起状态改变时,状态的变会会触发组件的自动…...
LuatOS-SOC接口文档(air780E)--rsa - RSA加密解密
示例 -- 请在电脑上生成私钥和公钥, 当前最高支持4096bit, 一般来说2048bit就够用了 -- openssl genrsa -out privkey.pem 2048 -- openssl rsa -in privkey.pem -pubout -out public.pem -- privkey.pem 是私钥, public.pem 是公钥 -- 私钥用于 加密 和 签名, 通常保密, 放在…...
简易版王者荣耀
所有包和类 GameFrame类 package newKingOfHonor;import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.KeyAdapter; import java.awt.event.KeyEvent; import java.io.File; import java.util.ArrayList;im…...
功能测试进阶建议,学习思路讲解
1. 深入了解测试理论: 了解测试的原理、方法和最佳实践,包括黑盒测试、白盒测试、灰盒测试等。可以阅读相关的书籍或参加在线课程。 2. 学习相关测试工具: 掌握常用的测试工具,如缺陷发现工具、性能测试工具、安全测试工具等。可以…...
AI数字人与虚拟人:区别与应用场景
随着人工智能和虚拟技术的不断发展,AI数字人和虚拟人成为了数字世界中的两个重要概念。本文将介绍AI数字人和虚拟人的区别,并探讨它们在不同领域的应用场景。 一、AI数字人与虚拟人的区别 定义和概念: AI数字人:是利用人工智能技术…...
金蝶Apusic应用服务器 任意文件上传漏洞复现
0x01 产品简介 金蝶Apusic应用服务器(Apusic Application Server,AAS)是一款标准、安全、高效、集成并具丰富功能的企业级应用服务器软件,全面支持JakartaEE8/9的技术规范,提供满足该规范的Web容器、EJB容器以及WebSer…...
ElasticSearch学习笔记(狂神说)
ElasticSearch学习笔记(狂神说) 视频地址:https://www.bilibili.com/video/BV17a4y1x7zq 在学习ElasticSearch之前,先简单了解一下Lucene: Doug Cutting开发是apache软件基金会 jakarta项目组的一个子项目是一个开放…...
OpenMMlab导出yolox模型并用onnxruntime和tensorrt推理
导出onnx文件 直接使用脚本 import torch from mmdet.apis import init_detector, inference_detectorconfig_file ./configs/yolox/yolox_tiny_8xb8-300e_coco.py checkpoint_file yolox_tiny_8x8_300e_coco_20211124_171234-b4047906.pth model init_detector(config_fi…...
CMake语法解读 | Qt6需要用到
CMake 入门CMakeLists.txtmain.cpp编译示例cmake常用参数入门 Hello CMake CMake 是一个用于配置跨平台源代码项目应该如何配置的工具建立在给定的平台上。 ├── CMakeLists.txt # 希望运行的 CMake命令 ├── main.cpp # 带有main 的源文件 ├── include # 头文件目录 …...
jenkins 参数构建
整体思路 依赖环境及工具 GitCentos7及以上GitlabJenkinsshellansible 创建一个jenkins项目 应用保存,测试构建 在gitlab创建新项目,编写index.html [rootjenkins-node1 .ssh]# ssh-keygen Generating public/private rsa key pair. Enter file in …...
DBT踩坑第二弹
总结下dbt-spark踩到的坑,连接方式采用的是thrift连接 Kerberos认证。考虑到开源组件Kyuubi也是基于Hiveserver2,使用的thrift协议,所以采用Kyuubi执行SparkSQL。 官方文档给出的Thrift方式连接示例真的是简单,但是真是用起来真是…...
elasticsearch Connection reset by peer如何处理
如何处理: 代码的心跳代码删除,服务linux内核参数修改 客户端时间要小于服务端时间#异常代码 public RestHighLevelClient elasticsearchClient() {// 初始化 RestClient, hostName 和 port 填写集群的内网 IP 地址与端口 // String[] hosts nod…...
IO和NIO的区别 BIO,NIO,AIO 有什么区别? Files的常用方法都有哪些?
文章目录 IO和NIO的区别BIO,NIO,AIO 有什么区别?Files的常用方法都有哪些? 今天来对java中的io, nio, bio, aio进行了解,有何区别。 IO和NIO的区别 NIO与IO区别 IO是面向流的,NIO是面向缓冲区的Java IO面向流意味着每次从流中读一个或多个字…...
pairplot
Python可视化 | Seaborn5分钟入门(七)——pairplot - 知乎 (zhihu.com) Seaborn是基于matplotlib的Python可视化库。它提供了一个高级界面来绘制有吸引力的统计图形。Seaborn其实是在matplotlib的基础上进行了更高级的API封装,从而使得作图更加容易,不需…...
pytest系列——pytest_collection_modifyitems钩子函数修改测试用例执行顺序
前言 pytest默认执行用例是根据项目下的文件名称按ascii码去收集运行的;文件中的用例是从上往下按顺序执行的。 pytest_collection_modifyitems 这个函数顾名思义就是收集测试用例、改变用例的执行顺序的。 【严格意义上来说,我们在用例设计原则上用例…...
【Linux】gcc和g++
👦个人主页:Weraphael ✍🏻作者简介:目前正在学习c和Linux还有算法 ✈️专栏:Linux 🐋 希望大家多多支持,咱一起进步!😁 如果文章有啥瑕疵,希望大佬指点一二 …...
nginx国密ssl测试
文章目录 文件准备编译部署nginx申请国密数字证书配置证书并测试 文件准备 下载文件并上传到服务器,这里使用centos 7.8 本文涉及的程序文件已打包可以直接下载。 点击下载 下载国密版openssl https://www.gmssl.cn/gmssl/index.jsp 下载稳定版nginx http://n…...
H5 清除浮动
1、为什么要清除浮动? 为了解决块级元素浮动后父元素塌陷问题。 2、为什么会产生 父元素塌陷? 首先父元素没有设置高度,父元素的高度是由子元素中最高的控件决定,撑开 简单可以这样理解,原本是在和父元素在同一层级上…...
h5小游戏--2048
2048 经典2048小游戏,基于JS、Html5改写版 效果预览 点我下载源代码 下载代码解压后,双击index.html即可开始本游戏。 Game Rule 游戏规则 以下为游戏默认规则,若需要修改规则请修改代码。 移动箭头键来移动方块,当两个相同数…...
随手写了个博客多平台发布脚本:Python自动发布文章到Wordpress
引言 作为一名技术博主,提高博客发布效率是我们始终追求的目标。在这篇文章中,我将分享一个基于Python的脚本,能够实现博客多平台发布,具体来说,是自动发布文章到WordPress。通过这个简单而高效的脚本,…...
AI Agent与Agentic AI:原理、应用、挑战与未来展望
文章目录 一、引言二、AI Agent与Agentic AI的兴起2.1 技术契机与生态成熟2.2 Agent的定义与特征2.3 Agent的发展历程 三、AI Agent的核心技术栈解密3.1 感知模块代码示例:使用Python和OpenCV进行图像识别 3.2 认知与决策模块代码示例:使用OpenAI GPT-3进…...
【SpringBoot】100、SpringBoot中使用自定义注解+AOP实现参数自动解密
在实际项目中,用户注册、登录、修改密码等操作,都涉及到参数传输安全问题。所以我们需要在前端对账户、密码等敏感信息加密传输,在后端接收到数据后能自动解密。 1、引入依赖 <dependency><groupId>org.springframework.boot</groupId><artifactId...
如何将联系人从 iPhone 转移到 Android
从 iPhone 换到 Android 手机时,你可能需要保留重要的数据,例如通讯录。好在,将通讯录从 iPhone 转移到 Android 手机非常简单,你可以从本文中学习 6 种可靠的方法,确保随时保持连接,不错过任何信息。 第 1…...
Module Federation 和 Native Federation 的比较
前言 Module Federation 是 Webpack 5 引入的微前端架构方案,允许不同独立构建的应用在运行时动态共享模块。 Native Federation 是 Angular 官方基于 Module Federation 理念实现的专为 Angular 优化的微前端方案。 概念解析 Module Federation (模块联邦) Modul…...
全面解析各类VPN技术:GRE、IPsec、L2TP、SSL与MPLS VPN对比
目录 引言 VPN技术概述 GRE VPN 3.1 GRE封装结构 3.2 GRE的应用场景 GRE over IPsec 4.1 GRE over IPsec封装结构 4.2 为什么使用GRE over IPsec? IPsec VPN 5.1 IPsec传输模式(Transport Mode) 5.2 IPsec隧道模式(Tunne…...
Java多线程实现之Thread类深度解析
Java多线程实现之Thread类深度解析 一、多线程基础概念1.1 什么是线程1.2 多线程的优势1.3 Java多线程模型 二、Thread类的基本结构与构造函数2.1 Thread类的继承关系2.2 构造函数 三、创建和启动线程3.1 继承Thread类创建线程3.2 实现Runnable接口创建线程 四、Thread类的核心…...
【数据分析】R版IntelliGenes用于生物标志物发现的可解释机器学习
禁止商业或二改转载,仅供自学使用,侵权必究,如需截取部分内容请后台联系作者! 文章目录 介绍流程步骤1. 输入数据2. 特征选择3. 模型训练4. I-Genes 评分计算5. 输出结果 IntelliGenesR 安装包1. 特征选择2. 模型训练和评估3. I-Genes 评分计…...
听写流程自动化实践,轻量级教育辅助
随着智能教育工具的发展,越来越多的传统学习方式正在被数字化、自动化所优化。听写作为语文、英语等学科中重要的基础训练形式,也迎来了更高效的解决方案。 这是一款轻量但功能强大的听写辅助工具。它是基于本地词库与可选在线语音引擎构建,…...
GO协程(Goroutine)问题总结
在使用Go语言来编写代码时,遇到的一些问题总结一下 [参考文档]:https://www.topgoer.com/%E5%B9%B6%E5%8F%91%E7%BC%96%E7%A8%8B/goroutine.html 1. main()函数默认的Goroutine 场景再现: 今天在看到这个教程的时候,在自己的电…...
Scrapy-Redis分布式爬虫架构的可扩展性与容错性增强:基于微服务与容器化的解决方案
在大数据时代,海量数据的采集与处理成为企业和研究机构获取信息的关键环节。Scrapy-Redis作为一种经典的分布式爬虫架构,在处理大规模数据抓取任务时展现出强大的能力。然而,随着业务规模的不断扩大和数据抓取需求的日益复杂,传统…...
