当前位置: 首页 > article >正文

鸿蒙面试题库收集(一):ArkTSArkUI-基础理论

收集官网faq:https://developer.huawei.com/consumer/cn/doc/harmonyos-faqs/faqs-arkui-kit-0000001769732210

一. ArkTS&ArkUI

1. 基础理论

1. 鸿蒙相关的生命周期都有哪些?

(1)UIAbility生命周期: onCreate、onWindowStageCreate、onForeground、onBackground、onWindowStageDestroy、onDestroy。

  • onCreate:Create状态为在应用加载过程中,UIAbility实例创建完成时触发,系统会调用onCreate()回调。可以在该回调中进行页面初始化操作,例如变量定义资源加载等,用于后续的UI展示。

  • onWindowStageCreate():UIAbility实例创建完成之后,在进入Foreground之前,系统会创建一个WindowStage。WindowStage创建完成后会进入onWindowStageCreate()回调,可以在该回调中设置UI加载、设置WindowStage的事件订阅。[事件订阅代码]

  • onForegound():在UIAbility的UI可见之前,如UIAbility切换至前台时触发。可以在onForeground()回调中申请系统需要的资源,或者重新申请在onBackground()中释放的资源。

  • onWindowStageDestory():在UIAbility实例销毁之前,则会先进入onWindowStageDestroy()回调,可以在该回调中释放UI资源。

  • onBackground():在UIAbility的UI完全不可见之后,如UIAbility切换至后台时候触发。可以在onBackground()回调中释放UI不可见时无用的资源,或者在此回调中执行较为耗时的操作,例如状态保存等。

  • onWindowStageDestory():在UIAbility实例销毁之前,则会先进入onWindowStageDestroy()回调,可以在该回调中释放UI资源。

  • onDestroy():Destroy状态在UIAbility实例销毁时触发。可以在onDestroy()回调中进行系统资源的释放、数据的保存等操作。

(2)页面生命周期:onPageShow、onPageHide、onBackPress。 页面生命周期,说白了就是@Entry修饰的组件,才称之为页面。

  • onPageShow:页面每次显示时触发一次,包括路由过程、应用进入前台等场景,仅@Entry装饰的自定义组件生效。
  • onPageHide:页面每次隐藏时触发一次,包括路由过程、应用进入后台等场景,仅@Entry装饰的自定义组件生效。
  • onBackPress:当用户点击返回按钮时触发,仅@Entry装饰的自定义组件生效。

(3)组件生命周期:aboutToAppear(发起网络请求)、aboutToDisappear。

  • aboutToAppear:在创建自定义组件的新实例后,在执行其build()函数之前执行。允许在aboutToAppear函数中改变状态变量,更改将在后续执行build()函数中生效。
  • aboutToDisappear:函数在自定义组件销毁之前执行。不允许在aboutToDisappear函数中改变状态变量,特别是@Link变量的修改可能会导致应用程序行为不稳定。

按返回键页面执行生命周期方法:

  • 打开第一个页面:
    • Index:aboutToAppear
    • Index:onPageShow
  • 跳转第二个页面:
    • Index:onPageHide
    • Second:aboutToAppear
    • Second:onPageShow
  • 点击back:如果是在第二个页面跳转到第一个页面:
    • Second:onBackPress Second:onPageHide
    • Second:onPageHide Index:aboutToAppear
    • Index:onPageShow Index:onPageShow
    • Second:aboutToDisappear

返回页面不走aboutToAppear:

  • aboutToAppear函数在创建自定义组件的新实例后,在执行其build()函数之前执行。
  • 返回页面时==不需要走重新创建==,不会执行aboutToAppear,只会执行onPageShow。

问:aboutToAppear和onAppear的区别?

  • aboutToAppear:是组件的生命周期方法,当组件实例创建后,执行build函数之前执行aboutToAppear

  • onAppear:是组件的属性方法,在该组件显示时触发此回调

    Text()
    .onAppear(()=>{}
2. ArkUI的两大开发范式是什么,区别是什么
  • ArkUI推荐使用声明式开发范式 , 其他的框架有参考类Web开发范式
  • 类Web开发范式:采用经典的HML、CSS、JavaScript三段式开发方式,即使用HML标签文件搭建布局、使用CSS文件描述样式、使用JavaScript文件处理逻辑。该范式更符合于Web前端开发者的使用习惯,便于快速将已有的Web应用改造成方舟UI框架应用。

  • 声明式开发范式:采用基于TypeScript声明式UI语法扩展而来的ArkTS语言,从组件、动画和状态管理三个维度提供UI绘制能力。

  • ==延伸问题==:有听过命令式编程么,命令式编程与声明式编程的区别是什么?

    • 其实这里的命令式编程,就相当于是类Web开发范式
  • 我们来对比一下命令式和声明式

  • 声明式开发范式 : 只需要描述/声明 , 你要做什么 (通过封装好的组件以及相关熟悉方法 , 快速实现目的)

  • 命令式开发范式 : 不仅需要知道做什么 , 更需要知道如何做 (需要通过最原始的方式 , 一步一步实现)

  • 左侧是纯前端实现的按钮点击 , 也就是命令式

    • 命令式需要自己一点一点实现 , 如何做必须清楚
  • 右侧是ArkTs实现的按钮点击 , 也就是声明式

    • 声明式只需要知道做什么 , 调用对应api即可 , 不需要知道内部如何实现
3. 项目使用的是harmoneyos还是openharmoney,区别是啥 ?

HarmonyOS:OpenHarmony+闭源应用和华为移动服务HMS(比如应用市场,视频,音乐等app)
Andoird:aosp(android open source project) + GMS(Google Mobile Service)

4. arkts中哪些类不能被继承, 面试官关注点是组件是否可以继承?(组件是否可以被继承)

组件不能被继承,被@compent修饰的自定义组件不能被继承,只能引用,或者对外暴露方法。

官网解释:

  • struct:自定义组件基于struct实现,struct + 自定义组件名 + {...}的组合构成自定义组件,==不能有继承关系==。对于struct的实例化,可以省略new。

  • @Component:@Component装饰器仅能装饰struct关键字声明的数据结构。==struct被@Component装饰后具备组件化的能力==,需要实现build方法描述UI,一个struct只能被一个@Component装饰。@Component可以接受一个可选的bool类型参数。

    @Component
    struct MyComponent {
    }
5.介绍Stage模型和FA模型
  1. Stage模型 : HarmonyOS 3.1推出 也就是API9 , 是目前==主推==且会长期演进的模型
    • 由于提供了AbilityStage、WindowStage等类作为应用组件和Window窗口的“舞台”,因此称这种应用模型为Stage模型
    • stage: 舞台 /steɪdʒ/
  2. FA模型: FA(Feature Ability)模型:HarmonyOS早期版本开始支持的模型,已经不再主推
    • feature: 特点 /ˈfiːtʃə(r)/
  3. 区别: Stage模型与FA模型最大的区别在于
    1. Stage模型中,多个应用组件共享同一个ArkTS引擎实例;
    2. 而FA模型中,每个应用组件独享一个ArkTS引擎实例。
    3. 因此在Stage模型中,应用组件之间可以方便的共享对象和状态,同时减少复杂应用运行对内存的占用。
    4. Stage模型作为主推的应用模型,开发者通过它能够更加便利地开发出分布式场景下的复杂应用。

2. 装饰器

1. 你使用过哪些装饰器,分别阐述一下他们得作用
  • @State装饰器,使得变量变为状态变量,影响UI(数据变化,UI变化)

  • @Prop装饰的变量和父组件建立单向的同步关系:

    • 父组件的@State数据变化,会同步到子组件@Prop

    • 具体用法

      //父组件:Parent
      @State num:number = 0
      build(){
          Son({num:this.num})
      }
      //子组件:Son
      @Prop num:number
    • @Prop修饰的变量,api9不能初始化,api11能初始化

  • @Link装饰的变量与其父组件中的数据源共享相同的值。

    • 父组件的@State数据变化,会同步到子组件@Link数据

    • 子组件@link数据变化,会同步到父组件@State数据

    • 具体用法

      //父组件:Parent
      @State num:number = 0
      build(){
          Son({num:$num})//api9必须使用$,api11开始也可以使用this了
      }
      //子组件:Son
      @Link num:number
    • @Link修饰的变量,api9不能初始化,api11不能初始化

2. 有用过@Styles,@Extend,@Builder装饰器么?
  • @Styles装饰器:定义组件重用样式 (多个组件通用的样式)

    @Styles装饰器,用于封装重复的通用样式代码。

    如果多个不同类型的组件,有着相同的样式,例如宽高,背景色,字体大小。那么就可以将这下相同的样式代码抽取到一个@Styles装饰器修饰的方法中,供大家复用。

    支持全局和局部定义:

    // 全局
    @Styles function functionName() { ... } //styles方法不能调用另一个styles方法***
    
    // 在组件内
    @Component
    struct FancyUse {
      @Styles fancy() {
        .height(100)
      }
    }
  • @Extend装饰器:定义扩展组件样式 (某一种组件自己的样式,私有属性)

    @Extend,用于扩展原生组件样式。

    如果同一类型的组件,有着很多相同的样式,例如按钮的类型,点击事件等。那么就可以将这些重复代码,抽过去到一个@Extend装饰器修饰的方法中,供此组件使用。

    ==仅支持全局定义==:(因为它相当于是给所有的此类组件使用)

    // @Extend(Text)可以支持Text的私有属性fontColor
    @Extend(Text) function fancy () {
      .fontColor(Color.Red)
    }
    // superFancyText可以调用预定义的fancy
    @Extend(Text) function superFancyText(size:number) { //Extend方法可以调用另一个Extend方法
        .fontSize(size)
        .fancy()
    }
  • @Builder装饰器:自定义构建函数

    @Builder装饰器,用于封装重复的,复杂UI结构代码,例如List中的ListItem的布局结构,一般比较复杂就可以抽取到@Builder装饰的函数中

    @Builder所装饰的函数遵循build()函数语法规则,开发者可以将重复使用的UI元素抽象成一个方法,在build方法里调用。

    支持全局定义和局部定义:

    //既然调用是通过this调用,那么说明是在组件内部定义
    //组件内部定义不需要关键字function
    @Builder MyBuilderFunction() { ... }
    
    //全局定义
    MyGlobalBuilderFunction()
  • @BuilderParam装饰器:引用@Builder函数

    当开发者创建了自定义组件,并想对该组件添加特定功能时,例如在自定义组件中添加一个点击跳转操作。若直接在组件内嵌入事件方法,将会导致所有引入该自定义组件的地方均增加了该功能。

    为解决此问题,ArkUI引入了@BuilderParam装饰器,该装饰器用于声明任意UI描述的一个元素,==类似slot占位符==。

    • 使得自定义组件更加灵活

    代码:

    @Component
    struct Child {
      @Builder customBuilder() {}
      // 使用父组件@Builder装饰的方法初始化子组件@BuilderParam
      @BuilderParam customBuilderParam: () => void = this.customBuilder;
    
      build() {
        Column() {
          this.customBuilderParam()
        }
      }
    }
    
    @Entry
    @Component
    struct Parent {
      @Builder componentBuilder() {
        Text(`Parent builder `)
      }
    
      build() {
        Column() {
          Child({ customBuilderParam: this.componentBuilder })
        }
      }
    }
3. 还用过其他装饰器么?
1. Provide和Consume
  1. @Provide和@Consume,用于祖先与后代组件的双向数据同步,实现跨层级传递

    • ==理解==:@Provide装饰器的变量是在祖先组件中,可以理解为被“提供”给后代的状态变量。@Consume装饰的变量是在后代组件中,去“消费”数据
  2. 语法特点:

    • @Provide和@Consume可以通过相同的变量名或者相同的变量别名绑定

      // 通过相同的变量名绑定
      @Provide a: number = 0; //祖先组件中定义
      @Consume a: number;  //子孙组件中定义
      
      // 通过相同的变量别名绑定
      @Provide('a') b: number = 0;//参数即为别名
      @Consume('a') c: number;
2. ObjectLink和Observed
  • @ObjectLink和@Observed类装饰器用于在涉及嵌套对象或数组的场景中进行双向数据同步:

    • 被@Observed装饰的类,可以被观察到属性的变化;
    • 子组件中@ObjectLink装饰器装饰的状态变量用于接收@Observed装饰的类的实例,和父组件中对应的状态变量建立双向数据绑定。这个实例可以是数组中的被@Observed装饰的项,或者是class object中的属性,这个属性同样也需要被@Observed装饰。
    • 单独使用@Observed是没有任何作用的,需要搭配@ObjectLink或者@Prop使用。
  • 详情参考: 3.状态管理.md --> 2.5章节

3. Watch

概述

  1. @Watch应用于==对状态变量的监听==。如果开发者需要关注某个状态变量的值是否改变,可以使用@Watch为状态变量设置回调函数。
  2. @Watch用于监听状态变量的变化,当状态变量变化时,@Watch的回调方法将被调用

代码:

@Component
struct TotalView {
  @Prop @Watch('onCountUpdated') count: number = 0;
  @State total: number = 0;
  // 该函数是自定义组件的成员函数
  // @Watch 回调
  // propName是被watch的属性名
  // 多个状态绑定同一个@Watch回调时,通过propName区分到底是哪个状态改变了
  onCountUpdated(propName: string): void {
    this.total += this.count;
  }

  build() {
    Text(`Total: ${this.total}`)
  }
}

@Entry
@Component
struct CountModifier {
  @State count: number = 0;

  build() {
    Column() {
      Button('add to basket')
        .onClick(() => {
          this.count++
        })
      TotalView({ count: this.count })
    }
  }
}

http://www.kler.cn/a/322869.html

相关文章:

  • Educational Codeforces Round 164 (Rated for Div. 2)(A~E)
  • 大模型论文精华-AI在医疗诊断、语言学习与情绪识别等领域的最新应用进展
  • <websocket><PLC>使用js和html实现webscoket,与PLC进行socket通讯的实例
  • Spring 4.3 源码导读
  • # ubuntu 安装的pycharm不能输入中文的解决方法
  • Vulhub漏洞复现---solr---CVE-2019-17558
  • MySQL知识点复习 - 常用的日志类型
  • 浅谈Java之多线程锁处理
  • kali linux crunch工具使用 -- 生成字典
  • 【常见框架漏洞】ThinkPHP、struts2、Spring、Shiro
  • 【数据结构】堆(Heap)详解
  • 前端框架的选择与考量:一场技术的盛宴
  • [Doc][ROS2]订阅发布、服务客户端区别
  • django drf 自动注册路由
  • Leetcode尊享面试100题-252.会议室
  • 产品推介——SOP4 随机相位可控硅光耦KLM305X
  • Docker Init 实战详解:从入门到精通
  • 前端练习总结(1)
  • 选择、冒泡、插入排序
  • 【Redis 源码】2项目结构说明
  • c语言中的杨氏矩阵的介绍以及元素查找的方法
  • Spring Boot 中实现任务后台处理的几种常见方式
  • 【笔记】自动驾驶预测与决策规划_Part4_时空联合规划
  • 数据结构及基本算法
  • LeetCode 2266. 统计打字方案数
  • UE4_Niagara基础实例—使用自定义模块二