关于Select下拉组件onSelect事件无法被触发分析

鸿蒙小绿娃 2023-03-13 18:58:11

1 关键字

OpenHarmony;Select;onSelect

2 问题描述

开发板型号:

芯片:

内核版本:

OH版本:OpenHarmony 3.1 Release

问题现象:OpenHarmony 3.1 Release系统上运行ets应用,在使用Select下拉组件时,点击下拉选项无法触发onSelect回调事件

测试步骤:

  1. 创建应用并编写好Select组件和onSelec事件代码。
  2. 运行应用
  3. 点击Select组件选择选项
  4. 期望执行onSelec回调,打印选择的值

3 问题原因

3.1 正常机制

  • OpenHarmony 3.1 Release下Select组件的onSelect方法会在下拉选择一项之后触发,回调方法的第一个参数为选择的值。

3.2 异常机制

  • OpenHarmony 3.1 Release下创建的ets应用在使用Select组件时,选择Select的下拉选项,onSelect回调方法未执行。

4 解决方案

通过下面的方式,可以解决此问题,在选择下拉选项的时候执行回调。基础代码如下,选择 "aaa"、"bbb"、"ccc" 时期望打印选择的inde和value值:

@Entry
@Component
struct Index {
  build() {
    Row() {
      Column() {
        Select([
          { value: "aaa" },
          { value: "bbb" },
          { value: "ccc" }
          ]).value('aaa')
          .onSelect((index, value)=>{
            console.log('onSelect index:' + index + ' value:' + value);
          })
      }
      .width('100%')
    }
    .height('100%')
  }
}

4.1 修改onSelect为onSelected

onSelected是API7中Select组件的选中后的事件,在API8中改为了onSelect,在这里需要使用onSelected来触发回调,修改后IDE会提示没有onSelected属性:

@Entry
@Component
struct Index {
  build() {
    Row() {
      Column() {
        Select([
          { value: "aaa" },
          { value: "bbb" },
          { value: "ccc" }
          ]).value('aaa')
          // 这里将原先的onSelect改为onSelected
          .onSelected((index, value)=>{
            console.log('onSelect index:' + index + ' value:' + value);
          })
      }
      .width('100%')
    }
    .height('100%')
  }
}

4.2 修改SDK文件解决IDE会提示没有onSelected

修改\ets\3.1.5.5\component\select.d.ts 文件,复制onSelect方法,然后改名为 onSelected,此操作可以解决IDE提示报错,但是编译不会通过:

// \ets\3.1.5.5\component\select.d.ts

...
/**
 * The commonMethod of select.
 * @since 8
 */
declare class SelectAttribute extends CommonMethod<SelectAttribute> {
  ...
  /**
   * Callback for selecting an item from the select.
   * @since 8
   */
  onSelect(callback: (index: number, value?: string) => void): SelectAttribute;
    
  // 这里将上面的  onSelect 复制后粘贴到下面 改为onSelected
  /**
   * Callback for selecting an item from the select.
   * @since 8
   */
  onSelected(callback: (index: number, value?: string) => void): SelectAttribute;
}
...

4.3 修改build-tools文件解决编译不通过问题

解决编译报错需要修改三个文件,分别如下:

  1. 修改 \ets\3.1.5.5\build-tools\ets-loader\components\select.json 文件
{
    "name": "Select",
    "attrs": [
        "selected",
        "value",
        "font",
        "fontColor",
        "selectedOptionBgColor",
        "selectedOptionFont",
        "selectedOptionFontColor",
        "optionBgColor",
        "optionFont",
        "optionFontColor",
        "onSelect",
        // 在这里添加 onSelected
        "onSelected"
    ]
}
  1. 修改 \ets\3.1.5.5\component\component_config.json 文件
{
    ...
    "Select": {
        "attrs": [
            "selected",
            "value",
            "font",
            "fontColor",
            "selectedOptionBgColor",
            "selectedOptionFont",
            "selectedOptionFontColor",
            "optionBgColor",
            "optionFont",
            "optionFontColor",
            "onSelect",
            // 在这里添加 onSelected
            "onSelected"
        ]
    },
    ...
}
  1. 修改\ets\3.1.5.5\build-tools\ets-loader\declarations\select.d.ts文件
...
/**
 * The commonMethod of select.
 * @since 8
 */
declare class SelectAttribute extends CommonMethod<SelectAttribute> {

  /**
   * Callback for selecting an item from the select.
   * @since 8
   */
  onSelect(callback: (index: number, value?: string) => void): SelectAttribute;
  // 这里将上面的  onSelect 复制后粘贴到下面 改为onSelected 
  /**
   * Callback for selecting an item from the select.
   * @since 8
   */
  onSelected(callback: (index: number, value?: string) => void): SelectAttribute;
}
...

按照以上步骤即可使用Select组件,并在其下拉选择选项时触发回调打印相关信息。

5 定位过程

在最开始时,发现onSelect的回调函数未执行,第一猜想是代码执行出错或者代码写法有误,在打包并在设备上运行之后得出,代码编写和sdk声明都没有问题,因此查看Select的组件源码,在\foundation\ace\ace_engine\frameworks\bridge\declarative_frontend\jsview\js_select.cpp和js_select.h中发现Select定义的方法与sdk声明文件中有所差异:

// \foundation\ace\ace_engine\frameworks\bridge\declarative_frontend\jsview\js_select.cpp
// 在源码中Select组件只定义了onSelected方法,未定义onSelect方法
...
void JSSelect::JSBind(BindingTarget globalObj)
{
    JSClass<JSSelect>::Declare("Select");
    MethodOptions opt = MethodOptions::NONE;
    JSClass<JSSelect>::StaticMethod("create", &JSSelect::Create, opt);

    JSClass<JSSelect>::StaticMethod("selected", &JSSelect::Selected, opt);
    JSClass<JSSelect>::StaticMethod("value", &JSSelect::Value, opt);
    JSClass<JSSelect>::StaticMethod("font", &JSSelect::Font, opt);
    JSClass<JSSelect>::StaticMethod("fontColor", &JSSelect::FontColor, opt);
    JSClass<JSSelect>::StaticMethod("selectedOptionBgColor", &JSSelect::SelectedOptionBgColor, opt);
    JSClass<JSSelect>::StaticMethod("selectedOptionFont", &JSSelect::SelectedOptionFont, opt);
    JSClass<JSSelect>::StaticMethod("selectedOptionFontColor", &JSSelect::SelectedOptionFontColor, opt);
    JSClass<JSSelect>::StaticMethod("optionBgColor", &JSSelect::OptionBgColor, opt);
    JSClass<JSSelect>::StaticMethod("optionFont", &JSSelect::OptionFont, opt);
    JSClass<JSSelect>::StaticMethod("optionFontColor", &JSSelect::OptionFontColor, opt);
    // 只有onSelected
    JSClass<JSSelect>::StaticMethod("onSelected", &JSSelect::OnSelected, opt);
    JSClass<JSSelect>::StaticMethod("width", &JSSelect::JsWidth);
    JSClass<JSSelect>::StaticMethod("height", &JSSelect::JsHeight);
    JSClass<JSSelect>::StaticMethod("size", &JSSelect::JsSize);
    JSClass<JSSelect>::StaticMethod("padding", &JSSelect::JsPadding);
    JSClass<JSSelect>::StaticMethod("paddingTop", &JSSelect::SetPaddingTop, opt);
    JSClass<JSSelect>::StaticMethod("paddingBottom", &JSSelect::SetPaddingBottom, opt);
    JSClass<JSSelect>::StaticMethod("paddingLeft", &JSSelect::SetPaddingLeft, opt);
    JSClass<JSSelect>::StaticMethod("paddingRight", &JSSelect::SetPaddingRight, opt);

    JSClass<JSSelect>::StaticMethod("onClick", &JSInteractableView::JsOnClick);
    JSClass<JSSelect>::StaticMethod("onTouch", &JSInteractableView::JsOnTouch);
    JSClass<JSSelect>::StaticMethod("onKeyEvent", &JSInteractableView::JsOnKey);
    JSClass<JSSelect>::StaticMethod("onDeleteEvent", &JSInteractableView::JsOnDelete);
    JSClass<JSSelect>::StaticMethod("onAppear", &JSInteractableView::JsOnAppear);
    JSClass<JSSelect>::StaticMethod("onDisAppear", &JSInteractableView::JsOnDisAppear);
    JSClass<JSSelect>::Inherit<JSViewAbstract>();
    JSClass<JSSelect>::Bind(globalObj);
}
...
// \foundation\ace\ace_engine\frameworks\bridge\declarative_frontend\jsview\js_select.h
// js_select.h中同样只定义了onSelected方法,未定义onSelect方法
#ifndef FRAMEWORKS_BRIDGE_DECLARATIVE_FRONTEND_JS_VIEW_JS_SELECT_H
#define FRAMEWORKS_BRIDGE_DECLARATIVE_FRONTEND_JS_VIEW_JS_SELECT_H

#include "frameworks/bridge/declarative_frontend/jsview/js_view_abstract.h"

namespace OHOS::Ace::Framework {
class JSSelect : public JSViewAbstract {
public:
    static void Create(const JSCallbackInfo& info);
    static void JSBind(BindingTarget globalObj);

    static void Selected(int value);
    static void Value(const std::string& value);
    static void Font(const JSCallbackInfo& info);
    static void FontColor(const JSCallbackInfo& info);
    static void SelectedOptionBgColor(const JSCallbackInfo& info);
    static void SelectedOptionFont(const JSCallbackInfo& info);
    static void SelectedOptionFontColor(const JSCallbackInfo& info);
    static void OptionBgColor(const JSCallbackInfo& info);
    static void OptionFont(const JSCallbackInfo& info);
    static void OptionFontColor(const JSCallbackInfo& info);
    // 只有 OnSelected
    static void OnSelected(const JSCallbackInfo& info);
    static void JsWidth(const JSCallbackInfo& info);
    static void JsHeight(const JSCallbackInfo& info);
    static void Width(const JSRef<JSVal>& jsValue);
    static void Height(const JSRef<JSVal>& jsValue);
    static void JsSize(const JSCallbackInfo& info);
    static void JsPadding(const JSCallbackInfo& info);
    static void SetPaddingTop(const JSCallbackInfo& info);
    static void SetPaddingBottom(const JSCallbackInfo& info);
    static void SetPaddingLeft(const JSCallbackInfo& info);
    static void SetPaddingRight(const JSCallbackInfo& info);
};
} // namespace OHOS::Ace::Framework
#endif 

由此判断出Select组件上并未有onSelect方法,因此回调函数不会执行。但是存在OnSelected方法,因此可以尝试使用OnSelected代替。

同样可以在js_select.cpp和js_select.h中将onSelected相关代码复制一份并改为onSelect也可以解决此问题。

6 知识分享

  • OpenHarmony的代码在持续更新,版本迭代的时候相关代码与sdk声明文件存在些许不匹配,在使用时需要多方面考虑分析问题,SDK和API是能第一手查到的资料。
  • 没有底层C语言基础也能看一些底层的基础代码和方法,大多数语言都有一些共通点。
...全文
4 回复 打赏 收藏 转发到动态 举报
写回复
用AI写文章
回复
切换为时间正序
请发表友善的回复…
发表回复

421

社区成员

发帖
与我相关
我的任务
社区描述
OpenHarmony开发者社区
其他 企业社区
社区管理员
  • csdnsqst0025
  • shewaliujingli
  • BaoWei
加入社区
  • 近7日
  • 近30日
  • 至今

试试用AI创作助手写篇文章吧