将 addEventDelegate 限制为仅父 hbox

restrict addEventDelegate to parent hbox only

这是为我之前的问题创建的自定义控件

我有两个 span 元素彼此相邻。他们坐在FormattedTextFormattedText 本身位于 HBox 中。 我希望当用户鼠标从 hbox 移动 over/out 时触发弹出窗口。不幸的是,因为我有 2 个跨度,所以当用户将鼠标悬停在它们上方时会单独触发(因此显示 2 个单独的弹出窗口,而实际上它应该是一个)。我的假设是,这是因为 onmouseover/out 附加到引擎盖下的两个跨度。我可以将这些事件限制为仅 hbox 吗?

sap.ui.define([
  'sap/ui/core/Control',
  'sap/m/FormattedText',
  'sap/m/HBox',
], function (Control, FormattedText, HBox) {

  return Control.extend('drex.control.TherapyCosts', {
    metadata: {
      properties: {
        rank: {
          type: 'int',
          defaultValue: 0
        },
      },
      aggregations: {
        _rankedTherapyCost: {type: 'sap.m.FormattedText', multiple: false, singularName: '_rankedTherapyCost'},
        _popover: {type: 'sap.m.Popover', multiple: false, singularName: '_popover'},
        _hbox: {type: 'sap.m.HBox', multiple: false}
      }
    },

    init: function () {
      Control.prototype.init.apply(this, arguments);
    },

    onBeforeRendering: function () {
      const highlighedCurrency = this.getCurrency().repeat(this.getRank());
      const fadedCurrency = this.getCurrency().repeat(7 - this.getRank());
      const _popover = new sap.m.Popover({
        showHeader: false,
        placement: 'VerticalPreferredBottom',
        content: new sap.m.Text({text: 'test'})
      });
      this.setAggregation('_popover', _popover);
      const _formattedText = new FormattedText({
        htmlText:
          `<span class="currencyHighlighted">${highlighedCurrency}</span>` +
          `<span class="currencyFaded">${fadedCurrency}</span>`
      });
      this.setAggregation('_rankedTherapyCost', _formattedText);
      const _hbox = new HBox(
        { items: [this.getAggregation('_rankedTherapyCost')]})
        .addEventDelegate({
          onmouseover: () => {
            this.getAggregation('_popover').openBy(this);
          },
          onmouseout: () => {
            this.getAggregation('_popover').close()
          }
        });
      this.setAggregation('_hbox', _hbox)
    },

    renderer: function (rm, oControl) {
      const _hbox = oControl.getAggregation('_hbox');
      rm.write('<div');
      rm.writeControlData(oControl);
      rm.write('>');
      rm.renderControl(_hbox);
      rm.write('</div>');
    }
  });
});

这是问题的视频 https://streamable.com/fjw408

我想你可以不用 hbox;只要有两个格式化文本或任何 sapui5 控件也可以。

sap.ui.define([
  'sap/ui/core/Control',
  'sap/m/FormattedText',
], function (Control, FormattedText) {

  Control.extend('TherapyCosts', {
    metadata: {
      properties: {
        rank: {
          type: 'int',
          defaultValue: 0
        },
        currency: {
          type: "string",
          defaultValue: "$"
        }
      },
      aggregations: {
        _highlighted: {type: 'sap.m.FormattedText', multiple: false},
        _faded: {type: 'sap.m.FormattedText', multiple: false},
        _popover: {type: 'sap.m.Popover', multiple: false, singularName: '_popover'}
      }
    },

    init: function () {
      Control.prototype.init.apply(this, arguments);
      this.addStyleClass('therapy-cost')
    },

    onBeforeRendering: function () {
      const highlighedCurrency = this.getCurrency().repeat(this.getRank());
      const highlight = new FormattedText({
        htmlText: highlighedCurrency
      });
      this.setAggregation('_highlighted', highlight);

      const fadedCurrency = this.getCurrency().repeat(7 - this.getRank());
      const faded = new FormattedText({
        htmlText: fadedCurrency
      });
      this.setAggregation('_faded', faded);

      const _popover = new sap.m.Popover({
        showHeader: false,
        placement: 'VerticalPreferredBottom',
        content: new sap.m.Text({text: 'test'})
      });
      this.setAggregation('_popover', _popover);
    },

    renderer: function (rm, oControl) {
      rm.write('<div');
      rm.writeControlData(oControl);
      rm.writeClasses(oControl);
      rm.writeStyles(oControl);
      rm.write('>');
      rm.renderControl(oControl.getAggregation('_highlighted'));
      rm.renderControl(oControl.getAggregation('_faded'));
      rm.write('</div>');
    },
    onAfterRendering: function () {
      const popOver = this.getAggregation('_popover');
      const highlighted = this.getAggregation("_highlighted");
      highlighted.$().addClass("currency-highlighted");
      highlighted.$().hover(function() {
        popOver.openBy(highlighted);
      }, function() {
        popOver.close();
      });
      const faded = this.getAggregation("_faded");
      faded.$().addClass("currency-faded");
    },
  });
  (new TherapyCosts({
    rank: 5
  })).placeAt('content')
});

https://jsbin.com/razebuq/edit?css,js,output

这里的关键是mouseout事件,当鼠标移出监听该事件的元素的任意子元素时触发。在这种情况下,例如,从强调文本移动到淡入淡出的文本,当离开强调文本时会发生 mouseout 事件,关闭弹出窗口,然后在淡入淡出的文本上发生鼠标悬停事件,再次打开它。

由于打开一个已经打开的弹出窗口不会执行任何操作,因此您只需要在 mouseout 上添加一行来检查您转到的元素。如果它不是当前元素的子元素,则只关闭弹出窗口。

if (!this.getDomRef().contains(e.toElement)) {
  popOver.close()
}

基于 D.Seah 的回答,我已将其添加到 JSBin。我个人不喜欢像这样使用 onBeforeRenderingonAfterRendering,所以我重构了一点以在 init 上构建所有内容并简单地更改 属性 更改上的控件。这样,出于性能原因,您可以减少渲染工作。

sap.ui.define([
  'sap/ui/core/Control',
  'sap/m/FormattedText',
], function (Control, FormattedText) {

  Control.extend('TherapyCosts', {
    metadata: {
      properties: {
        rank: {
          type: 'int',
          defaultValue: 0
        },
        currency: {
          type: "string",
          defaultValue: "$"
        }
      },
      aggregations: {
        _highlighted: {type: 'sap.m.FormattedText', multiple: false},
        _faded: {type: 'sap.m.FormattedText', multiple: false},
        _popover: {type: 'sap.m.Popover', multiple: false, singularName: '_popover'}
      }
    },

    init: function () {
      Control.prototype.init.apply(this, arguments);
      this.addStyleClass('therapy-cost');
      
      const highlight = new FormattedText();
      highlight.addStyleClass("currency-highlight");
      this.setAggregation('_highlighted', highlight);

      const faded = new FormattedText();
      faded.addStyleClass("currency-faded");
      this.setAggregation('_faded', faded);
      
      const _popover = new sap.m.Popover({
        showHeader: false,
        placement: 'VerticalPreferredBottom',
        content: new sap.m.Text({text: 'test'})
      });
      this.setAggregation('_popover', _popover);
    },
    
    _changeAggr: function () {
      const highlighedCurrency = this.getCurrency().repeat(this.getRank());
      const highlight = this.getAggregation("_highlighted");
      highlight.setHtmlText(highlighedCurrency);
      
      const fadedCurrency = this.getCurrency().repeat(7 - this.getRank());
      const faded = this.getAggregation("_faded");
      faded.setHtmlText(fadedCurrency);
    },
    
    setRank: function(rank) {
       if (this.getProperty("rank") !== rank) {
         this.setProperty("rank", rank);
         this._changeAggr();
       }
    },

    setCurrency: function(curr) {
       if (this.getProperty("currency") !== curr) {
         this.setProperty("currency", curr);
         this._changeAggr();
       }
    },
    
    renderer: function (rm, oControl) {
      rm.write('<div');
      rm.writeControlData(oControl);
      rm.writeClasses(oControl);
      rm.writeStyles(oControl);
      rm.write('>');
      rm.renderControl(oControl.getAggregation('_highlighted'));
      rm.renderControl(oControl.getAggregation('_faded'));
      rm.write('</div>');
    },
    
    onmouseover: function (e) {
      const popOver = this.getAggregation('_popover');
      popOver.openBy(this);
    },
    
    onmouseout: function (e) {
      if (!this.getDomRef().contains(e.toElement)) {
        const popOver = this.getAggregation('_popover');
        popOver.close();
      }
    }
  });
  (new TherapyCosts({
    rank: 5,
    currency: "£"
  })).placeAt('content')
});
.therapy-cost {
  display: inline-flex;
  flex-direction: row;
}

.therapy-cost .currency-highlighted {
  color: black;
}

.therapy-cost .currency-faded {
  color: lightgrey;
}
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>JS Bin</title>
    <script 
            src="https://openui5.hana.ondemand.com/resources/sap-ui-core.js" 
            id="sap-ui-bootstrap" 
            data-sap-ui-theme="sap_bluecrystal" 
            data-sap-ui-xx-bindingSyntax="complex" 
            data-sap-ui-libs="sap.m"></script>
  </head>
  <body class="sapUiBody sapUiSizeCompact">
    <div id='content'></div>
  </body>
</html>

https://jsbin.com/gukedamemu/3/edit?css,js,output