鸿蒙 HarmonyOS 6 | Pura X Max 鸿蒙原生适配 15:编辑表单在展开态限制最大宽度 原创
头像 小雨同学 2026-05-29 09:30:08    发布
1 浏览 0 点赞 0 收藏


前言

我在处理材料编辑页的时候,会注意到页面表单会不会被拉得太长。外屏状态下,一列表单从上到下排,标题、分类、提醒时间、处理备注、保存按钮都在同一条阅读路径里,用户填写完一个字段以后继续往下走,整个页面没有太多干扰。到了 Pura X Max 展开态以后,同样的表单如果继续铺满整个窗口,输入框会被拉成很长一条,短文本字段尤其空,页面看起来有空间,实际填写时反而不够集中。

这个问题在表单页里比列表页更明显。列表页变宽以后,可以考虑增加列数、增加字段或者做列表详情联动;表单页的目标不一样,它更在意填写路径和字段边界。输入框变宽以后,用户的视线会被拉得很散,短文本字段也会显得很空。保存按钮如果继续跟着表单铺满,页面底部也会变得有点松,用户很难判断真正的编辑区域从哪里开始、在哪里结束。

这类问题通常会出现在下面几种页面里:

  • 材料编辑页
  • 备注编辑页
  • 提醒规则设置页
  • 用户资料编辑页
  • 订单或客户信息编辑页
  • 轻量 CMS 内容维护页

我的处理方式是控制主表单宽度,多出来的空间交给辅助说明,比如来源信息、识别摘要、填写规则和当前状态。

这个页面我会拆成两种状态。外屏或宽度不足时,保持单列表单;展开态空间够用时,左侧显示受控宽度的主表单,右侧显示辅助说明卡片。这里最容易踩的坑,是只写一个宽度阈值就强行分栏。真正落到页面上,还要把左右 padding、中间间距、表单宽度和说明卡片宽度一起算进去。

一、表单被拉长以后哪里不对

1.1 外屏单列没有问题

编辑页在外屏里用单列结构很常见。标题在上方,下面依次是分类、提醒时间、备注和保存按钮。用户拿着设备时,从上往下填,字段之间的关系也比较清楚。这个场景里,输入框占满卡片宽度没有什么问题,因为窗口本来就窄,输入区域不会被拉得太离谱。

最开始的写法也很简单。

Column() {  TextInput()  TextInput()  TextArea()  Button()}.width('100%')

这个结构在外屏没有问题。所有字段都跟随父容器宽度,开发时也不需要单独考虑左右区域。很多表单页最早都是这么写出来的,尤其是材料编辑、备注编辑、简单设置这类页面。

但是问题出现在展开态。窗口突然变宽以后,width('100%') 会把所有输入框都撑开。标题字段可能只有十几个字,输入框却占了一整行;分类字段可能只填两个字,输入区域也被拉得很长。页面看起来没有溢出,但填写节奏已经变散了。

1.2 展开态不能把空间都给输入框

我把编辑页放到展开态里看时,最明显的感觉是输入区域太宽。用户真正要填写的内容并不复杂,标题、分类、提醒时间都是短字段,备注也只是一段说明。把这些字段拉到接近整屏宽度,反而让表单看起来像一张空白很大的卡片。

表单页和卡片列表不一样。卡片列表可以通过多列展示更多记录,表单页更看重字段之间的连续性。用户填写时会反复确认字段名称和输入内容,如果输入框被拉得很长,字段标签在左边,输入内容在很宽的区域里展开,视线会被拖开。

我更倾向于把主表单控制在一个稳定宽度里。这个宽度不需要特别窄,但也不能跟着屏幕无限拉宽。多出来的横向空间可以用来放辅助说明,比如识别摘要、来源信息、当前状态、填写建议。这样展开态空间没有浪费,主表单也能保持比较稳定的填写路径。

二、分栏前先算可用宽度

2.1 不能只写一个展开态阈值

这个页面最容易写成一个简单判断:窗口超过某个宽度,就进入左右分栏。比如写一个 wideThreshold = 860,然后把表单放左边,说明卡片放右边。这个思路看起来直接,但实际跑起来容易在中间尺寸出问题。

左右分栏真正占用的宽度,不只是表单和说明卡片本身。页面左右 padding、中间间距、卡片阴影、滚动容器的可用宽度都会参与进来。如果只看窗口宽度,某些尺寸下页面会进入分栏,但两个卡片加起来已经接近或超过可用区域,最后就会出现横向挤压或溢出。

我这次把宽度拆开算。主表单给 540vp,右侧辅助说明给 260vp,中间间距给 14vp。页面左右 padding 在展开态下是 24vp。也就是说,窗口宽度必须先扣掉外层 padding,再去判断左右两块区域能不能同时放下。

private readonly wideThreshold: number = 860;private readonly formPanelWidth: number = 540;private readonly helperPanelWidth: number = 260;private readonly twoColumnGap: number = 14;

这些值都不是固定模板。表单字段比较短,540vp 足够;如果页面里有长 URL、配置项、代码路径,表单可以加宽到 600vp 左右。右侧说明卡片如果只是展示状态和摘要,260vp 已经能承载;如果要放更复杂的说明,就要重新计算是否还能稳定分栏。

2.2 可用宽度要把 padding 算进去

真正决定是否进入左右分栏的函数是 canUseTwoColumn()

private canUseTwoColumn(): boolean {  const availableWidth = this.getEffectiveWidth() - this.getPagePadding() * 2;  const requiredWidth = this.formPanelWidth + this.helperPanelWidth + this.twoColumnGap;  return availableWidth >= requiredWidth;}

这个函数里有两个量。availableWidth 是页面扣掉左右 padding 后能用的宽度,requiredWidth 是表单、说明卡片和间距加起来的宽度。只有前者大于等于后者,页面才进入左右分栏。

这比单纯判断 getEffectiveWidth() >= wideThreshold 更贴近真实布局。因为页面不是直接从屏幕边缘开始排内容,中间还有外层 padding。很多横向溢出的问题,恰恰出在开发时忘了把这些边距算进去。

我会把这个判断放在页面层,而不是让 FormPanel()HelperPanel() 自己决定宽度。表单组件只负责显示字段,说明组件只负责显示辅助内容,是否左右排由外层统一决定。这样以后要改断点、改左右宽度,修改点会更集中。

三、控制表单宽度,说明放右侧

3.1 主表单只负责填写路径

表单进入左右分栏后,左侧仍然是主要区域。用户真正要完成的动作,是确认标题、分类、提醒时间和备注,然后保存编辑结果。这个区域不需要被拉到整屏宽,只要保持稳定、可读、可填写就够了。

示例里,左侧表单外层固定为 formPanelWidth

Column() {  this.FormPanel()}.width(this.formPanelWidth)

FormPanel() 内部的输入框仍然使用 width('100%'),由父容器控制实际宽度。这样写比在每个输入框上写固定宽度更容易维护。以后如果要调整表单整体宽度,只改外层宽度就可以,不用挨个改输入框。

表单内部包括标题、分类、提醒时间、备注和保存按钮。每个字段仍然按上下顺序排列,不因为进入展开态就横向拆字段。我的经验是,简单编辑页不一定要把字段拆成多列。字段少的时候,单列表单更容易保持填写顺序,右侧空间交给辅助说明会更合适。

3.2 辅助说明只在空间够时出现

右侧说明卡片承接的是辅助信息,不参与主要填写路径。它可以展示来源、状态、建议动作、识别可信度,也可以放一段识别摘要。用户需要的时候可以看,不需要的时候也不会影响左侧表单的填写。

示例里的右侧卡片宽度是 helperPanelWidth

Column() {  this.HelperPanel()}.width(this.helperPanelWidth)

右侧说明不要做得太复杂。它适合展示当前表单的上下文,比如这条材料来自哪里、识别出来了什么、建议保存成什么任务。如果把复杂编辑、更多表单字段或者长文本都塞到右侧,右侧就会变成另一个表单,左侧主表单和右侧说明之间的关系会变乱。

四、实际运行效果

这里我提供了外屏和展开态两个演示按钮,方便在同一台模拟器里观察表单布局变化。实际项目里可以删掉这些按钮,页面直接使用真实窗口宽度判断是否分栏。

外屏状态下,页面保持单列表单。所有字段从上到下排列,保存按钮仍然在表单内部。宽度不足时不强行分栏,可以避免表单和说明卡片互相挤压。

展开态状态下,页面进入左右结构。左侧表单宽度为 540vp,右侧说明卡片宽度为 260vp,中间间距为 14vp。外层 padding 已经被纳入宽度判断,页面不会因为固定宽度叠加而横向溢出。

五、实际项目中怎么用

5.1 演示宽度要删掉

示例里的 previewWidth 只是为了在同一个模拟器里观察外屏和展开态。真实项目里不需要这些演示按钮,页面应该直接使用真实窗口宽度。

private getEffectiveWidth(): number {  if (this.previewWidth > 0) {    return this.previewWidth;  }​  return this.pageWidth;}

实际项目时,可以直接返回 pageWidth

private getEffectiveWidth(): number {  return this.pageWidth;}

页面宽度可以继续通过 onAreaChange 写入。这里记录的是页面根容器宽度,而不是设备型号。对 Pura X Max 来说,同一台设备可能处在外屏、展开态、分屏和自由窗口里,能不能分栏要看当前窗口实际能给多少空间。

5.2 表单宽度不要全局写死

示例里用了 formPanelWidth = 540,这是为了演示材料编辑页。真实项目里,表单宽度最好根据页面类型整理成配置。不同表单字段长度不同,适合的最大宽度也不一样。

比如:

  • 资料编辑、提醒编辑这类短字段表单,可以控制在 520vp 到 560vp。
  • 配置页、地址页、URL 输入页,可以适当放宽到 600vp 左右。
  • 多字段复杂表单,如果字段之间有明显分组,可以考虑分段,而不是单纯加宽。
  • 长文本编辑页不要套用短表单宽度,要单独设计阅读和编辑区域。

这个边界要提前想清楚。表单最大宽度不是一个全局万能值,它跟字段类型、输入内容长度、是否有右侧辅助说明都有关系。

5.3 右侧说明要服务表单

右侧说明卡片出现以后,不要随手把所有补充信息都塞进去。它应该帮助用户填写左侧表单,比如解释来源、展示识别摘要、提示建议动作。如果右侧卡片里放太多不相关内容,用户填写表单时反而会被干扰。

我会把右侧说明控制在几类内容里:

  • 来源和状态
  • 识别摘要
  • 填写规则
  • 建议动作
  • 当前记录的轻量提醒

完整历史、附件、长说明、复杂校验结果,应该进入详情页或单独模块。右侧卡片只是辅助,不应该把主表单变成左右两边都要填写的复杂页面。

总结

Pura X Max 展开态里,表单页不能急着铺满整屏。外屏下单列表单更适合连续填写,字段从上到下排,用户不需要在左右区域之间来回找内容;展开态空间变宽以后,主表单反而要收住宽度,右侧再放识别摘要、来源状态和填写规则。这样处理以后,表单仍然是表单,右侧区域只是辅助,不会把编辑页变成一个横向拉长的输入区。

我后面处理这类编辑页时,需要注意:

  • 主表单要有最大宽度,短字段不能跟着展开态无限拉长。
  • 辅助说明只在空间足够时出现,不能和表单互相挤压。
  • 分栏前要扣掉外层 padding、中间间距和两张卡片的固定宽度。
  • 宽度不足时继续保持单列,不为了展开态强行左右分栏。
  • 右侧说明只放来源、状态、识别摘要、填写规则这类辅助内容,不承接复杂编辑。

如果放到实际项目里,我会把表单宽度、说明卡片宽度和中间间距抽成配置,再按页面类型单独调整。短字段表单可以收得更窄,配置类表单可以适当放宽,长文本编辑页则要单独处理。展开态多出来的横向空间不一定都要给输入框,能帮助用户填写的内容才适合放到右侧。

附:完整代码

interface HelperItem {  id: number;  label: string;  value: string;}​@Entry@Componentstruct Index {  // 页面真实宽度,由 onAreaChange 写入  @State private pageWidth: number = 0;​  // 演示宽度,只用于在同一个模拟器里观察外屏和展开态  @State private previewWidth: number = 0;​  // 表单字段模拟真实编辑状态  @State private materialTitle: string = '社区物业缴费提醒';  @State private category: string = '通知';  @State private remindTime: string = '2026-05-28 09:00';  @State private noteText: string = '缴费前一天提醒,并确认是否已经完成支付。';​  // 模拟保存次数,用来观察操作状态是否正常保留  @State private saveCount: number = 0;​  private readonly wideThreshold: number = 860;  private readonly formPanelWidth: number = 540;  private readonly helperPanelWidth: number = 280;  private readonly twoColumnGap: number = 16;​  private readonly helperItems: HelperItem[] = [    {      id: 1,      label: '来源',      value: '拍照整理'    },    {      id: 2,      label: '状态',      value: '待处理'    },    {      id: 3,      label: '建议动作',      value: '保存为待办提醒'    },    {      id: 4,      label: '识别可信度',      value: '较高'    }  ];​  // Demo 中优先使用演示宽度,真实项目里可以直接返回 pageWidth  private getEffectiveWidth(): number {    if (this.previewWidth > 0) {      return this.previewWidth;    }​    return this.pageWidth;  }​  private getPagePadding(): number {    if (this.getEffectiveWidth() >= this.wideThreshold) {      return 24;    }​    return 16;  }​  // 分栏前先扣掉外层 padding,再判断表单、说明卡片和间距是否真的放得下  private canUseTwoColumn(): boolean {    const width = this.getEffectiveWidth();    const availableWidth = width - this.getPagePadding() * 2;    const requiredWidth = this.formPanelWidth + this.helperPanelWidth + this.twoColumnGap;​    return width >= this.wideThreshold && availableWidth >= requiredWidth;  }​  private isExpanded(): boolean {    return this.canUseTwoColumn();  }​  private getContentWidth(): Length {    if (this.previewWidth > 0) {      return this.previewWidth;    }​    return '100%';  }​  private getTitleSize(): number {    return this.isExpanded() ? 28 : 23;  }​  private getModeText(): string {    return this.isExpanded() ? 'expanded · 表单 + 说明分栏' : 'compact · 单列表单';  }​  private getModeDesc(): string {    if (this.isExpanded()) {      return '可用宽度足够时,主表单保持受控宽度,右侧显示辅助说明。';    }​    return '可用宽度不足时,表单保持单列,避免左右区域互相挤压。';  }​  private setPreview(width: number) {    this.previewWidth = width;  }​  private save() {    this.saveCount += 1;  }​  @Builder  private PreviewButton(text: string, width: number) {    Text(text)      .fontSize(12)      .fontColor(this.previewWidth === width ? '#FFFFFF' : '#2F8F83')      .textAlign(TextAlign.Center)      .padding({ left: 10, right: 10, top: 7, bottom: 7 })      .backgroundColor(this.previewWidth === width ? '#2F8F83' : '#E6F4F1')      .borderRadius(999)      .onClick(() => {        this.setPreview(width);      })  }​  @Builder  private StatusPill(text: string) {    Text(text)      .fontSize(12)      .fontColor('#B25E00')      .padding({ left: 8, right: 8, top: 4, bottom: 4 })      .backgroundColor('#FFF4E5')      .borderRadius(999)  }​  @Builder  private DividerLine() {    Divider()      .strokeWidth(0.5)      .color('#E5E7EB')      .margin({ left: 92 })  }​  @Builder  private HeaderPanel() {    Column({ space: 10 }) {      Row({ space: 10 }) {        Column({ space: 4 }) {          Text('编辑表单在展开态限制最大宽度')            .fontSize(this.getTitleSize())            .fontWeight(FontWeight.Bold)            .fontColor('#111827')            .maxLines(1)            .textOverflow({ overflow: TextOverflow.Ellipsis })​          Text(this.getModeText())            .fontSize(14)            .fontColor('#2F8F83')            .maxLines(1)            .textOverflow({ overflow: TextOverflow.Ellipsis })        }        .layoutWeight(1)​        Text('窗口 ' + Math.round(this.pageWidth).toString() + 'vp')          .fontSize(12)          .fontColor('#374151')          .padding({ left: 10, right: 10, top: 6, bottom: 6 })          .backgroundColor('#FFFFFF')          .borderRadius(999)      }      .width('100%')​      Text('演示宽度:' + Math.round(this.getEffectiveWidth()).toString() + 'vp。' + this.getModeDesc())        .fontSize(14)        .fontColor('#6B7280')        .lineHeight(21)        .maxLines(2)        .textOverflow({ overflow: TextOverflow.Ellipsis })​      Row({ space: 8 }) {        this.PreviewButton('自动', 0)        this.PreviewButton('外屏', 430)        this.PreviewButton('展开态', 1040)      }      .width('100%')    }    .width('100%')  }​  @Builder  private FormGroup() {    Column() {      Row({ space: 12 }) {        Text('材料标题')          .fontSize(15)          .fontColor('#374151')          .width(80)          .flexShrink(0)​        TextInput({          text: this.materialTitle,          placeholder: '请输入材料标题'        })          .height(48)          .layoutWeight(1)          .fontSize(15)          .fontColor('#111827')          .placeholderColor('#9CA3AF')          .backgroundColor('#00000000')          .padding({ left: 0, right: 0 })          .onChange((value: string) => {            this.materialTitle = value;          })      }      .width('100%')      .height(56)      .alignItems(VerticalAlign.Center)​      this.DividerLine()​      Row({ space: 12 }) {        Text('分类')          .fontSize(15)          .fontColor('#374151')          .width(80)          .flexShrink(0)​        TextInput({          text: this.category,          placeholder: '请输入分类'        })          .height(48)          .layoutWeight(1)          .fontSize(15)          .fontColor('#111827')          .placeholderColor('#9CA3AF')          .backgroundColor('#00000000')          .padding({ left: 0, right: 0 })          .onChange((value: string) => {            this.category = value;          })      }      .width('100%')      .height(56)      .alignItems(VerticalAlign.Center)​      this.DividerLine()​      Row({ space: 12 }) {        Text('提醒时间')          .fontSize(15)          .fontColor('#374151')          .width(80)          .flexShrink(0)​        TextInput({          text: this.remindTime,          placeholder: '请输入提醒时间'        })          .height(48)          .layoutWeight(1)          .fontSize(15)          .fontColor('#111827')          .placeholderColor('#9CA3AF')          .backgroundColor('#00000000')          .padding({ left: 0, right: 0 })          .onChange((value: string) => {            this.remindTime = value;          })      }      .width('100%')      .height(56)      .alignItems(VerticalAlign.Center)    }    .width('100%')    .padding({ left: 14, right: 14 })    .backgroundColor('#F7F8FA')    .borderRadius(18)  }​  @Builder  private NoteGroup() {    Column({ space: 10 }) {      Text('处理备注')        .fontSize(15)        .fontColor('#374151')​      TextArea({        text: this.noteText,        placeholder: '请输入处理备注'      })        .height(this.isExpanded() ? 124 : 104)        .fontSize(15)        .fontColor('#111827')        .placeholderColor('#9CA3AF')        .backgroundColor('#00000000')        .padding({ left: 0, right: 0, top: 0, bottom: 0 })        .onChange((value: string) => {          this.noteText = value;        })    }    .width('100%')    .padding(14)    .backgroundColor('#F7F8FA')    .borderRadius(18)  }​  @Builder  private FormPanel() {    Column({ space: 18 }) {      Row() {        Column({ space: 4 }) {          Text('材料编辑')            .fontSize(20)            .fontWeight(FontWeight.Bold)            .fontColor('#111827')            .maxLines(1)            .textOverflow({ overflow: TextOverflow.Ellipsis })​          Text('按识别结果补全提醒信息')            .fontSize(13)            .fontColor('#6B7280')            .maxLines(1)            .textOverflow({ overflow: TextOverflow.Ellipsis })        }        .layoutWeight(1)​        this.StatusPill('待处理')      }      .width('100%')​      this.FormGroup()​      this.NoteGroup()​      if (!this.isExpanded()) {        Text('单列状态下,字段从上到下填写。宽度不足时不强行分栏,避免表单和说明卡片互相挤压。')          .fontSize(13)          .fontColor('#6B7280')          .lineHeight(20)          .maxLines(2)          .textOverflow({ overflow: TextOverflow.Ellipsis })      }​      Button('保存编辑结果')        .height(46)        .fontSize(15)        .fontColor('#FFFFFF')        .width('100%')        .backgroundColor('#2F8F83')        .borderRadius(23)        .onClick(() => {          this.save();        })​      Text('已保存 ' + this.saveCount.toString() + ' 次')        .fontSize(13)        .fontColor('#6B7280')        .width('100%')        .textAlign(TextAlign.Center)    }    .width('100%')    .padding(this.isExpanded() ? 20 : 16)    .backgroundColor('#FFFFFF')    .borderRadius(26)    .shadow({      radius: 12,      color: '#12000000',      offsetX: 0,      offsetY: 4    })  }​  @Builder  private HelperRow(item: HelperItem) {    Column({ space: 5 }) {      Text(item.label)        .fontSize(12)        .fontColor('#9CA3AF')        .maxLines(1)        .textOverflow({ overflow: TextOverflow.Ellipsis })​      Text(item.value)        .fontSize(14)        .fontColor('#374151')        .lineHeight(20)        .maxLines(2)        .textOverflow({ overflow: TextOverflow.Ellipsis })    }    .width('100%')    .padding(12)    .backgroundColor('#F7F8FA')    .borderRadius(16)  }​  @Builder  private HelperPanel() {    Column({ space: 14 }) {      Row() {        Column({ space: 4 }) {          Text('辅助说明')            .fontSize(20)            .fontWeight(FontWeight.Bold)            .fontColor('#111827')            .maxLines(1)            .textOverflow({ overflow: TextOverflow.Ellipsis })​          Text('识别内容和填写建议')            .fontSize(13)            .fontColor('#6B7280')            .maxLines(1)            .textOverflow({ overflow: TextOverflow.Ellipsis })        }        .layoutWeight(1)      }      .width('100%')​      Text('展开态下,右侧只放辅助信息。主表单保持稳定宽度,填写动作仍然集中在左侧。')        .fontSize(14)        .fontColor('#4B5563')        .lineHeight(22)        .maxLines(4)        .textOverflow({ overflow: TextOverflow.Ellipsis })​      Column({ space: 10 }) {        ForEach(this.helperItems, (item: HelperItem) => {          this.HelperRow(item)        }, (item: HelperItem) => item.id.toString())      }      .width('100%')​      Column({ space: 8 }) {        Text('识别摘要')          .fontSize(16)          .fontWeight(FontWeight.Medium)          .fontColor('#111827')          .maxLines(1)          .textOverflow({ overflow: TextOverflow.Ellipsis })​        Text('识别到物业费缴纳截止日期、金额明细和办理地点。建议保存为待办提醒,并在截止日前一天通知。')          .fontSize(14)          .fontColor('#6B7280')          .lineHeight(22)          .maxLines(5)          .textOverflow({ overflow: TextOverflow.Ellipsis })      }      .width('100%')      .padding(14)      .backgroundColor('#F3F8F7')      .borderRadius(18)    }    .width('100%')    .padding(16)    .backgroundColor('#FFFFFF')    .borderRadius(26)    .shadow({      radius: 12,      color: '#10000000',      offsetX: 0,      offsetY: 4    })  }​  @Builder  private MainContent() {    Scroll() {      if (this.isExpanded()) {        Row({ space: this.twoColumnGap }) {          Column() {            this.FormPanel()          }          .width(this.formPanelWidth)          .flexShrink(0)​          Column() {            this.HelperPanel()          }          .width(this.helperPanelWidth)          .flexShrink(0)        }        .width('100%')        .alignItems(VerticalAlign.Top)        .justifyContent(FlexAlign.Center)        .padding({ bottom: 24 })      } else {        Column() {          this.FormPanel()        }        .width('100%')        .padding({ bottom: 24 })      }    }    .layoutWeight(1)    .width('100%')    .edgeEffect(EdgeEffect.Spring)  }​  build() {    Column() {      Column({ space: 16 }) {        this.HeaderPanel()        this.MainContent()      }      .width(this.getContentWidth())      .height('100%')      .padding({        left: this.getPagePadding(),        right: this.getPagePadding(),        top: 18,        bottom: 16      })    }    .width('100%')    .height('100%')    .alignItems(HorizontalAlign.Center)    .backgroundColor('#F6F7F9')    .onAreaChange((_: Area, newValue: Area) => {      const width = Number(newValue.width);      if (!Number.isNaN(width) && width > 0) {        this.pageWidth = width;      }    })  }}


©本站发布的所有内容,包括但不限于文字、图片、音频、视频、图表、标志、标识、广告、商标、商号、域名、软件、程序等,除特别标明外,均来源于网络或用户投稿,版权归原作者或原出处所有。我们致力于保护原作者版权,若涉及版权问题,请及时联系我们进行处理。
分类
HarmonyOS

暂无评论数据

加载中...

发布

头像

小雨同学

产品总监、独立开发者社群主理人、资深全栈工程师,HarmonyOS应用开发者高级认证,PMP认证,CSDN博客专家,鸿蒙极客,Trae Fellow,阿里云社区专家博主、51CTO 博客专家、OpenTiny 优秀布道师、科大讯飞荣誉讲师。

15

帖子

0

提问

26

粉丝

关注
热门推荐
地址:北京市朝阳区北三环东路三元桥曙光西里甲1号第三置业A座1508室 商务内容合作QQ:2291221 电话:13391790444或(010)62178877
版权所有:电脑商情信息服务集团 北京赢邦策略咨询有限责任公司
声明:本媒体部分图片、文章来源于网络,版权归原作者所有,我司致力于保护作者版权,如有侵权,请与我司联系删除

京ICP备:2022009079号-2

京公网安备:11010502051901号

ICP证:京B2-20230255