HarmonyOS鸿蒙Next中对于大量的设置选项怎么简化代码

HarmonyOS鸿蒙Next中对于大量的设置选项怎么简化代码 最近在写一个用于在鸿蒙系统上调试webview的软件,其中有一个设置界面,用于设置webview的行为

设置列表来源于属性-Web-ArkTS 组件-ArkWeb(方舟Web)-应用框架 - 华为HarmonyOS开发者

问题在于,我定义了一个响应式的对象Options,作为一个组件的属性(使用ComponentV2)

@Param @Require options: KWebOptions

现在的代码能够正常运行,但是过于繁琐,比如KWebOptions的定义:

@ObservedV2
export class KWebOptions {

  @Trace javaScriptAccess: boolean;
  // ... 44行
  @Trace gestureFocusMode: GestureFocusMode;

  constructor(options: Optional<KWebValue> = defaultInitValue) { // defaultInitValue用于存储默认值列表

    this.javaScriptAccess = options.javaScriptAccess ?? defaultInitValue.javaScriptAccess
    // ... 44行
    this.gestureFocusMode = options.gestureFocusMode ?? defaultInitValue.gestureFocusMode

  }

  toRaw(){ // 为了JSON序列化保存配置
    return {

      javaScriptAccess: this.javaScriptAccess,
      // ... 44行
      gestureFocusMode: this.gestureFocusMode

    }
  }
}

我反复书写了总计44个属性3次。。。因为响应式对象似乎不能动态读取属性,不然我就一个for循环写完了

再比如,设置页面,一行设置的代码如下

ListItem() {
  ItemToggle({
    title: $r("app.string.web_options_java_script_access"),
    value: this.options.javaScriptAccess,
    onChange: (value: boolean) => this.options.javaScriptAccess = value
  })
}.attributeModifier(this.itemStyle)

每一个设置我需要单独配置value和onChange两次,而且必须静态访问属性,意味着这个代码需要复制粘贴43次(虽然实际上我就是这么干的)

虽然但是,我觉得这玩意太折腾了,有没有能够优化的手段


更多关于HarmonyOS鸿蒙Next中对于大量的设置选项怎么简化代码的实战教程也可以访问 https://www.itying.com/category-93-b0.html

8 回复

对于ItemToggle 可以配置一个对象属性参数,在这个对象里进行其他参数配置和方法实现。这里使用v1演示:

@Observed
class ToggleParams {
  @Track title: string = ''
  @Track value: boolean = false
  onChange?: (v: boolean) => void
}

@Component
struct ItemToggle {
  @ObjectLink params: ToggleParams

  build() {
    Text(this.params.title)
  }
}

@Component
struct SettingsPage {
  @State SETTING_CONFIGS: ToggleParams[] = []

  aboutToAppear(): void {
    const config: ToggleParams[] = []
    for (let index = 0; index < 5; index++) {
      const element = config[index];
      //for循环创建
    }

    this.SETTING_CONFIGS = config
  }

  build() {
    Column() {
      List() {
        ForEach(this.SETTING_CONFIGS, (item: ToggleParams) => {
          ListItem() {
            ItemToggle({
              params: item
            })
          }.attributeModifier(this.itemStyle)
        })
      }
    }
  }
}

对于KWebOptions,可以使用一些model转类对象工具,比如class-transformer

ohpm i class-transformer

更多关于HarmonyOS鸿蒙Next中对于大量的设置选项怎么简化代码的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


一个很大的问题是这里的options是外面传进来的,外面有全局的状态保持和持久化,也是绑定到具体的Web组件对象上的,这里如果要手动定义SETTINGS数组,本质上还是需要把所有属性挨着展开写一遍没法用for循环,因为不支持动态属性

定义属性是必要的,方便类的内存布局。使用class-transformer可以不必再写 constructor(options: Optional<KWebValue> = defaultInitValue)toRaw()。这样只写一遍属性定义。

const webOptionsInstance = plainToInstance(KWebOptions, options)

const rawObj = instanceToPlain(webOptionsInstance)

好哦,我试试

const SETTING_CONFIGS = [
  { key: 'javaScriptAccess', resId: 'app.string.web_options_java_script_access' },
  { key: 'gestureFocusMode', resId: 'app.string.web_options_gesture_focus' },
  // ...其他配置项
];

@ComponentV2
struct SettingsPage {
  @Param options: KWebOptions

  build() {
    Column() {
      List() {
        ForEach(SETTING_CONFIGS, item => {
          ListItem() {
            ItemToggle({
              title: $r(item.resId),
              value: this.options[item.key],
              onChange: (v: boolean) => this.options[item.key] = v
            })
          }.attributeModifier(this.itemStyle)
        })
      }
    }
  }
}

不支持动态属性 this.options[item.key]报错 Indexed access is not supported for fields (arkts-no-props-by-index) <ArkTSCheck>,

鸿蒙Next中简化设置选项代码可使用@Builder装饰器封装UI组件,通过@State管理状态。利用ForEach循环渲染选项列表,结合@Link实现数据双向绑定。推荐使用Settings模块的预置组件(如ToggleSlider)减少自定义控件代码。通过Preferences统一管理持久化数据,避免分散存储逻辑。

在HarmonyOS Next中处理大量设置选项时,可以通过以下方式简化代码:

1. 使用装饰器工厂和反射(需谨慎) 虽然ArkTS不支持运行时反射,但可以通过装饰器工厂模式减少重复。为@Trace装饰器创建工厂,自动生成属性的getter/setter,但需注意性能影响。

2. 配置化驱动UI生成 将属性配置抽取为数组,动态生成UI:

const optionConfigs = [
  { key: 'javaScriptAccess', title: $r("app.string.web_options_java_script_access"), type: 'boolean' },
  // ... 其他配置
];

@Builder
function buildSettings(options: KWebOptions) {
  ForEach(optionConfigs, (config) => {
    ListItem() {
      ItemToggle({
        title: config.title,
        value: options[config.key],
        onChange: (value) => options[config.key] = value
      })
    }
  })
}

3. 使用Proxy简化对象操作 通过Proxy代理实现属性的动态访问和序列化:

class KWebOptions {
  private _data: Record<string, any> = {};

  constructor(defaults: KWebValue) {
    return new Proxy(this, {
      get(target, prop) {
        return target._data[prop] ?? defaults[prop];
      },
      set(target, prop, value) {
        target._data[prop] = value;
        return true;
      }
    });
  }

  toRaw() {
    return { ...this._data };
  }
}

4. 属性映射表 创建属性描述符映射表,统一管理初始化和序列化:

const propertyDescriptors = {
  javaScriptAccess: { default: true, type: Boolean },
  // ... 其他属性
};

class KWebOptions {
  constructor(options?: Partial<KWebValue>) {
    Object.entries(propertyDescriptors).forEach(([key, desc]) => {
      Object.defineProperty(this, key, {
        get() { /* ... */ },
        set(value) { /* ... */ },
        enumerable: true
      });
    });
  }
}

5. 代码生成工具 对于44个属性这种情况,可以考虑使用简单的代码生成脚本(如Node.js脚本),根据属性列表自动生成类定义、构造函数和序列化方法。

推荐方案:采用配置化驱动UI生成结合Proxy模式,既能减少UI代码重复,又能简化对象操作。但需要注意Proxy在性能敏感场景下的使用,以及确保类型安全。

回到顶部