Web前端浅谈ArkTS组件开发

news2024/11/15 9:27:16

本文由JS老狗原创。
有幸参与本厂APP的鸿蒙化改造,学习了ArkTS以及IDE的相关知识,并有机会在ISSUE上与鸿蒙各路大佬交流,获益颇丰。

本篇文章将从一个Web前端的视角出发,浅谈ArkTS组件开发的基础问题,比如属性传递、插槽、条件渲染等。

创建项目

这个过程简单过一下,不赘述。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

组件与页面

创建好项目后,我们会自动跳到初始首页,代码如下:

@Entry
@Component
struct Index {
    @State message: string = 'Hello World';

    build() {
        RelativeContainer() {
            Text(this.message)
                .id('HelloWorld')
                .fontSize(50)
                .fontWeight(FontWeight.Bold)
                .alignRules({
                    center: { anchor: '__container__', align: VerticalAlign.Center },
                    middle: { anchor: '__container__', align: HorizontalAlign.Center }
                })
        }
        .height('100%')
        .width('100%')
    }
}

首先注意页面Index是按struct定义。我们在这里不深入讨论struct的含义,照猫画虎即可。主要看前面的装饰器。

  • @Entry 表示该页面为一个独立的Page,可通过router进行跳转。
  • @Component 对该对象封装之后,即可进行页面渲染,并构建数据->视图的更新,可以看成是一个mvvm结构的模版,类似对React.Component的集成,或者是vuedefineComponent的语法糖。
  • build 渲染,可以对标React组件中的render(),或者vue中的setup()。当使用@Component装饰器之后,必须显式声明该方法,否则会有系统报错。

另外需要注意的是,在build()中仅可以使用声明式的写法,也就是只能使用表达式。可以看成是jsx的一个变体:

// 请感受下面组件函数中 return 之后能写什么
export default () => {
    return (
        <h1>Hello World</h1>
    )
}
@Component
export default struct SomeComponent {
    build() {
        // console.log(123) // 这是不行的
        Text('Hello World')
    }
}

如果有条件可以打开IDE实际操作体会一下。

独立组件

上面组件的示例代码中,我们并没有使用@Entry装饰器。是的这就足够了,上面的代码就是一个完整组件的声明。

我们把组件单拎出来:
在这里插入图片描述

在这里插入图片描述

@Component
export struct CustomButton {
    build() {
        Button('My Button')
    }
}

刚才的首页做一下改造,使用前端惯用的flex布局:

import { CustomButton } from './CustomButton'

@Entry
@Component
struct Index {
    @State message: string = 'Hello World';

    build() {
        Flex({
            direction: FlexDirection.Column,
            justifyContent: FlexAlign.Center,
            alignItems: ItemAlign.Center,
        }) {
            Text(this.message)
                .id('HelloWorld')
                .fontSize(50)
                .fontWeight(FontWeight.Bold)
            CustomButton()
        }
        .height('100%')
        .width('100%')
    }
}

在这里插入图片描述
最基本的组件定义和使用,就是如此了。

样式簇

web前端不同,ArkTS没有css,但ArkTS通过链式写法,实现了常用的css样式定义。只要有css方案,基本都可以通过链式写法,把想要的样式出来。
在这里插入图片描述

这样散养的样式并不常用,Web前端会用class来声明样式集。类似的功能,可以通过@Extend@Styles两个装饰器实现。

Style装饰器

import { CustomButton } from './CustomButton'

@Entry
@Component
struct Index {
    @State message: string = 'Hello World';
    
    // 声明Style簇
    @Styles
    HelloWorldStyle() {
        .backgroundColor(Color.Yellow)
        .border({ width: { bottom: 5 }, color: '#ccc' })
        .margin({ bottom: 10 })
    }


    build() {
        Flex({
            direction: FlexDirection.Column,
            justifyContent: FlexAlign.Center,
            alignItems: ItemAlign.Center,
        }) {
            Text(this.message)
                .id('HelloWorld')
                .fontSize(50)
                .fontWeight(FontWeight.Bold)
                .HelloWorldStyle()  // 注意这里调用样式簇
            CustomButton()
        }
        .height('100%')
        .width('100%')
    }
}

在这里插入图片描述

@Styles装饰器也可以单独修饰function函数:

@Styles
function HelloWorldStyle2() {
    .backgroundColor(Color.Yellow)
    .border({ width: { bottom: 5 }, color: '#000' })
    .margin({ bottom: 10 })
}

@Entry
@Component
struct Index {
    //...
}

使用@Styles装饰器可以定义一些布局类的基础样式,比如背景,内外边距等等;如果定义在组件内部,有助于提升组件内聚;定义在外部,可以构建基础样式库。

而像fontSizefontColor之类的仅在部分组件上具备的属性定义,在@Styles中无法使用。所以这里就需要用到@Extends装饰器。

Extend装饰器

import { CustomButton } from './CustomButton'

@Extend(Text)
function TextStyle() {
    .fontSize(50)
    .fontWeight(FontWeight.Bold)
    .id('HelloWorld')
}

@Entry
@Component
struct Index {
    @State message: string = 'Hello World';

    @Styles
    HelloWorldStyle() {
        .backgroundColor(Color.Yellow)
        .border({ width: { bottom: 5 }, color: '#ccc' })
        .margin({ bottom: 10 })
    }

    build() {
        Flex({
            direction: FlexDirection.Column,
            justifyContent: FlexAlign.Center,
            alignItems: ItemAlign.Center,
        }) {
            Text(this.message)
                .TextStyle()
                .HelloWorldStyle()
            CustomButton()
        }
        .height('100%')
        .width('100%')
    }
}

此外@Extend还可以带参数:

@Extend(Text)
function TextStyle(fontSize: number = 50, fontColor: ResourceStr | Color = '#f00') {
    .fontSize(fontSize)
    .fontColor(fontColor)
    .fontWeight(FontWeight.Bold)
    .id('HelloWorld')
}

然后直接调用

Text(this.message)
    .TextStyle(36, '#06c')
    .HelloWorldStyle()

我们就得到了:

在这里插入图片描述

@Extend装饰器不能装饰struct组件内部成员函数,这是与@Styles装饰器的一处不同。

事件回调

各种事件也都可以出来:

import { promptAction } from '@kit.ArkUI'

@Component
export struct CustomButton {
    build() {
        Column() {
            Button('My Button')
                .onClick(() => {
                    promptAction.showToast({
                        message: '你点我!'
                    })
                })
        }
    }
}

请注意这里使用了promptAction组件来实现toast效果:

在这里插入图片描述

事件回调的参数

对Web开发者来说,首先要注意的是:没有事件传递————没有冒泡捕获过程,不需要处理子节点事件冒泡到父节点的问题。

此外点击事件的回调参数提供了比较全面的详细信息UI信息,对实现一些弹框之类的UI展示比较有帮助。

在这里插入图片描述

比如event.target.area可以获取触发组件本身的布局信息:

在这里插入图片描述

自定义事件

我们改一下上面的组件代码,在组件中声明一个成员函数onClickMyButton,作为Button点击的回调:

@Component
export struct CustomButton {

    onClickMyButton?: () => void

    build() {
        Column() {
            Button('My Button')
                .onClick(() => {
                    if(typeof this.onClickMyButton === 'function') {
                        this.onClickMyButton()
                    }
                })
        }
    }
}

然后改一下Index页面代码,定义onClickMyButton回调:

build() {
    Flex({
        direction: FlexDirection.Column,
        justifyContent: FlexAlign.Center,
        alignItems: ItemAlign.Center,
    }) {
        // ...
        CustomButton({
            onClickMyButton: () => {
                promptAction.showToast({
                    message: '你又点我!'
                })
            }
        })
    }
    .height('100%')
    .width('100%')
}

在这里插入图片描述

属性与状态

mv(x)架构下,数据模型(model)一般分为属性状态两种概念,且都应当驱动视图(view)更新。

  • 属性(property),指外部(父级)传入值,自身只可读不可更改;如需要修改,则要通过回调通知父组件。
  • 状态(state),私有值,用于内部逻辑计算;一般来讲,状态的数据结构复杂度,与组件复杂度正相关。

ArkTS中,组件(struct)成员有诸多修饰符可选。基于个人的开发经验和习惯,我推荐使用单向数据流方式,模型层面仅使用@Prop@State来实现组件间交互。下面简单讲一下使用:

@State状态装饰器

在之前的代码中,可以看到一个用@State声明的状态值message

@State装饰的成员,可以对标reactuseState成员,或者vue组件中data()的某一个key

@Prop属性装饰器

@State装饰的成员,可以对标reactuseState成员,或者vue组件中data()的某一个key

@Component
export struct CustomButton {

    onClickMyButton?: () => void

    @Prop text: string = 'My Button'

    build() {
        Column() {
            Button(this.text)  // 使用该属性
                .onClick(() => {
                    if(typeof this.onClickMyButton === 'function') {
                        this.onClickMyButton()
                    }
                })
        }
    }
}

在父级调用

CustomButton({
    text: '我的按钮'
})

在这里插入图片描述

状态和属性的更改

再完善一下组件:

@Component
export struct CustomButton {
    onClickMyButton?: () => void
    @Prop text: string = 'My Button'
    @Prop count: number = 0
    build() {
        Column() {
            // 这里展示计数
            Button(`${this.text}(${this.count})`)
                .onClick(() => {
                    if(typeof this.onClickMyButton === 'function') {
                        this.onClickMyButton()
                    }
                })
        }
    }
}

这里声明了两个属性textcount,以及一个自定义事件onClickMyButton

父级声明一个状态clickCount,绑定子组件的count属性,并在子组件的自定义事件中,增加clickCount的值。预期页面的计数随clickCount变化,按钮组件的计数随属性count变化,两者应当同步。

@Entry
@Component
struct Index {
    @State message: string = 'Hello World';
    @State clickCount: number = 0

    @Styles
    HelloWorldStyle() {
        .backgroundColor(Color.Yellow)
        .border({ width: { bottom: 5 }, color: '#ccc' })
        .margin({ bottom: 10 })
    }


    @Builder
    SubTitle() {
        // 这里展示计数
        Text(`The message is "${this.message}", count=${this.clickCount}`)
            .margin({ bottom: 10 })
            .fontSize(12)
            .fontColor('#999')
    }

    build() {
        Flex({
            direction: FlexDirection.Column,
            justifyContent: FlexAlign.Center,
            alignItems: ItemAlign.Center,
        }) {
            Text(this.message)
                .TextStyle(36, '#06c')
                .HelloWorldStyle2()
            this.SubTitle()
            ItalicText('ItalicText')
            CustomButton({
                text: '点击次数',
                count: this.clickCount,
                onClickMyButton: () => {
                    this.clickCount += 1
                }
            })
        }
        .height('100%')
        .width('100%')
    }
}

实际效果:

在这里插入图片描述

符合预期。

属性监听

使用@Watch装饰器,可以监听@Prop装饰对象的变化,并能指定监听方法:

@Prop @Watch('onChange') count: number = 0

private onChange(propName: string) {
    console.log('>>>>>>', propName)
}

@Watch装饰器调用onChange时,会把发生变化的属性名作为参数传递给onChange;也就是说,我们可以只定义一个监听方法,通过入参propName来区分如何操作。

@Prop @Watch('onChange') count: number = 0
@Prop @Watch('onChange') stock: number = 0

private onChange(propName: string) {
    if(propName === 'count') {
        //...
    } else if(propName === 'stock') {
        //...
    }
}

我们下面用@Watch监听属性count,实现属性更改驱动组件内部状态变化。首先改造组件:

@Component
export struct CustomButton {
    onClickMyButton?: () => void
    @Prop text: string = 'My Button'
    @Prop @Watch('onChange') count: number = 0
    // 内部状态
    @State private double: number = 0
    
    private onChange() {
        this.double = this.count * 2
    }

    build() {
        Column() {
            Button(`${this.text}(${this.count} x 2 = ${this.double})`)
                .onClick(() => {
                    if(typeof this.onClickMyButton === 'function') {
                        this.onClickMyButton()
                    }
                })
        }
    }
}

在这里插入图片描述

效果可以对标react中的useEffect,或者vue中的observer或者watch

这里有一个隐含的问题:当@Prop被第一次赋值的时候,不会触发@Watch监听器。比如我们把页面状态clickCount初始化为3,这时候尬住了:

在这里插入图片描述

在web的解决方案中,这种问题自然是绑定组件生命周期。同样,ArtTS也是如此:

@Component
export struct CustomButton {
    onClickMyButton?: () => void
    @Prop text: string = 'My Button'
    @Prop @Watch('onChange') count: number = 0

    @State private double: number = 0

    private onChange() {
        this.double = this.count * 2
    }

    build() {
        Column() {
            Button(`${this.text}(${this.count} x 2 = ${this.double})`)
                .onClick(() => {
                    if(typeof this.onClickMyButton === 'function') {
                        this.onClickMyButton()
                    }
                })
        }
        // 这里绑定生命周期
        .onAttach(() => {
            this.onChange()
        })
    }
}

本文为了简便,直接在onAttach中使用监听函数初始化。具体情况请自行斟酌。

在这里插入图片描述

条件渲染

用过react的人都知道三目表达式的痛:

// 以下伪代码 未验证
export default MyPage = (props: { hasLogin: boolean; userInfo: TUserInfo }) => {
    const { hasLogin, userInfo } = props
    return <div className='my-wrapper'>{
        hasLogin ? <UserInfo info={userInfo} /> : <Login />
    }</div>
}

前面提过,由于return后面词法限制,只能使用纯表达式写法。或者,把return包裹到if..else中,总归不是那么优雅。

ArkTS则直接支持在build()中使用if...else分支写法:

build() {
    Column() {
        Button(`${this.text}(${this.count} x 2 = ${this.double})`)
            .onClick(() => {
                if(typeof this.onClickMyButton === 'function') {
                    this.onClickMyButton()
                }
            })
        if(this.count % 2 === 0) {
            Text('双数').fontColor(Color.Red).margin({ top: 10 })
        } else {
            Text('单数').fontColor(Color.Blue).margin({ top: 10 })
        }
    }
    .onAttach(() => {
        this.onChange()
    })
}

在这里插入图片描述

函数式组件

这里的函数式的命名,是纯字面的,并不是reactFunctional Component的意思。

这类组件由@Builder装饰器声明,对象可以是一个单独的function,抑或是struct组件中的一个方法。

需要特别注意的是,这里的function是指通过function声明的函数,不包括**箭头函数(Arrow Function) **。

import { CustomButton } from './CustomButton'

@Extend(Text)
function TextStyle(fontSize: number = 50, fontColor: ResourceStr | Color = '#f00') {
    .fontSize(fontSize)
    .fontColor(fontColor)
    .fontWeight(FontWeight.Bold)
    .id('HelloWorld')
}

@Builder
function ItalicText(content: string) {
    Text(content).fontSize(14).fontStyle(FontStyle.Italic).margin({ bottom: 10 })
}

@Entry
@Component
struct Index {
    @State message: string = 'Hello World';

    @Styles
    HelloWorldStyle() {
        .backgroundColor(Color.Yellow)
        .border({ width: { bottom: 5 }, color: '#ccc' })
        .margin({ bottom: 10 })
    }

    @Builder
    SubTitle() {
        Text(`The message is "${this.message}"`)
            .margin({ bottom: 10 })
            .fontSize(12)
            .fontColor('#999')
    }

    build() {
        Flex({
            direction: FlexDirection.Column,
            justifyContent: FlexAlign.Center,
            alignItems: ItemAlign.Center,
        }) {
            Text(this.message)
                .TextStyle(36, '#06c')
                .HelloWorldStyle()
            this.SubTitle()
            ItalicText('ItalicText')
            CustomButton()
        }
        .height('100%')
        .width('100%')
    }
}

上面的代码中,声明了一个外部组件ItalicText,一个内部组件this.SubTitle,可以在build()中直接使用。

在这里插入图片描述

由于@Builder的装饰对象是一个function函数,所以这个组件可以带参数动态渲染。

实现插槽

ArkTS中提供了@BuilderParam装饰器,可以让@Builder以参数的形式向其他组件传递。这为实现插槽提供了条件。

我们首先在组件中声明一个@BuilderParam,然后植入到组件的build()中。改造组件代码:

@Component
export struct CustomButton {
    onClickMyButton?: () => void
    @Prop text: string = 'My Button'
    @Prop @Watch('onChange') count: number = 0
    @State private double: number = 0
    // 插槽
    @BuilderParam slot: () => void

    private onChange() {
        this.double = this.count * 2
    }

    build() {
        Column() {
            Button(`${this.text}(${this.count} x 2 = ${this.double})`)
                .onClick(() => {
                    if(typeof this.onClickMyButton === 'function') {
                        this.onClickMyButton()
                    }
                })
            if(this.count % 2 === 0) {
                Text('双数').fontColor(Color.Red).margin({ top: 10 })
            } else {
                Text('单数').fontColor(Color.Blue).margin({ top: 10 })
            }
            // 植入插槽,位置自定
            if(typeof this.slot === 'function') {
                this.slot()
            }
        }
        .onAttach(() => {
            this.onChange()
        })
    }
}

页面代码更改:

build() {
    Flex({
        direction: FlexDirection.Column,
        justifyContent: FlexAlign.Center,
        alignItems: ItemAlign.Center,
    }) {
        Text(this.message)
            .TextStyle(36, '#06c')
            .HelloWorldStyle2()
        this.SubTitle()
        ItalicText('ItalicText')
        CustomButton({
            text: '点击次数',
            count: this.clickCount,
            onClickMyButton: () => {
                this.clickCount += 1
            },
            // 定义插槽
            slot: () => {
                this.SubTitle()
            }
        })
    }
    .height('100%')
    .width('100%')
}

在这里插入图片描述

这种单一插槽的情况,可以有更优雅的写法:

在这里插入图片描述

请注意:单一插槽,也就是说组件中仅包含一个@BuilderParam成员,且与成员命名无关。

如果有多个@BuilderParam成员,下面那种嵌套写法会在编译期报错:

[Compile Result]  In the trailing lambda case, 'CustomButton' must have one and only one property decorated with @BuilderParam, and its @BuilderParam expects no parameter.

这错误提示给出两点要求:

  • 仅有一个@BuilderParam装饰成员
  • 该成员函数不能有参数

看一个多插槽的例子,继续优化组件:

@Component
export struct CustomButton {
    onClickMyButton?: () => void
    @Prop text: string = 'My Button'
    @Prop @Watch('onChange') count: number = 0
    @State private double: number = 0

    @BuilderParam slot: () => void
    @BuilderParam slot2: () => void

    private onChange() {
        this.double = this.count * 2
    }

    build() {
        Column() {
            Button(`${this.text}(${this.count} x 2 = ${this.double})`)
                .onClick(() => {
                    if(typeof this.onClickMyButton === 'function') {
                        this.onClickMyButton()
                    }
                })
            if(typeof this.slot === 'function') {
                this.slot()
            }
            if(this.count % 2 === 0) {
                Text('双数').fontColor(Color.Red).margin({ top: 10 })
            } else {
                Text('单数').fontColor(Color.Blue).margin({ top: 10 })
            }
            if(typeof this.slot2 === 'function') {
                this.slot2()
            }
        }
        .onAttach(() => {
            this.onChange()
        })
    }
}

在这里插入图片描述

请注意:在向@BuilderParam插槽传入@Builder的时候,一定包一层箭头函数,否则会引起this指向问题。

写在最后

从个人感受来讲,如果一个开发者对TS有充分的使用经验,进入ArkTS之后,只要对ArkTS的方言、开发模式和基础库做简单了解,基本就能上手开发了,总体门槛不高。

最后吐几个槽点:

  • 语法方面:虽然叫ts,但ts的类型推断几乎没有;没有type类型声明;不能一次性声明嵌套的复杂类型;没有any/unkown类型,Object有点类似unknown,仅此而已;不支持解构取值。
  • 文档系统不完善,使用不方便,检索困难。
  • 开发工具在模拟器或者真机下没有热更,每次更改都要重新编译,效率不高。

不过,上面的槽点只是有点烦,习惯就好。

关于 OpenTiny

在这里插入图片描述

OpenTiny 是一套企业级 Web 前端开发解决方案,提供跨端、跨框架、跨版本的 TinyVue 组件库,包含基于 Angular+TypeScript 的 TinyNG 组件库,拥有灵活扩展的低代码引擎 TinyEngine,具备主题配置系统TinyTheme / 中后台模板 TinyPro/ TinyCLI 命令行等丰富的效率提升工具,可帮助开发者高效开发 Web 应用。

欢迎加入 OpenTiny 开源社区。添加微信小助手:opentiny-official 一起参与交流前端技术~
OpenTiny 官网:https://opentiny.design/
OpenTiny 代码仓库:https://github.com/opentiny/
TinyVue 源码:https://github.com/opentiny/tiny-vue
TinyEngine 源码: https://github.com/opentiny/tiny-engine
欢迎进入代码仓库 Star🌟TinyEngine、TinyVue、TinyNG、TinyCLI~ 如果你也想要共建,可以进入代码仓库,找到 good first issue标签,一起参与开源贡献~

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

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

相关文章

定积分与不定积分

定积分与不定积分 引言正文不定积分理解角度1理解角度2 定积分 引言 可能大家看到这个标题会不屑一顾&#xff0c;觉得这个还用你教我吗&#xff0c;高等数学最简单的内容。今天突然想到一个问题&#xff0c;就是为什么不定积分会有一个常数 C C C 出现&#xff0c;这个常数 …

继电器驱动电路的可靠性设计分析

在温度-30℃到85℃、供电电源9V-16V范围条件下&#xff0c;保证外部继电器能正常作动&#xff0c;且不发生负载能力降低的情况。&#xff08;注&#xff1a;需要详细的外部继电器规格说明&#xff09; 对于控制多路输出而且要求负载同时打开的模块&#xff0c;必须以50ms(10ms…

C++_单例模式

目录 1、饿汉方式实现单例 2、懒汉方式实现单例 3、单例模式的总结 结语 前言&#xff1a; 在C中有许多设计模式&#xff0c;单例模式就是其中的一种&#xff0c;该模式主要针对类而设计&#xff0c;确保在一个进程下该类只能实例化出一个对象&#xff0c;因此名为单例。而…

OpenCV 图像旋转和平移 数学和代码原理详解

文章目录 数学原理旋转矩阵平移和旋转合成变换矩阵应用在OpenCV中的实现 代码关键点解读完整代码C代码&#xff1a;Python代码&#xff1a; 在OpenCV中进行图像旋转涉及到一些基本的几何变换和图像处理操作。 数学原理 在图像旋转中&#xff0c;背后的数学原理主要涉及二维欧…

嵌入式硬件-Xilinx FPGA DDR4 接口配置基础(PG150)

1. 简介 1.1 DDR4 SDRAM 控制器主要特点 支持8到80位接口宽度的组件&#xff08;支持 RDIMM、LRDIMM、UDIMM 和 SODIMM&#xff09; 最大组件限制为9&#xff0c;此限制仅适用于组件&#xff0c;不适用于 DIMM。密度支持 最高支持 32 GB 的组件密度&#xff0c;64 GB 的 LRDI…

步步精慕尼黑上海电子展完美收官,感恩所有相遇,期待下次再会

2024年7月11日至13日&#xff0c;慕尼黑上海电子展圆满落幕&#xff0c;步步精科技&#xff08;以下简称步步精&#xff09;在此次展会上取得了丰硕的成果。作为连接器行业的重要制造商&#xff0c;步步精携带其最新产品和连接器技术方案亮相展会&#xff0c;吸引了大量参观者的…

【HarmonyOS】HarmonyOS NEXT学习日记:六、渲染控制、样式结构重用

【HarmonyOS】HarmonyOS NEXT学习日记&#xff1a;六、渲染控制、样式&结构重用 渲染控制包含了条件渲染和循环渲染&#xff0c;所谓条件渲染&#xff0c;即更具状态不同&#xff0c;选择性的渲染不同的组件。 而循环渲染则是用于列表之内的、多个重复元素组成的结构中。 …

RK3568笔记四十二:OLED 屏幕驱动(模拟I2C)

若该文为原创文章&#xff0c;转载请注明原文出处。 本篇记录使用GPIO模拟I2C驱动OLED屏幕&#xff0c;显示界面效果如下。 主要流程是&#xff0c;修改设备树&#xff0c;使用普通IO口&#xff0c;驱动模拟I2C方式&#xff0c;应用程直接传输数据控制。 1、修改设备 2、编写…

Go语言 Import导入

本文主要介绍Go语言import导入使用时注意事项和功能实现示例。 目录 Import 创建功能文件夹 加法 减法 主函数 优化导入的包名 .引入方法 总结 Import 创建功能文件夹 做一个计算器来演示&#xff0c;首先创建test文件夹。 加法 在test文件夹中创建add文件夹&#xff…

数据预处理在建模中的重要性与常见方法(三):特征工程篇

数据预处理在建模中的重要性与常见方法&#xff08;三&#xff09;&#xff1a;特征工程篇 特征工程是数据预处理中至关重要的一步&#xff0c;通过构建、转换和选择最能代表数据特性的特征&#xff0c;以提高模型的性能和准确性。常见的特征工程方法包括特征选择、特征提取和特…

前端-模拟请求数据mook第三方插件 json-server的使用

大纲 第一步下载第二配置mook的数据源第三配置启动命令第四运行模拟服务第五测试接口如果要进行更复杂的操作 第一步下载 npm install json-server -D"devDependencies": {"json-server": "^1.0.0-beta.1"}第二配置mook的数据源 在项目的根目录…

某指挥调度系统功能展示(下)

照片管理 拍照是普通执勤巡检中很常用的信息记录功能。 通过此功能可以看到设备本地拍摄的照片&#xff0c;此平台分成了两部分&#xff1a; 一部分是设备上的&#xff0c;需要设备在线才可以访问&#xff1b;支持上传到平台&#xff0c;并且在设备端有相应的选择&#xff0…

人、智能、机器人……

在遥远的未来之城&#xff0c;智能时代如同晨曦般照亮了每一个角落&#xff0c;万物互联&#xff0c;机器智能与人类智慧交织成一幅前所未有的图景。这座城市&#xff0c;既是科技的盛宴&#xff0c;也是人性与情感深刻反思的舞台。 寓言&#xff1a;《智光与心影》 在智能之…

Linux性能分析之-CPU篇

开发车载软件app&#xff0c;除了常用Android操作系统外&#xff0c;还可能是基于Linux系统开发。对于web应用基本也都部署在Linux系统上&#xff0c;所以&#xff0c;进行系统性能分析&#xff0c;很大情况下都是对Linux系统进行性能分析。此篇博客将重点介绍如果收集CPU相关指…

GPT-4o mini是什么?

今天&#xff0c;全网都知道 OpenAI 发现货了&#xff01; GPT-4o mini 取代 GPT 3.5&#xff0c;从此坐上正主之位。 从官网信息来看&#xff0c;OpenAI 最新推出的 GPT-4o mini 重新定义了 AI 成本效益的标准&#xff0c;其性能优于前代模型 GPT-3.5 Turbo&#xff0c;且成本…

SpringBoot系列—4.SpringBoot 整合Mybatis、MP(MyBatis-Plus)

SpringBoot系列—1.IDEA搭建SpringBoot框架 SpringBoot系列—2.SpringBoot拦截器篇 SpringBoot系列—3.SpringBoot Redis篇 SpringBoot系列—4.SpringBoot 整合Mybatis、MP&#xff08;MyBatis-Plus&#xff09; SpringBoot系列—5.SpringBoot 整合Mybatis-Plus分页 **1.pom.xm…

设计模式-Git-其他

目录 设计模式&#xff1f; 创建型模式 单例模式&#xff1f; 啥情况需要单例模式 实现单例模式的关键点&#xff1f; 常见的单例模式实现&#xff1f; 01、饿汉式如何实现单例&#xff1f; 02、懒汉式如何实现单例&#xff1f; 03、双重检查锁定如何实现单例&#xff…

【扩散模型(五)】IP-Adapter 源码详解3-推理代码

系列文章目录 【扩散模型&#xff08;一&#xff09;】中介绍了 Stable Diffusion 可以被理解为重建分支&#xff08;reconstruction branch&#xff09;和条件分支&#xff08;condition branch&#xff09;【扩散模型&#xff08;二&#xff09;】IP-Adapter 从条件分支的视…

前端JS特效第48集:terseBanner焦点图轮播插件

terseBanner焦点图轮播插件&#xff0c;先来看看效果&#xff1a; 部分核心的代码如下(全部代码在文章末尾)&#xff1a; <!DOCTYPE html> <html lang"zh"> <head><meta charset"UTF-8"><meta http-equiv"X-UA-Compatibl…

python每日学习:异常处理

python每日学习8&#xff1a;异常处理 Python中的错误可以分为两种&#xff1a;语法错误和异常 语法错误(Syntax errors) &#xff1a;代码编译时的错误&#xff0c;不符合Python语言规则的代码会停止编译并返回 错误信息。 缺少起始符号或结尾符号(括号、引号等)。 缩进错误…