HarmonyOS 自定义节点

1. HarmonyOS 自定义节点

1.1. 概念

官方文档(https://developer.huawei.com/consumer/cn/doc/harmonyos-guides-V5/arkts-user-defined-capabilities-V5)
在这里插入图片描述
  自定义能力是HarmonyOS ArkUI开发框架提供的对UI界面进行开发和设计的能力。现有的自定义能力包括:自定义节点。ArkUI开发框架提供的不同控制层级的自定义能力用于实现不同场景的应用的开发。自定义能力的控制层级越低接近基础能力,开发的灵活程度越高,开发难度越高、对于开发者能力的要求也越高。
  自定义节点:具备底层实体节点的部分基础能力的节点对象,这些节点能够通过自定义占位节点与原生控件进行混合显示。自定义节点可以具备单个节点的测算布局、设置基础属性、设置事件监听、自定义绘制渲染内容的自定义能力。包括FrameNode、RenderNode、BuilderNode三类对象。FrameNode表示了组件的实体节点,RenderNode表示更加轻量级的渲染节点,BuilderNode对象提供了能够创建、更新原生组件以及组件树的能力。

1.1.1. FrameNode

  FrameNode表示组件的实体节点,具体可以分为两大类能力:完全自定义节点的能力以及原生组件节点代理的能力。
  完全自定义节点:提供完整的自定义能力,包括自定义测量、布局以及绘制,支持节点的动态增、删,设置通用属性,设置事件回调。适用于不自带渲染引擎,需要依赖系统的布局、事件、动画、渲染等能力的场景。
原生组件代理节点:提供原生组件的代理能力,提供遍历节点树的能力,通过组件树上的FrameNode可以遍历整个组件树,并通过节点访问组件的信息或者注册额外的事件监听回调。适用于结合无感监听的接口实现打点、广告SDK、中台DFX等业务。

1.1.2. RenderNode

  RenderNode作为轻量级的渲染节点,仅提供了设置渲染相关属性、自定义绘制内容以及节点操作的能力。适用于仅依赖系统渲染与动画能力的自定义场景。

1.1.3. BuilderNode

  BuilderNode通过无状态的UI方法全局@Builder生成组件树,组件树内的节点为原生组件。适用于需要基于系统能力创建特定原生组件树与其他自定义节点进行混合显示的场景。相比较原生组件,BuilderNode具备预创建的优势,可以控制开始创建的时间。由于持有实体节点对象,因此可以同步实现节点的复用,通过占位节点结合FrameNode、RenderNode的节点操作能力控制显示位置。

1.2. FrameNode

  对于具备自己前端定义的三方框架,需要将特定的dsl转换成为ArkUI的声明式描述。这个转换过程需依赖额外的数据驱动绑定至Builder中,转换比较复杂且性能较低。这一类框架一般依赖系统ArkUI框架的布局、事件能力,以及最基础的节点操作和自定义能力,大部分组件通过自定义完成,但是需要使用部分原生组件混合显示。FrameNode的设计就是为了解决上述的问题。
在这里插入图片描述

import { BuilderNode, FrameNode, NodeController, router, UIContext } from '@kit.ArkUI';
import { BusinessError } from '@kit.BasicServicesKit';
import { RouterParams } from '@zzsKit/zzsLib';
import { TitleBar } from '../../../components/common/TitleBar';const TEST_TAG: string = "FrameNode"class Params {text: string = "this is a text"
}@Builder
function buttonBuilder(params: Params) {Column({ space: 10 }) {Button(params.text).fontSize(12).borderRadius(8).borderWidth(2).backgroundColor(Color.Orange)Button(params.text).fontSize(12).borderRadius(8).borderWidth(2).backgroundColor(Color.Pink)}
}class MyNodeController extends NodeController {public buttonNode: BuilderNode<[Params]> | null = null;public frameNode: FrameNode | null = null;public childList: Array<FrameNode> = new Array<FrameNode>();public rootNode: FrameNode | null = null;private uiContext: UIContext | null = null;private wrapBuilder: WrappedBuilder<[Params]> = wrapBuilder(buttonBuilder);makeNode(uiContext: UIContext): FrameNode | null {this.uiContext = uiContext;if (this.rootNode == null) {this.rootNode = new FrameNode(uiContext);this.rootNode.commonAttribute.width("50%").height(100).borderWidth(1).backgroundColor(Color.Gray)}if (this.frameNode == null) {this.frameNode = new FrameNode(uiContext);this.frameNode.commonAttribute.width("100%").height(50).borderWidth(1).position({ x: 200, y: 0 }).backgroundColor(Color.Pink);this.rootNode.appendChild(this.frameNode);}if (this.buttonNode == null) {this.buttonNode = new BuilderNode<[Params]>(uiContext);this.buttonNode.build(this.wrapBuilder, { text: "This is a Button" })this.rootNode.appendChild(this.buttonNode.getFrameNode())}return this.rootNode;}operationFrameNodeWithFrameNode(frameNode: FrameNode | undefined | null) {if (frameNode) {console.log(TEST_TAG + " get ArkTSNode success.")console.log(TEST_TAG + " check rootNode whether is modifiable "+ frameNode.isModifiable());}if (this.uiContext) {let frameNode1 = new FrameNode(this.uiContext);let frameNode2 = new FrameNode(this.uiContext);frameNode1.commonAttribute.size({ width: 50, height: 50 }).backgroundColor(Color.Black).position({ x: 50, y: 60 })frameNode2.commonAttribute.size({ width: 50, height: 50 }).backgroundColor(Color.Orange).position({ x: 120, y: 60 })try {frameNode?.appendChild(frameNode1);console.log(TEST_TAG + " appendChild success ");} catch (err) {console.log(TEST_TAG + " appendChild fail :"+ (err as BusinessError).code + " : "+ (err as BusinessError).message);}try {frameNode?.insertChildAfter(frameNode2, null);console.log(TEST_TAG + " clearChildren success ");} catch (err) {console.log(TEST_TAG + " insertChildAfter fail : "+ (err as BusinessError).code + " : " + (err as BusinessError).message);}setTimeout(() => {try {frameNode?.removeChild(frameNode?.getChild(0))console.log(TEST_TAG + " removeChild success ");} catch (err) {console.log(TEST_TAG + " removeChild fail : "+ (err as BusinessError).code + " : " + (err as BusinessError).message);}}, 2000)setTimeout(() => {try {frameNode?.clearChildren();console.log(TEST_TAG + " clearChildren success ");} catch (err) {console.log(TEST_TAG + " clearChildren fail : "+ (err as BusinessError).code + " : " + (err as BusinessError).message);}}, 4000)}}testInterfaceAboutSearch(frameNode: FrameNode | undefined | null): string {let result: string = "";if (frameNode) {result = result + `current node is ${frameNode.getNodeType()} \n`;result = result + `parent node is ${frameNode.getParent()?.getNodeType()} \n`;result = result + `child count is ${frameNode.getChildrenCount()} \n`;result = result + `first child node is ${frameNode.getFirstChild()?.getNodeType()} \n`;result = result + `seconde child node is ${frameNode.getChild(1)?.getNodeType()} \n`;result = result + `previousSibling node is ${frameNode.getPreviousSibling()?.getNodeType()} \n`;result = result + `nextSibling node is ${frameNode.getNextSibling()?.getNodeType()} \n`;}return result;}checkAppendChild(parent: FrameNode | undefined| null, child: FrameNode | undefined | null) {try {if (parent && child) {parent.appendChild(child);console.log(TEST_TAG + " appendChild success ");}} catch (err) {console.log(TEST_TAG + " appendChild fail : "+ (err as BusinessError).code + " : "+ (err as BusinessError).message);}}
}@Entry
@Component
struct FrameNodePage {@State index: number = 0;@State result: string = ""private myNodeController: MyNodeController = new MyNodeController();@State pageTitle: string = "网格列表"aboutToAppear() {try {this.pageTitle = (router.getParams() as RouterParams).title} catch (e) {}}build() {Column() {TitleBar({ pageTitle: $pageTitle })Flex({direction: FlexDirection.Column,alignItems: ItemAlign.Center,justifyContent: FlexAlign.SpaceBetween}) {List({ space: 20, initialIndex: 0 }) {ListItem() {Column({ space: 5 }) {Text("验证FrameNode子节点的增、删、改功能")Button("对自定义FrameNode进行操作").fontSize(16).width(400).onClick(() => {// 对FrameNode节点进行增、删、改操作,正常实现。this.myNodeController.operationFrameNodeWithFrameNode(this.myNodeController?.frameNode);})Button("对BuilderNode中的代理节点进行操作").fontSize(16).width(400).onClick(() => {// 对BuilderNode代理节点进行增、删、改操作,捕获异常信息。this.myNodeController.operationFrameNodeWithFrameNode(this.myNodeController?.buttonNode?.getFrameNode());})Button("对原生组件中的代理节点进行操作").fontSize(16).width(400).onClick(() => {// 对代理节点进行增、删、改操作,捕获异常信息。this.myNodeController.operationFrameNodeWithFrameNode(this.myNodeController?.rootNode?.getParent());})}}ListItem() {Column({ space: 5 }) {Text("验证FrameNode添加子节点的特殊场景")Button("新增BuilderNode的代理节点").fontSize(16).width(400).onClick(() => {let buttonNode = new BuilderNode<[Params]>(this.getUIContext());buttonNode.build(wrapBuilder<[Params]>(buttonBuilder), { text: "BUTTON" })this.myNodeController.checkAppendChild(this.myNodeController?.frameNode,buttonNode?.getFrameNode());})Button("新增原生组件代理节点").fontSize(16).width(400).onClick(() => {this.myNodeController.checkAppendChild(this.myNodeController?.frameNode,this.myNodeController?.rootNode?.getParent());})Button("新增已有父节点的自定义节点").fontSize(16).width(400).onClick(() => {this.myNodeController.checkAppendChild(this.myNodeController?.frameNode,this.myNodeController?.rootNode);})}}ListItem() {Column({ space: 5 }) {Text("验证FrameNode节点的查询功能")Button("对自定义FrameNode进行操作").fontSize(16).width(400).onClick(() => {// 对FrameNode节点进行进行查询。当前节点为NodeContainer的子节点。this.result = this.myNodeController.testInterfaceAboutSearch(this.myNodeController?.rootNode);setTimeout(() => {// 对FrameNode节点进行进行查询。rootNode下的第一个子节点。this.result = this.myNodeController.testInterfaceAboutSearch(this.myNodeController?.frameNode);}, 2000)})Button("对BuilderNode中的代理节点进行操作").fontSize(16).width(400).onClick(() => {// 对BuilderNode代理节点进行进行查询。// 当前节点为BuilderNode中的Column节点。this.result = this.myNodeController.testInterfaceAboutSearch(this.myNodeController?.buttonNode?.getFrameNode());})Button("对原生组件中的代理节点进行操作").fontSize(16).width(400).onClick(() => {// 对代理节点进行查询。当前节点为NodeContainer。this.result = this.myNodeController.testInterfaceAboutSearch(this.myNodeController?.rootNode?.getParent());})}}}.height("50%")Text(`Result:\n${this.result}`).fontSize(16).width(400).height(200).padding(30).borderWidth(1)Column() {Text("This is a NodeContainer.").textAlign(TextAlign.Center).borderRadius(10).backgroundColor(0xFFFFFF).width('100%').fontSize(16)NodeContainer(this.myNodeController).borderWidth(1).width(400).height(150)}}.padding({left: 35,right: 35,top: 35,bottom: 35}).width("100%").height("100%")}}
}

1.3. RenderNode

  对于不具备自己的渲染环境的三方框架,虽然实现了前端的解析以及布局、事件等处理,但需要依赖系统提供的基础渲染、动画的能力。FrameNode上的通用属性、通用事件对这一类框架是多余的,会进行多次冗余的操作,包括布局、事件等处理逻辑。
  RenderNode是更加轻量级的渲染节点,仅包含渲染相关的能力。在该节点上暴露了设置基础的渲染属性的能力,并提供节点的动态增加、删除能力以及自定义绘制的能力。可以向三方框架提供基础的渲染、动画能力。
在这里插入图片描述

import { FrameNode, NodeController, RenderNode, router } from '@kit.ArkUI';
import { RouterParams } from '@zzsKit/zzsLib';
import { TitleBar } from '../../../components/common/TitleBar';const renderNode = new RenderNode();
renderNode.frame = {x: 0,y: 0,width: 200,height: 350
};
renderNode.backgroundColor = 0xffff0000;
for (let i = 0; i < 5; i++) {const node = new RenderNode();// 设置node节点的Frame大小node.frame = {x: 10,y: 10 + 60 * i,width: 50,height: 50};// 设置node节点的背景颜色node.backgroundColor = 0xff00ff00;// 将新增节点挂载在renderNode上renderNode.appendChild(node);
}class MyNodeController extends NodeController {private rootNode: FrameNode | null = null;makeNode(uiContext: UIContext): FrameNode | null {this.rootNode = new FrameNode(uiContext);const rootRenderNode = this.rootNode?.getRenderNode();if (rootRenderNode) {rootRenderNode.appendChild(renderNode);}return this.rootNode;}
}@Entry
@Component
struct RenderNodePage {private myNodeController: MyNodeController = new MyNodeController();@State pageTitle: string = "网格列表"aboutToAppear() {try {this.pageTitle = (router.getParams() as RouterParams).title} catch (e) {}}build() {Column() {TitleBar({ pageTitle: $pageTitle })Row() {NodeContainer(this.myNodeController).width(200).height(350)Button('getNextSibling').onClick(() => {const child = renderNode.getChild(1);const nextSibling = child!.getNextSibling()if (child === null || nextSibling === null) {console.log('the child or nextChild is null');} else {// 获取子节点的位置信息console.log(`the position of child is x: ${child.position.x},y: ${child.position.y}, ` +`the position of nextSibling is x: ${nextSibling.position.x},y: ${nextSibling.position.y}`);}})}}}
}

1.4. BuilderNode

  BuilderNode提供能够挂载原生组件的能力,支持通过无状态的UI方法全局@Builder生成组件树,并通过getFrameNode获取组件树的根FrameNode节点。该节点可以通过NodeController直接返回,挂载在NodeContainer节点下,也可以在FrameNode树结构和RenderNode树结构嵌入声明式的组件结构,实现混合显示的能力。同时BuilderNode可以提供纹理导出的功能,导出的纹理用于在XComponent中进行同层渲染显示。
  BuilderNode创建的ArkTS原生控件树支持与自定义节点(例如:FrameNode、RenderNode)进行关联使用,实现了原生组件与自定义节点的混合显示。对于使用自定义节点的能力进行对接的三方框架,BuilderNode为其提供了嵌入原生组件的能力。
  BuilderNode提供了组件预创建的能力,能够自定义原生组件的创建开始的时间,在后续的业务中动态挂载显示。对于一些在创建初始化耗时较长的声明式组件,比如Web、XComponent等,预创建可以有效减少组件初始化的耗时。

1.4.1. 创建BuilderNode对象

  BuilderNode对象为一个模板类,需要在创建的时候指定类型。该类型需要与后续build方法中传入的WrappedBuilder的类型保持一致,否则会存在编译告警导致编译失败。
  创建原生组件树
  通过BuilderNode的build可以实现原生组件树的创建。依照传入的WrappedBuilder对象创建组件树,并持有组件树的根节点。
  创建离线节点以及原生组件树,结合FrameNode进行使用。
  BuilderNode的根节点直接作为NodeController的makeNode返回值。
在这里插入图片描述

import { BuilderNode, FrameNode, NodeController, router, UIContext } from '@kit.ArkUI'
import { RouterParams } from '@zzsKit/zzsLib';
import { TitleBar } from '../../../components/common/TitleBar';class Params {text: string = ""constructor(text: string) {this.text = text;}
}@Builder
function buildText(params: Params) {Column() {Text(params.text).fontSize(50).fontWeight(FontWeight.Bold).margin({ bottom: 36 })}
}class TextNodeController extends NodeController {private textNode: BuilderNode<[Params]> | null = null;private message: string = "DEFAULT";constructor(message: string) {super();this.message = message;}makeNode(context: UIContext): FrameNode | null {this.textNode = new BuilderNode(context);this.textNode.build(wrapBuilder<[Params]>(buildText),new Params(this.message))return this.textNode.getFrameNode();}
}@Entry
@Component
struct BuilderNodePage {@State message: string = "hello"@State pageTitle: string = "网格列表"aboutToAppear() {try {this.pageTitle = (router.getParams() as RouterParams).title} catch (e) {}}build() {Column() {TitleBar({ pageTitle: $pageTitle })Row() {Column() {NodeContainer(new TextNodeController(this.message)).width('100%').height(100).backgroundColor('#FFF0F0F0')}.width('100%').height('100%')}.height('100%')}}
}

1.4.2. 更新原生组件树

  通过BuilderNode对象的build创建原生组件树。依照传入的WrappedBuilder对象创建组件树,并持有组件树的根节点。
  自定义组件的更新遵循状态管理的更新机制。WrappedBuilder中直接使用的自定义组件其父组件为BuilderNode对象。因此,更新子组件即WrappedBuilder中定义的自定义组件,需要遵循状态管理的定义将相关的状态变量定义为@Prop或者@ObjectLink。装饰器的选择请参照状态管理的装饰器规格结合应用开发需求进行选择。
在这里插入图片描述

import { NodeController, BuilderNode, FrameNode, UIContext, router } from "@kit.ArkUI"
import { RouterParams } from '@zzsKit/zzsLib';
import { TitleBar } from '../../../components/common/TitleBar';class Params {text: string = ""constructor(text: string) {this.text = text;}
}// 自定义组件
@Component
struct TextBuilder {// 作为自定义组件中需要更新的属性,数据类型为基础属性,定义为@Prop@Prop message: string = "TextBuilder";build() {Row() {Column() {Text(this.message).fontSize(50).fontWeight(FontWeight.Bold).margin({ bottom: 36 }).backgroundColor(Color.Gray)}}}
}@Builder
function buildText(params: Params) {Column() {Text(params.text).fontSize(50).fontWeight(FontWeight.Bold).margin({ bottom: 36 })TextBuilder({ message: params.text }) // 自定义组件}
}class TextNodeController extends NodeController {private textNode: BuilderNode<[Params]> | null = null;private message: string = "";constructor(message: string) {super()this.message = message}makeNode(context: UIContext): FrameNode | null {this.textNode = new BuilderNode(context);this.textNode.build(wrapBuilder<[Params]>(buildText), new Params(this.message))return this.textNode.getFrameNode();}update(message: string) {if (this.textNode !== null) {// 调用update进行更新。this.textNode.update(new Params(message));}}
}@Entry
@Component
struct BuilderNode2Page {@State message: string = "hello"private textNodeController: TextNodeController = new TextNodeController(this.message);private count = 0;@State pageTitle: string = "网格列表"aboutToAppear() {try {this.pageTitle = (router.getParams() as RouterParams).title} catch (e) {}}build() {Column() {TitleBar({ pageTitle: $pageTitle })Row() {Column() {NodeContainer(this.textNodeController).width('100%').height(200).backgroundColor('#FFF0F0F0')Button('Update').onClick(() => {this.count += 1;const message = "Update " + this.count.toString();this.textNodeController.update(message);})}.width('100%').height('100%')}.height('100%')}}
}

1.4.3. 注入触摸事件

  BuilderNode中提供了postTouchEvent,可以通过该接口向BuilderNode中绑定的组件注入触摸事件,实现事件的模拟转发。
  通过postTouchEvent向BuilderNode对应的节点树中注入触摸事件。
  向BuilderNode中的Column组件转发另一个Column的接收事件,即点击下方的Column组件,上方的Colum组件也会收到同样的触摸事件。当Button中的事件被成功识别的时候,返回值为true。
在这里插入图片描述

import { NodeController, BuilderNode, FrameNode, UIContext, router } from '@kit.ArkUI';
import { RouterParams } from '@zzsKit/zzsLib';
import { TitleBar } from '../../../components/common/TitleBar';class Params {text: string = "this is a text"
}@Builder
function ButtonBuilder(params: Params) {Column() {Button(`button ` + params.text).borderWidth(2).backgroundColor(Color.Orange).width("100%").height("100%").gesture(TapGesture().onAction((event: GestureEvent) => {console.log("TapGesture");}))}.width(500).height(300).backgroundColor(Color.Gray)
}class MyNodeController extends NodeController {private rootNode: BuilderNode<[Params]> | null = null;private wrapBuilder: WrappedBuilder<[Params]> = wrapBuilder(ButtonBuilder);makeNode(uiContext: UIContext): FrameNode | null {this.rootNode = new BuilderNode(uiContext);this.rootNode.build(this.wrapBuilder, { text: "this is a string" })return this.rootNode.getFrameNode();}postTouchEvent(touchEvent: TouchEvent): void {if (this.rootNode == null) {return;}let result = this.rootNode.postTouchEvent(touchEvent);console.log("result " + result);}
}@Entry
@Component
struct BuilderNode3Page {private nodeController: MyNodeController = new MyNodeController();@State pageTitle: string = "网格列表"aboutToAppear() {try {this.pageTitle = (router.getParams() as RouterParams).title} catch (e) {}}build() {Column() {TitleBar({ pageTitle: $pageTitle })NodeContainer(this.nodeController).height(300).width(500)Column().width(500).height(300).backgroundColor(Color.Pink).onTouch((event) => {if (event != undefined) {this.nodeController.postTouchEvent(event);}})}}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://xiahunao.cn/news/3269187.html

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

数模打怪(八)之图论模型

一、作图 图的数学语言描述&#xff1a; G( V(G), E(G) )&#xff0c;G&#xff08;graph&#xff09;&#xff1a;图&#xff0c;V&#xff08;vertex&#xff09;&#xff1a;顶点集&#xff0c;E&#xff08;edge&#xff09;&#xff1a;边集 1、在线作图 https://csac…

《牛角型电解电容和螺栓型电解电容》

牛角型电解电容之所以被称为牛角型&#xff0c;是因为引出端子的形状类似牛角。 螺栓型电解电容被称为螺栓型&#xff0c;是因为其引出端子的形状像螺栓。 牛角型电解电容和螺栓型电解电容&#xff0c;虽然也是电容&#xff0c;但在普通电路板上用的很少&#xff0c;更多是安…

Linux网络-wget命令

作者介绍&#xff1a;简历上没有一个精通的运维工程师。希望大家多多关注我&#xff0c;我尽量把自己会的都分享给大家&#xff0c;下面的思维导图也是预计更新的内容和当前进度(不定时更新)。 Linux服务器作为一个常用的网络服务器&#xff0c;主要的作用就是向客户端提供网络…

学习测试11-移动自动化(略)

安卓SDK 链接: https://pan.baidu.com/s/1P4v9K2RYAGEoA5M_93hHlQ?pwdqsbu 提取码: qsbu 复制这段内容后打开百度网盘手机App&#xff0c;操作更方便哦 记得配置环境变量 下载Appium软件 hub网址&#xff1a;https://github.com/appium/appium-desktop/releases 链接: https…

【Node.js入门精要】从零开始的开发之旅

说明文档&#xff1a;Node.js 教程_w3cschool 概念 Node.js 是一个开源、跨平台的 JavaScript 运行时环境&#xff0c;基于 Chrome 的 V8 引擎构建&#xff0c;专为构建高性能和可扩展的网络应用程序而设计的服务端语言。它采用事件驱动、非阻塞 I/O 模型&#xff0c;能够处理大…

【Django】前端技术HTML常用标签(开发环境vscode)

文章目录 安装两个常用插件HTML常用标签定义文档类型DOCTYPE网页的结构html/head//title/body/div标题h1/h2/h3/h4/h5分割线hr段落 p列表ul/li&#xff0c;ol/li超链接a文本span图片img按钮button表格table&#xff08;table、tr、th、td&#xff09;表单form 安装两个常用插件…

学习大数据DAY25 Shell脚本的书写2与Shell工具的使用

目录 自定义函数 递归-自己调用自己 上机练习 12 Shell 工具 sort sed awk 上机练习 13 自定义函数 name(){ action; } function name { Action; } name 因为 shell 脚本是从上到下逐行运行&#xff0c;不会像其它语言一样先编译&#xff0c;所以函数必 须在调…

React Router-v6.25.1

以下例子是根据vitereactts构建的&#xff0c;使用路由前先安装好这些环境&#xff01;&#xff01;&#xff01;&#xff01; 1、路由的简单使用 首先要创建一个浏览器路由器并配置我们的第一个路由。这将为我们的 Web 应用启用客户端路由。 该main.jsx文件是入口点。打开它…

前端知识--前端访问后端技术Ajax及框架Axios

一、异步数据请求技术----Ajax Ajax是前端访问后端的技术&#xff0c;为异步请求&#xff08;不刷新页面&#xff0c;请求数据&#xff0c;只更新局部数据&#xff09;。 例如&#xff1a;在京东网站中搜索电脑&#xff0c;就会出现一些联想搜索&#xff0c;但此时页面并没有…

Pytorch深度学习实践(5)逻辑回归

逻辑回归 逻辑回归主要是解决分类问题 回归任务&#xff1a;结果是一个连续的实数分类任务&#xff1a;结果是一个离散的值 分类任务不能直接使用回归去预测&#xff0c;比如在手写识别中&#xff08;识别手写 0 − − 9 0 -- 9 0−−9&#xff09;&#xff0c;因为各个类别…

动态获取配置文件中的配置参数,当配置文件中的参数修改之后,不需要重启项目

这里写目录标题 一、本地开发环境二、nocas环境配置 一、本地开发环境 如果是在本地开发环境中&#xff0c;读取的配置文件是本地根目录下的application.properties文件&#xff1a; 路径为配置文件的绝对路径。 配置文件里面配置的参数需要和获取的参数名称相互对应 通过Au…

linux怎么创建python

第一步&#xff0c;创建一个test文件夹。 第二步&#xff0c;打开终端进入该文件。 第三步&#xff0c;vim test.py。 第四步&#xff0c;编写代码。 第五步&#xff0c;编辑好之后&#xff0c;按Esc键切换到命令模式&#xff0c;然后输入:wq&#xff0c;再按回车键即可自动保存…

Java突击复习小练习,附带讲解

练习&#xff1a; 1.下面的代码在主方法中可以正常执行吗&#xff0c;如果不能&#xff0c;为什么&#xff1f; 2.已知i的值为10&#xff0c;请问在情况一和情况二中j的值是否相同呢&#xff1f;如果不相同&#xff0c;它们的值分别是多少呢?为什么&#xff1f; 3.在主方法运…

3D打印:重塑模具制造业的创新引擎

在科技浪潮的推动下&#xff0c;3D打印技术正以前所未有的速度渗透到制造业的核心&#xff0c;尤其在模具制造领域&#xff0c;它正引领一场深刻的创新革命。该技术通过颠覆传统制造范式&#xff0c;显著优化了模具生产的复杂流程&#xff0c;实现了从设计到成品的一体化的高效…

系统架构设计师教程 第4章 信息安全技术基础知识-4.3 信息安全系统的组成框架4.4 信息加解密技术-解读

系统架构设计师教程 第4章 信息安全技术基础知识-4.3 信息安全系统的组成框架 4.3 信息安全系统的组成框架4.3.1 技术体系4.3.1.1 基础安全设备4.3.1.2 计算机网络安全4.3.1.3 操作系统安全4.3.1.4 数据库安全4.3.1.5 终端安全设备4.3.2 组织机构体系4.3.3 管理体系4.4 信息加…

【PostgreSQL 16】专栏日常

本专栏从 3 个月前开始着手准备&#xff0c;利用周末及节假日的时间来整理。 ldczzDESKTOP-HVJOUVN MINGW64 ~/mypostgres (dev) $ git lg |tee * 7a7f468 - (HEAD -> dev, origin/main, origin/dev, main) 完成服务端编程的初步整理 (6 minutes ago) <Laven Liu> * …

masscan 端口扫描——(Golang 简单使用总结)

1. 前言 最近要做一个扫描 ip 端口的功能 扫描的工具有很多&#xff0c;但是如何做到短时间扫描大量的 ip 是个相对困难的事情。 市场上比较出名的工具有 masscan和nmap masscan 支持异步扫描&#xff0c;对多线程的利用很好&#xff0c;同时仅仅支持 syn 半开扫描&#xff…

GraphHopper-map-navi_路径规划、导航(web前端页面版)

文章目录 一、项目地址二、踩坑环境三、问题记录3.1、graphhopper中地图问题3.1.1. getOpacity不存在的问题3.1.2. dispatchEvent不存在的问题3.1.3. vectorLayer.set(background-maplibre-layer, true)不存在set方法3.1.4. maplibre-gl.js.map不存在的问题3.1.5. Uncaught Ref…

聊聊基于Alink库的特征工程方法

独热编码 OneHotEncoder 是用于将类别型特征转换为独热编码的类。独热编码是一种常用的特征编码方式&#xff0c;特别适用于处理类别型特征&#xff0c;将其转换为数值型特征。 对于每个类别型特征&#xff0c;OneHotEncoder 将其编码成一个长度为类别数量的向量。 每个类别对…

在线教育数仓项目(数据采集部分1)

文章目录 数据仓库概念项目需求及架构设计项目需求分析系统数据流程设计框架版本选型集群规模估算集群资源规划设计 数据生成模块目标数据页面事件曝光启动播放错误 数据埋点主流埋点方式&#xff08;了解&#xff09;埋点数据上报时机埋点数据日志结构 服务器和JDK准备服务器准…