HarmonyOS鸿蒙Next中拖拽Text进入Grid,触发onDrop,修改数据源直接不显示了?

HarmonyOS鸿蒙Next中拖拽Text进入Grid,触发onDrop,修改数据源直接不显示了?

import { Prompt } from '@kit.ArkUI';
import { unifiedDataChannel } from '@kit.ArkData';
import { hilog } from '@kit.PerformanceAnalysisKit';

@Entry
@Component
struct GridExample {
  @State numbers: string[] = [];
  // 添加图片资源引用声明
  @State dragImage: Resource = $r('app.media.app_icon');
  scroller: Scroller = new Scroller();
  @State text: string = 'drag';
  @State insertIndex: number = -1

  @Builder
  pixelMapBuilder() {
    Column() {
      Image($r('app.media.app_icon')) // 使用本地图片资源
        .width(80)
        .height(80)
        .objectFit(ImageFit.Contain) // 保持图片比例
    }
  }

  aboutToAppear() {

    for (let i = 1; i <= 15; i++) {

      this.numbers.push(i + '');

    }

  }

  addNewItem(text: string, insertIndex: number) {
    // 在指定位置插入新项目
    this.numbers.splice(insertIndex, 0, text);
  }

  build() {

    Column({ space: 5 }) {

      // 外部可拖拽文本
      Text('拖拽我')
        .fontSize(16)
        .backgroundColor(0xD2B48C)
        .width(120)
        .height(40)
        .textAlign(TextAlign.Center)
        .onDragStart((event: DragEvent, extraParams?: string) => {
          // const data: unifiedDataChannel.PlainText = new unifiedDataChannel.PlainText()
          // data.textContent = "111"
          // const udata = new unifiedDataChannel.UnifiedData(data)
          // event.setData(udata)

          const dragItemInfo: DragItemInfo = {
            builder: this.pixelMapBuilder(),
            extraInfo: '1313131313'
          }
          return dragItemInfo
          //return this.pixelMapBuilder();
        })
        .onClick(() => {
          this.numbers.splice(0, 0, "1111");
        })

      Grid(this.scroller) {

        ForEach(this.numbers, (day: string) => {
          GridItem() {
            Text(day)
              .fontSize(16)
              .backgroundColor(0xF9CF93)
              .width(80)
              .height(80)
              .textAlign(TextAlign.Center)
          }

        })

      }
      .columnsTemplate('1fr 1fr 1fr')
      .columnsGap(10)
      .rowsGap(10)
      .key("1111111")
      .backgroundColor(0xFAEEE0)
      .height('100%')
      // .supportAnimation(true)
      //.editMode(true) // 设置Grid是否进入编辑模式,进入编辑模式可以拖拽Grid组件内部GridItem

      // .onItemDragStart((event: ItemDragInfo, itemIndex: number) => { // 第一次拖拽此事件绑定的组件时,触发回调。
      //
      //   return this.pixelMapBuilder(); //设置拖拽过程中显示的图片。
      //
      // })
      //
      // // 绑定此事件的组件可作为拖拽释放目标,当在本组件范围内停止拖拽行为时,触发回调。
      //
      // .onItemDrop((event: ItemDragInfo, itemIndex: number, insertIndex: number, isSuccess: boolean) => {
      //   // 获取拖拽的文本数据
      //   //const draggedText = event.extraInfo;
      //   // if (draggedText) {
      //   //   this.addNewItem(draggedText, insertIndex);
      //   // }
      // })
      .onDrop((dragEvent: DragEvent) => {
        this.numbers.push("10")
        const globalX = dragEvent.getWindowX(); // 获取全局X坐标
        const globalY = dragEvent.getWindowY(); // 获取全局Y坐标

        // 将全局坐标转换为相对于Grid的坐标
        const gridX = globalX - this.scroller.currentOffset().xOffset;
        const gridY = globalY - this.scroller.currentOffset().yOffset;
        hilog.info(1, '[DEMO]', gridX + "")
        hilog.info(1, '[DEMO]', gridY + "")
        // 计算当前拖拽位置的索引
        const colCount = 3; // 根据columnsTemplate设置
        const itemWidth = 80 + 50; // 项目宽度+列间距
        const itemHeight = 80 + 10; // 项目高度+行间距

        const colIndex = Math.floor(gridX / itemWidth);
        const rowIndex = Math.floor(gridY / itemHeight);
        const insertIndex = (rowIndex * colCount + colIndex) - 3;
        this.numbers = this.numbers.splice(insertIndex, 0, "1111");
        // hilog.info(1, '[DEMO]', insertIndex + "")
        //
        // //this.numbers = this.numbers.splice(insertIndex, 0, "1111");
        // this.numbers.push("10")
        // hilog.info(1, '[DEMO]', JSON.stringify(this.numbers))
        // this.addNewItem("1111", insertIndex)
        // hilog.info(1, '[DEMO]',JSON.stringify(this.numbers.splice(insertIndex, 0, "1111")))
      })

    }.width('100%').margin({ top: 5 })

  }
}

谁知道为啥?


更多关于HarmonyOS鸿蒙Next中拖拽Text进入Grid,触发onDrop,修改数据源直接不显示了?的实战教程也可以访问 https://www.itying.com/category-93-b0.html

4 回复

onDrop事件中直接使用splice方法修改数组会破坏响应式更新机制

尝试如下修改

.onDrop((dragEvent: DragEvent) => {
  const data = dragEvent.getData()?.getFirstPlainText(); // 获取拖拽数据
  if (!data) return;

  // 计算有效插入位置
  const offset = this.scroller.currentOffset();
  const gridX = dragEvent.getWindowX() - Math.abs(offset.xOffset);
  const gridY = dragEvent.getWindowY() - Math.abs(offset.yOffset);
  
  const colCount = 3;
  const itemWidth = 80 + 10; // 包含列间距
  const itemHeight = 80 + 10; // 包含行间距

  const colIndex = Math.floor(gridX / itemWidth);
  const rowIndex = Math.floor(gridY / itemHeight);
  let insertIndex = rowIndex * colCount + colIndex;

  // 边界保护
  insertIndex = Math.max(0, Math.min(insertIndex, this.numbers.length));
  
  // 更新数据源
  this.numbers.splice(insertIndex, 0, data);
  this.numbers = [...this.numbers]; // 触发响应式更新
})

更多关于HarmonyOS鸿蒙Next中拖拽Text进入Grid,触发onDrop,修改数据源直接不显示了?的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


算不算系统bug,

在HarmonyOS Next中,拖拽Text进入Grid触发onDrop后,若直接修改数据源导致Grid不显示,通常是因为数据源变更未触发UI刷新。需使用@State@Observed装饰器管理数据源,确保数据驱动UI更新。修改数据源后,框架应自动重新渲染Grid。检查数据绑定是否正确,并确保onDrop内数据更新操作被响应式系统捕获。

这个问题是由于在 onDrop 回调中直接修改 @State 数据源 numbers 数组时,使用了错误的数组操作方法导致的。

在你的代码中,这一行有问题:

this.numbers = this.numbers.splice(insertIndex, 0, "1111");

splice() 方法返回的是被删除的元素数组,而不是修改后的新数组。当你将 splice() 的返回值赋给 this.numbers 时,实际上是将一个空数组(因为没有删除任何元素)赋值给了 this.numbers,导致所有内容消失。

正确的做法应该是:

// 方法1:直接修改原数组,然后重新赋值触发刷新
this.numbers.splice(insertIndex, 0, "1111");
this.numbers = [...this.numbers]; // 创建新数组引用触发UI更新

// 方法2:使用数组扩展运算符
this.numbers = [
  ...this.numbers.slice(0, insertIndex),
  "1111",
  ...this.numbers.slice(insertIndex)
];

另外,你的坐标计算逻辑可能也有问题:

  • itemWidthitemHeight 应该使用 Grid 的实际布局参数
  • 坐标转换时需要考虑 Grid 的滚动偏移量

建议先修复数组操作问题,如果还有显示问题,再检查坐标计算逻辑。

回到顶部