【Harmony】SCU暑期实训鸿蒙开发学习日记Day1

关于ArkTS和ArkUI,基础语法请看👉官方开发手册

系统学习后,聊聊几个点,面向刚学习这门语言的小白,用于巩固和回顾😋

目录

类型推断应用

函数相关

布局方式

线性布局

堆叠布局

网格布局

弹性布局

渲染相关

条件渲染

循环渲染

ForEach

Repeat

数据懒加载

装饰器

数据传递装饰器

省流版

@State

@Prop

@Provide 和 @Consume

@Observed

增强和扩展组件功能

@Extender

@Style

@Builder

自定义组件

创建自定义组件

使用 @Prop 动态传参

使用 @State 和 @Link 管理状态

使用 @BuilderParam 传递UI

router-路由操作

页面跳转和后退

页面栈

路由模式

路由传参

Stage模型

App

Module

Ability

关系和交互

生命周期流程示例


类型推断应用

类型推断是一种自动确定表达式类型的机制,能够在不明确指定类型的情况下,通过代码的上下文来推断出合适的类型。这种机制有助于减少代码中的类型声明,使代码更简洁和易于维护。

变量声明与初始化: 当你在声明变量时赋予它初始值,ArkTS会根据初始值推断变量的类型。

let num = 10;  // 推断为number类型
let str = "Hello";  // 推断为string类型
let isTrue = true;  // 推断为boolean类型
let numbers = [1, 2, 3];  // 推断为number[]
let user = {
    name: "Alice",
    age: 30
};  // 推断为{ name: string, age: number }

函数返回值: ArkTS会根据函数体内的返回值来推断函数的返回类型。

function getNumber() {
    return 42;  // 推断返回值类型为number
}

类型兼容性: ArkTS会在需要的时候推断出类型,以确保类型之间的兼容性。

let x = "hello";
let y = x;  // 推断y的类型为string

泛型推断: 在使用泛型时,ArkTS会根据传入的参数类型来推断泛型的具体类型。

function identity<T>(arg: T): T {
    return arg;
}

let output = identity(42);  // 推断T为number,output的类型为number

函数相关

常规函数声明

这种方式使用 function 关键字,可以显式声明参数和返回值类型。

function add(x: number, y: number): number {
    return x + y;
}

函数表达式

函数表达式可以赋值给变量,变量的类型可以显式声明。

const multiply: (x: number, y: number) => number = function(x, y) {
    return x * y;
};

箭头函数

箭头函数是一种简洁的函数声明方式,常用于简化函数表达式。

const subtract = (x: number, y: number): number => {
    return x - y;
};

重载函数

通过定义多个函数签名,可以实现函数重载。

function double(x: number): number;
function double(x: string): string;

function double(x: any): any {
    if (typeof x === "number") {
        return x * 2;
    } else if (typeof x === "string") {
        return x + x;
    }
}

泛型函数

泛型函数允许你定义可复用的函数,并在调用时指定类型。

function identity<T>(arg: T): T {
    return arg;
}

let output1 = identity<string>("myString");  // T 被推断为 string
let output2 = identity<number>(100);  // T 被推断为 number

参数

在ArkTS中,函数参数的处理可以非常灵活,包括可选参数、默认参数和剩余参数。这三者的综合运用可以使函数声明更加简洁和强大,适应多种调用场景。

①可选参数和默认参数

可选参数和默认参数在函数声明中都允许函数参数有灵活性:

  • 可选参数使用 ? 标识,使参数可以在调用时省略。
  • 默认参数为参数提供默认值,当调用时未提供该参数时使用默认值。
function greet(name: string, greeting: string = "Hello", punctuation?: string): string {
    if (punctuation) {
        return `${greeting}, ${name}${punctuation}`;
    } else {
        return `${greeting}, ${name}!`;
    }
}

// 示例调用
console.log(greet("Alice"));                     // 输出: Hello, Alice!
console.log(greet("Bob", "Hi"));                 // 输出: Hi, Bob!
console.log(greet("Charlie", "Hey", "?"));       // 输出: Hey, Charlie?

②剩余参数

剩余参数使用 ... 语法,可以将多个参数收集到一个数组中,用于处理变长参数列表的场景。

function sum(...numbers: number[]): number {
    return numbers.reduce((acc, curr) => acc + curr, 0);
}

// 示例调用
console.log(sum(1, 2, 3));         // 输出: 6
console.log(sum(10, 20, 30, 40));  // 输出: 100

布局方式

线性布局

线性布局是最常用的布局之一,它将子元素沿水平方向或垂直方向排列。

特性

  • 可以设置子元素的排列方向:水平(row)或垂直(column)。
  • 支持设置子元素之间的间距。

示例

import { Column, Text, Button } from 'ArkUI';

Column() {
    Text('Item 1');
    Text('Item 2');
    Button('Click Me');
}

堆叠布局

堆叠布局将子元素堆叠在一起,所有元素都位于同一个坐标位置。

特性

  • 子元素可以相互覆盖。
  • 常用于需要将多个元素叠加在一起的场景,如图像叠加文本。

示例

import { Stack, Image, Text } from 'ArkUI';

Stack() {
    Image('background.png');
    Text('Overlay Text');
}

网格布局

网格布局将子元素按照网格进行排列,子元素可以跨行或跨列。

特性

  • 灵活的行列定义。
  • 支持子元素跨行、跨列。

示例

import { Grid, Text } from 'ArkUI';

Grid(columns="1fr 1fr", rows="auto auto") {
    Text('Item 1').gridColumn("1 / 2").gridRow("1");
    Text('Item 2').gridColumn("2 / 3").gridRow("1");
    Text('Item 3').gridColumn("1 / 3").gridRow("2");
}

弹性布局

弹性布局提供了一种灵活的布局方式,适用于复杂的自适应布局。

特性

  • 支持主轴和交叉轴上的元素对齐和分布。
  • 子元素可以按比例缩放。

示例

import { Flex, Text } from 'ArkUI';

Flex(direction="row", justifyContent="space-between") {
    Text('Item 1');
    Text('Item 2');
    Text('Item 3');
}

 

 

渲染相关

条件渲染

条件渲染允许你根据某些条件来决定是否渲染某个UI组件。通常使用三元运算符或 if 语句来实现。

示例

@Entry
@Component
struct ConditionalRenderingComponent {
  @State isVisible: boolean = true;

  build() {
    Column() {
      if (this.isVisible) {
        Text('This text is visible');
      } else {
        Text('This text is hidden');
      }
      Button(this.isVisible ? 'Hide' : 'Show').onClick(() => {
        this.isVisible = !this.isVisible;
      });
    }
  }
}

循环渲染

循环渲染用于根据数组数据来渲染一组相似的UI组件。在ArkUI中,常用的循环渲染方法有 ForEachRepeat

ForEach

ForEach 用于遍历数组并渲染每个元素。

示例

@Entry
@Component
struct ForEachComponent {
  @State items: string[] = ['Item 1', 'Item 2', 'Item 3'];

  build() {
    Column() {
      ForEach(this.items, (item) => {
        Text(item);
      });
    }
  }
}
Repeat

Repeat 用于渲染一定次数的相同组件。

示例

@Entry
@Component
struct RepeatComponent {
  build() {
    Column() {
      Repeat(5, (index) => {
        Text(`Item ${index + 1}`);
      });
    }
  }
}

 

数据懒加载

数据懒加载用于按需加载数据,从而提高应用性能和响应速度。通常在需要加载大量数据时使用懒加载。

 

@Entry
@Component
struct LazyLoadComponent {
  @State data: string[] = [];
  @State hasMoreData: boolean = true;

  onInit() {
    this.loadData();
  }

  loadData() {
    // 模拟数据加载
    setTimeout(() => {
      this.data = this.data.concat(['New Item 1', 'New Item 2', 'New Item 3']);
      this.hasMoreData = this.data.length < 20;  // 假设最多加载20条数据
    }, 1000);
  }

  build() {
    Column() {
      ForEach(this.data, (item) => {
        Text(item);
      });
      if (this.hasMoreData) {
        Button('Load More').onClick(() => {
          this.loadData();
        });
      }
    }
  }
}

装饰器

什么是装饰器?

类似java的注解

用于装饰类、结构、方法以及变量,并赋予其特殊的含义。如@Entry、@Component和@State都是装饰器,@Component表示自定义组件,@Entry表示该自定义组件为入口组件,@State表示组件中的状态变量,状态变量变化会触发UI刷新。

数据传递装饰器

从数据的传递形式和同步类型层面看,装饰器也可分为:

  • 只读的单向传递;

  • 可变更的双向传递。

省流版

  • @State:管理组件内部状态,不涉及组件间数据传递。
  • @Prop:接收父组件传递的只读数据,用于单向数据流。
  • @Link:实现双向数据绑定,允许子组件修改父组件的数据。
  • @Provide 和 @Consume:用于跨组件层级的数据共享,适用于全局状态管理。
  • @Observed:监视对象属性变化,自动触发组件重新渲染。
  • @ObjectLink:传递复杂对象,允许子组件修改,适用于复杂数据管理。

@State

功能

  • 声明组件内部的状态。
  • 状态数据变化时,组件自动重新渲染。

使用场景

  • 用于组件内部的可变数据管理,不涉及组件之间的数据传递。

示例

@State count: number = 0;

区别

  • 仅限于组件内部使用,不会与其他组件共享。

@Prop

功能

  • 接收父组件传递的属性(props)。
  • 这些属性是只读的,不能在子组件中修改。

使用场景

  • 用于子组件从父组件接收数据。

示例

@Prop title: string;

区别

  • 只读属性,适用于父组件向子组件传递数据,不支持数据的双向绑定。

功能

  • 创建组件之间的数据连接,允许子组件修改父组件的数据。
  • 支持数据的双向绑定。

使用场景

  • 用于需要子组件与父组件共享和修改数据的场景。

示例

@Link count: number;

区别

  • @Prop 相比,@Link 允许双向数据绑定,子组件可以更新父组件的数据。

@Provide 和 @Consume

功能

  • @Provide:在祖先组件中提供数据。
  • @Consume:在后代组件中消费数据。

使用场景

  • 用于跨多个组件层级的数据共享。

示例: 祖先组件:

@Provide theme: string = "dark";

后代组件:

@Consume theme: string;

区别

  • 适用于需要跨越多层组件共享数据的场景,与 @State@Prop 不同,主要用于更广泛的数据分发。

@Observed

功能

  • 监视对象属性的变化。
  • 属性变化时,组件自动重新渲染。

使用场景

  • 用于需要自动追踪和响应数据变化的场景。

示例

@Observed userName: string = "John";

区别

  • @State 类似,但更适用于需要自动监视对象属性变化的场景。

功能

  • 允许复杂对象作为属性传递给子组件。
  • 子组件可以修改这些对象。

使用场景

  • 用于复杂数据结构的共享和管理。

示例

@ObjectLink userDetails: User;

区别

  • @Link 相似,但专门用于复杂对象的数据共享和管理。

增强和扩展组件功能

在ArkTS中,@Extender@Style@Builder 是特定的注解,用于增强和扩展组件的功能。

@Extender

功能

  • @Extender 注解用于扩展现有的组件或类,允许在现有功能的基础上添加新的行为或属性。

使用场景

  • 当需要在不修改原组件或类的情况下,增加或修改功能时使用。

示例

@Extender
class ExtendedComponent extends BaseComponent {
    newMethod() {
        // 新的方法或属性
    }
}

区别

  • @Extender 注解的主要作用是增强现有类或组件的功能,类似于装饰器模式。

@Style

功能

  • @Style 注解用于为组件应用特定的样式,允许开发者在组件声明中直接定义样式。

使用场景

  • 在需要为组件指定特定样式或动态样式时使用。

示例

@Style({
    backgroundColor: 'blue',
    fontSize: '14px'
})
class StyledComponent {
    // 组件逻辑
}

区别

  • @Style 注解使得样式定义与组件逻辑紧密结合,增强了样式管理的灵活性。

@Builder

功能

  • @Builder 注解用于构建复杂对象或组件,简化了对象的创建过程,通常用于需要链式调用来设置属性的场景。

使用场景

  • 当需要简化复杂对象或组件的创建过程,使用链式调用设置多个属性时使用。

示例

@Builder
class ComplexObject {
    private prop1: string;
    private prop2: number;

    setProp1(value: string): this {
        this.prop1 = value;
        return this;
    }

    setProp2(value: number): this {
        this.prop2 = value;
        return this;
    }

    build(): ComplexObject {
        return this;
    }
}

// 使用示例
const obj = new ComplexObject().setProp1("value1").setProp2(123).build();

区别

  • @Builder 注解通过链式调用的方式简化了复杂对象的构建过程,增强了代码的可读性和可维护性。

自定义组件

创建自定义组件

自定义组件通过 @Component 装饰器定义。以下是一个简单的示例:

示例:创建一个简单的 MyButton 组件。

@Component
struct MyButton {
  @Prop label: string;

  build() {
    Button(this.label).onClick(() => {
      console.log(`${this.label} clicked`);
    });
  }
}

在这个示例中,MyButton 组件接收一个 label 属性,并在按钮点击时输出该标签。

使用 @Prop 动态传参

@Prop 注解用于父组件向子组件传递数据。

示例

@Entry
@Component
struct HomePage {
  build() {
    Column() {
      MyButton({ label: 'Click Me' });
    }
  }
}

使用 @State@Link 管理状态

示例

  • HomePage 组件使用 @State 管理 parentCount
  • Counter 组件通过 @Link 接收并修改 count,实现与父组件 HomePage 的数据绑定和状态同步。
// HomePage.ets
@Entry
@Component
struct HomePage {
  @State parentCount: number = 0;

  build() {
    Column() {
      Text(`Parent Count: ${this.parentCount}`);
      Counter({ count: this.parentCount });
    }
  }
}

// Counter.ets
@Component
struct Counter {
  @Link count: number;

  build() {
    Column() {
      Text(`Count: ${this.count}`);
      Button('Increment').onClick(() => {
        this.count += 1;
      });
    }
  }
}

使用 @BuilderParam 传递UI

@BuilderParam 注解用于在组件间传递UI组件,特别适用于需要传递复杂布局或多个UI组件的场景。

示例:创建一个可以接收自定义标题和内容的 CustomCard 组件。

CustomCard.ets

@Component
struct CustomCard {
  @BuilderParam title: () => any;
  @BuilderParam content: () => any;

  build() {
    Column() {
      this.title();
      this.content();
    }
  }
}

使用 CustomCard 的父组件

@Entry
@Component
struct HomePage {
  build() {
    CustomCard({
      title: () => Text('Custom Title'),
      content: () => Text('This is the custom content of the card.')
    });
  }
}

 

router-路由操作

页面跳转和后退

使用 router 对象可以在不同页面之间进行跳转和后退操作。

页面跳转

在页面跳转时,还可以使用 pushUrlreplaceUrl 方法。

pushUrl:用于在当前页面栈中推入新页面。

router.pushUrl('pages/DetailsPage');

replaceUrl:用于替换当前页面栈的顶层页面。

router.replaceUrl('pages/DetailsPage');

页面栈

页面栈管理用于维护页面的导航历史,允许应用程序在多个页面之间前进和后退。

页面栈内最多32个页面。

路由模式

ArkUI支持两种路由模式:standardsingle

  • standard模式:标准模式,每次跳转页面都会创建一个新的实例。
  • single模式:单实例模式,每次跳转页面时,都会使用同一个页面实例,类似于单例模式。

设置路由模式

router.setMode('standard'); // 或 'single'

路由传参

在页面跳转时,可以通过路由传递参数,这些参数可以在目标页面中获取。

传递参数

router.push({
  url: 'pages/DetailsPage',
  params: {
    id: 123,
    name: 'example'
  }
});

接收参数

@Entry
@Component
struct DetailsPage {
  @State id: number;
  @State name: string;

  onInit() {
    const params = router.getParams();
    this.id = params.id;
    this.name = params.name;
  }

  build() {
    Column() {
      Text(`ID: ${this.id}`)
      Text(`Name: ${this.name}`)
    }
  }
}

Stage模型

在ArkUI中,Stage模型是HarmonyOS的应用开发模型之一,它管理应用程序的生命周期和各个组件的交互。Stage模型由App、Module和Ability三部分组成。下面详细介绍它们之间的关系和生命周期。

App

功能

  • App是应用程序的根实体,代表整个应用的生命周期。它是应用的入口,管理应用的初始化、全局状态和资源。

生命周期

  • onCreate(): 应用启动时调用,用于进行初始化操作。
  • onDestroy(): 应用销毁时调用,用于进行清理操作。

示例

@Entry
class MyApp extends App {
  onCreate() {
    console.log('Application created');
  }

  onDestroy() {
    console.log('Application destroyed');
  }
}

Module

功能

  • Module是应用程序的功能模块,一个应用可以包含多个模块,每个模块可以包含多个Ability。
  • Module通过配置文件(config.json)定义,描述了模块的能力、权限等信息。

示例config.json:

{
  "module": {
    "abilities": [
      {
        "name": "MainAbility",
        "label": "Main Ability",
        "icon": "$media:icon",
        "type": "page"
      }
    ],
    "deviceType": ["phone", "tablet"],
    "requiredPermissions": ["INTERNET"]
  }
}

Ability

功能

  • Ability是应用程序的核心组件,代表应用的具体功能。主要有两种类型:Page Ability和Service Ability。
    • Page Ability:用于管理界面和用户交互。
    • Service Ability:用于后台任务和服务。

生命周期

  • Page Ability

    • onStart(): Ability启动时调用。
    • onActive(): Ability进入前台时调用。
    • onInactive(): Ability进入后台时调用。
    • onBackground(): Ability完全进入后台时调用。
    • onStop(): Ability停止时调用。
  • Service Ability

    • onStart(): Ability启动时调用。
    • onCommand(): 接收并处理命令。
    • onStop(): Ability停止时调用。

示例MainAbility.ts:

@Entry
class MainAbility extends Ability {
  onStart(intent) {
    console.log('MainAbility started');
  }

  onActive() {
    console.log('MainAbility active');
  }

  onInactive() {
    console.log('MainAbility inactive');
  }

  onBackground() {
    console.log('MainAbility background');
  }

  onStop() {
    console.log('MainAbility stopped');
  }
}

关系和交互

  • App 是整个应用的入口,管理全局状态和资源。
  • Module 是应用的功能模块,包含一个或多个Ability。
  • Ability 是具体功能的实现单元,可以是页面能力(Page Ability)或者服务能力(Service Ability)。

它们通过配置文件(如config.json)和生命周期方法进行交互和管理。

生命周期流程示例

一个典型的应用启动和运行流程如下:

  1. 应用启动:App的onCreate()方法被调用,应用初始化。
  2. Module加载:根据config.json加载模块和权限。
  3. Ability启动:Ability的onStart()方法被调用。
  4. Ability进入前台:Ability的onActive()方法被调用。
  5. Ability进入后台:Ability的onInactive()onBackground()方法被依次调用。
  6. Ability停止:Ability的onStop()方法被调用。
  7. 应用销毁:App的onDestroy()方法被调用,应用资源被清理。

通过这种层次化的设计,Stage模型使得应用的开发和管理更加模块化、清晰和高效。

  • 19
    点赞
  • 31
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值