Text组件下Span布局属性和触摸事件无效
======================

#### 问题现象

Text组件内嵌套Span组件时，设置Span组件的布局属性会失效。

问题代码如下：

@Entry
@Component
struct Index {
  spanValue: string = '';

  @Styles
  pressedStyles(): void {
    .margin({ left: 50 });
  }

  build() {
    Column() {
      Text() {
        Span('aaaaa').visibility(Visibility.Hidden);
        Span('bbbbb').padding({ left: 10 });
        Span('ccccc').margin({ left: 50 });
        Span('ddddd').stateStyles({
          pressed: this.pressedStyles,
        })
        Span('eeeee')
          .onTouch((event?: TouchEvent) => {
            if (event && event.sourceTool === SourceTool.Finger) {
              if (event.type === TouchType.Down) {
                console.info('Span onTouch');
              };
            };
          });
      };
    }
    .height('100%')
    .width('100%')
  }
}

预期是第一个Span组件隐藏，第三个Span组件距离左侧50vp，第四个Span组件点击后变成距离左侧50vp，最后一个Span组件触摸后有日志输出，但实际效果却是布局属性和触摸事件全部不生效，内容连在一起。

#### 背景知识

[Span](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/ts-basic-components-span)组件是Text组件的子组件，遇到多个字符串拼接场景往往会利用Span组件来实现，但是Span组件的属性不像Text那样丰富，有如下特点：

*   Span组件不支持margin，padding属性，Span作为Text组件的子组件，不支持“[通用属性](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/ts-component-general-attributes)”。
*   Span可以继承父组件Text的属性，支持继承的属性仅包括：fontColor、fontSize、fontStyle、fontWeight、decoration、letterSpacing、textCase、fontfamily、textShadow。
*   Span组件通用事件只支持点击事件onClick和悬浮事件onHover。

#### 解决方案

Text组件搭配Span组件使用时，仅可设置文本通用属性，如果需要实现Span组件的布局效果，建议使用Row和Text组件等其他代替方案实现。

*   针对设置visibility可见性场景，可以利用变量来控制Span的展示：
    
    @Entry
    @Component
    struct Scene1 {
      @State isVisibility: boolean = false;
    
      build() {
        Column() {
          Text() {
            if (this.isVisibility) {
              Span('aaaaa');
            }
            Span('bbbbb')
              .onClick(() => {
                this.isVisibility = !this.isVisibility;
              });
          }
        }
        .height('100%')
        .width('100%')
      }
    }
    
*   针对设置margin组件间距场景，可以使用Row和Text组件来实现：
    
    @Entry
    @Component
    struct Scene2 {
      build() {
        Column() {
          Row() {
            Text('aaaaa');
            Text('bbbbb');
            Text('ccccc').margin({ left: 50 });
          }
        }
        .height('100%')
        .width('100%')
      }
    }
    
*   针对设置padding属性的场景，可以在文本前后增加空格，也可以通过增加Span(' ')实现控制间距：
    
    @Entry
    @Component
    struct Scene3 {
      build() {
        Column() {
          Text() {
         _   // 在文本前后增加空格控制左右距离_
            Span(' 标题 ')
              .fontSize('20fp')
              .textBackgroundStyle({ color: Color.Green, radius: '5vp' })
              .fontColor(Color.White);
          _  // 直接增加空格控制间距_
            Span(' ').letterSpacing(10);
            Span('我是一段文本我是一段文本我是一段文本，我是一段文本我是一段文本我是一段文本，我是一段文本我是一段文本我是一段文本')
              .fontSize('20fp');
          }.maxLines(2).textOverflow({ overflow: TextOverflow.Ellipsis }).width('80%')
        }.width('100%').alignItems(HorizontalAlign.Center)
      }
    }
    
*   针对设置多态样式场景，可以使用Row和Text组件结合来替代实现：
    
    @Entry
    @Component
    struct Scene4 {
      @Styles
      pressedStyles(): void {
        .margin({ left: 50 });
      }
    
      build() {
        Column() {
          Row() {
            Text('aaaaa');
            Text('bbbbb');
            Text('ccccc');
            Text('ddddd').stateStyles({
              pressed: this.pressedStyles,
            });
          }
        }
        .height('100%')
        .width('100%')
      }
    }
    
*   针对Span组件触摸事件不生效场景，可以使用Row和Text组件结合来替代实现：
    
    @Entry
    @Component
    struct Scene5 {
      build() {
        Column() {
          Row() {
            Text('eeeee').onTouch((event?: TouchEvent) => {
              if (event && event.sourceTool === SourceTool.Finger) {
                if (event.type === TouchType.Down) {
                  console.info('Text onTouch');
                };
              };
            });
          }
        }
        .height('100%')
        .width('100%')
      }
    }
    

#### 常见FAQ

Q：DevEco Studio版本（5.0.5.315），使用@Extend装饰器修饰Span，设置margin属性后编译运行报错。报错内容为“Error: Debug Failure. False expression: Node must have a real position for this operatior”。

A：针对该无效属性的编译期的校验已在DevEco Studio 5.0.2 Release（5.0.7.210）版本优化，后续版本中该问题不会影响编译构建，但由于Span组件不支持margin属性，即使设置了该属性，实际运行效果也不会生效。

Q：为何ImageSpan能设置margin等布局属性？

A：[ImageSpan](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/ts-basic-components-imagespan)的通用属性方法支持尺寸设置、背景设置、边框设置，设计如此。