1# 拖拽事件 2 3拖拽事件指组件被长按后拖拽时触发的事件。 4 5> **说明:** 6> 7> 从API Version 8开始支持。后续版本如有新增内容,则采用上角标单独标记该内容的起始版本。 8 9## 事件 10 11| 名称 | 支持冒泡 | 功能描述 | 12| ------------------------------------------------------------ | -------- | ------------------------------------------------------------ | 13| onDragStart(event: (event?: [DragEvent](#dragevent说明), extraParams?: string) => [CustomBuilder](ts-types.md#custombuilder8) \| [DragItemInfo](#dragiteminfo说明)) | 否 | 第一次拖拽此事件绑定的组件时,触发回调。<br/>- event:拖拽事件信息,包括拖拽点坐标。<br/>- extraParams:拖拽事件额外信息,详见[extraParams](#extraparams说明)说明。<br/>返回值:当前跟手效果所拖拽的对象,用于显示拖拽时的提示组件。<br/>长按150ms可触发拖拽事件。优先级:长按手势配置时间小于等于150ms时,长按手势优先触发,否则拖拽事件优先触发。 | 14| onDragEnter(event: (event?: [DragEvent](#dragevent说明), extraParams?: string) => void) | 否 | 拖拽进入组件范围内时,触发回调。<br/>- event:拖拽事件信息,包括拖拽点坐标。<br/>- extraParams:拖拽事件额外信息,详见[extraParams](#extraparams说明)说明。<br/>当监听了onDrop事件时,此事件才有效。 | 15| onDragMove(event: (event?: [DragEvent](#dragevent说明), extraParams?: string) => void) | 否 | 拖拽在组件范围内移动时,触发回调。<br/>- event:拖拽事件信息,包括拖拽点坐标。<br/>- extraParams:拖拽事件额外信息,详见[extraParams](#extraparams说明)说明。<br/>当监听了onDrop事件时,此事件才有效。 | 16| onDragLeave(event: (event?: [DragEvent](#dragevent说明), extraParams?: string) => void) | 否 | 拖拽离开组件范围内时,触发回调。<br/>- event:拖拽事件信息,包括拖拽点坐标。<br/>- extraParams:拖拽事件额外信息,详见[extraParams](#extraparams说明)说明。<br/>当监听了onDrop事件时,此事件才有效。 | 17| onDrop(event: (event?: [DragEvent](#dragevent说明), extraParams?: string) => void) | 否 | 绑定此事件的组件可作为拖拽释放目标,当在本组件范围内停止拖拽行为时,触发回调。<br/>- event:拖拽事件信息,包括拖拽点坐标。<br/>- extraParams:拖拽事件额外信息,详见[extraParams](#extraparams说明)说明。 | 18 19## DragItemInfo说明 20 21| 名称 | 类型 | 必填 | 描述 | 22| --------- | ---------------------------------------- | ---- | --------------------------------- | 23| pixelMap | [PixelMap](../apis/js-apis-image.md#pixelmap7) | 否 | 设置拖拽过程中显示的图片。 | 24| builder | [CustomBuilder](ts-types.md#custombuilder8) | 否 | 拖拽过程中显示自定义组件,如果设置了pixelMap,则忽略此值。 | 25| extraInfo | string | 否 | 拖拽项的描述。 | 26 27 28## extraParams说明 29 30 用于返回组件在拖拽中需要用到的额外信息。 31 32 extraParams是Json对象转换的string字符串,可以通过Json.parse转换的Json对象获取如下属性。 33 34| 名称 | 类型 | 描述 | 35| ------------- | ------ | ---------------------------------------- | 36| selectedIndex | number | 当拖拽事件设在父容器的子元素时,selectedIndex表示当前被拖拽子元素是父容器第selectedIndex个子元素,selectedIndex从0开始。<br/>仅在ListItem组件的拖拽事件中生效。 | 37| insertIndex | number | 当前拖拽元素在List组件中放下时,insertIndex表示被拖拽元素插入该组件的第insertIndex个位置,insertIndex从0开始。<br/>仅在List组件的拖拽事件中生效。 | 38 39## DragEvent说明 40 41| 名称 | 类型 | 描述 | 42| ------ | ------ | ---------------- | 43| getX() | number | 当前拖拽点相对于屏幕左上角的x轴坐标,单位为vp。 | 44| getY() | number | 当前拖拽点相对于屏幕左上角的y轴坐标,单位为vp。 | 45 46## 示例 47 48### 示例1 49 50```ts 51@Observed 52class ClassA { 53 public name: string 54 public bol: boolean 55 56 constructor(name: string, bol: boolean) { 57 this.name = name 58 this.bol = bol 59 } 60} 61 62@Extend(Text) function textStyle() { 63 .width('25%') 64 .height(35) 65 .fontSize(16) 66 .textAlign(TextAlign.Center) 67 .backgroundColor(0xAFEEEE) 68} 69 70@Entry 71@Component 72struct DragExample { 73 @State arr: ClassA[] = [new ClassA('A', true), new ClassA('B', true), new ClassA('C', true)] 74 @State dragIndex: number = 0 75 76 changeIndex(index1: number, index2: number) { // 交换数组位置 77 [this.arr[index1], this.arr[index2]] = [this.arr[index2], this.arr[index1]]; 78 } 79 80 build() { 81 Column() { 82 Row({ space: 15 }) { 83 List({ space: 20 }) { 84 ForEach(this.arr, (item, index) => { 85 ListItem() { 86 Column() { 87 Child({ a: this.arr[index] }) 88 } 89 .onTouch((event: TouchEvent) => { 90 if (event.type === TouchType.Down) { 91 this.dragIndex = index // 获取当前拖拽子组件的索引 92 console.info('onTouch' + this.dragIndex) 93 } 94 }) 95 } 96 }) 97 } 98 .listDirection(Axis.Horizontal) 99 .onDrop((event: DragEvent, extraParams: string) => { // 绑定此事件的组件可作为拖拽释放目标,当在本组件范围内停止拖拽行为时,触发回调。 100 let jsonString = JSON.parse(extraParams); 101 this.changeIndex(this.dragIndex, jsonString.insertIndex) 102 }) 103 }.padding({ top: 10, bottom: 10 }).margin(10) 104 105 }.width('100%').height('100%').padding({ top: 20 }).margin({ top: 20 }) 106 } 107} 108 109@Component 110struct Child { 111 @ObjectLink a: ClassA 112 113 @Builder pixelMapBuilder() { 114 Column() { 115 Text(this.a.name) 116 .width('50%') 117 .height(60) 118 .fontSize(16) 119 .borderRadius(10) 120 .textAlign(TextAlign.Center) 121 .backgroundColor(Color.Yellow) 122 } 123 } 124 125 build() { 126 Column() { 127 Text(this.a.name) 128 .textStyle() 129 .visibility(this.a.bol ? Visibility.Visible : Visibility.None) 130 .onDragStart(() => { // 第一次拖拽此事件绑定的组件时,触发回调。 131 this.a.bol = false // 控制显隐 132 return this.pixelMapBuilder() // 设置拖拽过程中显示的图片。 133 }) 134 .onTouch((event: TouchEvent) => { 135 if (event.type === TouchType.Up) { 136 this.a.bol = true 137 } 138 }) 139 Text('') 140 .width('25%') 141 .height(35) 142 .fontSize(16) 143 .textAlign(TextAlign.Center) 144 .border({ width: 5, color: 'red' }) 145 .visibility(!this.a.bol ? Visibility.Visible : Visibility.None) 146 } 147 } 148} 149``` 150 151![drag-drop](figures/drag-drop.gif) 152 153### 示例2 154 155```ts 156// xxx.ets 157@Extend(Text) function textStyle () { 158 .width('25%') 159 .height(35) 160 .fontSize(16) 161 .textAlign(TextAlign.Center) 162 .backgroundColor(0xAFEEEE) 163} 164 165@Entry 166@Component 167struct DragExample { 168 @State numbers: string[] = ['one', 'two', 'three', 'four', 'five', 'six'] 169 @State text: string = '' 170 @State bool: boolean = true 171 @State eventType: string = '' 172 @State appleVisible: Visibility = Visibility.Visible 173 @State orangeVisible: Visibility = Visibility.Visible 174 @State bananaVisible: Visibility = Visibility.Visible 175 private dragList: string[] = ['apple', 'orange', 'banana'] 176 @State fruitVisible: Visibility[] = [Visibility.Visible, Visibility.Visible, Visibility.Visible] 177 @State idx: number = 0 178 179 // 自定义拖拽过程中显示的内容 180 @Builder pixelMapBuilder() { 181 Column() { 182 Text(this.text) 183 .width('50%') 184 .height(60) 185 .fontSize(16) 186 .borderRadius(10) 187 .textAlign(TextAlign.Center) 188 .backgroundColor(Color.Yellow) 189 } 190 } 191 192 build() { 193 Column() { 194 Text('There are three Text elements here') 195 .fontSize(12) 196 .fontColor(0xCCCCCC) 197 .width('90%') 198 .textAlign(TextAlign.Start) 199 .margin(5) 200 Row({ space: 15 }) { 201 ForEach(this.dragList, (item, index) => { 202 Text(item) 203 .textStyle() 204 .visibility(this.fruitVisible[index]) 205 .onDragStart(() => { 206 this.bool = true 207 this.text = item 208 this.fruitVisible[index] = Visibility.None 209 return this.pixelMapBuilder 210 }) 211 .onTouch((event: TouchEvent) => { 212 if (event.type === TouchType.Down) { 213 this.eventType = 'Down' 214 this.idx = index 215 } 216 if (event.type === TouchType.Up) { 217 this.eventType = 'Up' 218 if (this.bool) { 219 this.fruitVisible[index] = Visibility.Visible 220 } 221 } 222 }) 223 }) 224 }.padding({ top: 10, bottom: 10 }).margin(10) 225 226 Text('This is a List element') 227 .fontSize(12) 228 .fontColor(0xCCCCCC) 229 .width('90%') 230 .textAlign(TextAlign.Start) 231 .margin(15) 232 List({ space: 20 }) { 233 ForEach(this.numbers, (item) => { 234 ListItem() { 235 Text(item) 236 .width('100%') 237 .height(80) 238 .fontSize(16) 239 .borderRadius(10) 240 .textAlign(TextAlign.Center) 241 .backgroundColor(0xAFEEEE) 242 } 243 }, item => item) 244 } 245 .editMode(true) 246 .height('50%') 247 .width('90%') 248 .border({ width: 1 }) 249 .padding(15) 250 .divider({ strokeWidth: 2, color: 0xFFFFFF, startMargin: 20, endMargin: 20 }) 251 .onDragEnter((event: DragEvent, extraParams: string) => { 252 console.log('List onDragEnter, ' + extraParams + 'X:' + event.getX() + 'Y:' + event.getY()) 253 }) 254 .onDragMove((event: DragEvent, extraParams: string) => { 255 console.log('List onDragMove, ' + extraParams + 'X:' + event.getX() + 'Y:' + event.getY()) 256 }) 257 .onDragLeave((event: DragEvent, extraParams: string) => { 258 console.log('List onDragLeave, ' + extraParams + 'X:' + event.getX() + 'Y:' + event.getY()) 259 }) 260 .onDrop((event: DragEvent, extraParams: string) => { 261 let jsonString = JSON.parse(extraParams); 262 if (this.bool) { 263 // 通过splice方法插入元素 264 this.numbers.splice(jsonString.insertIndex, 0, this.text) 265 this.bool = false 266 } 267 this.fruitVisible[this.idx] = Visibility.None 268 }) 269 }.width('100%').height('100%').padding({ top: 20 }).margin({ top: 20 }) 270 } 271} 272``` 273 274![zh-cn_image_0000001252667389](figures/zh-cn_image_0000001252667389.gif) 275