ограничить addEventDelegate только родительским hbox - PullRequest
0 голосов
/ 16 июня 2020

Это настраиваемый элемент управления, созданный для моего предыдущего вопроса Пользовательский шрифт для знаков валюты

У меня два элемента span идут рядом друг с другом. Сидят в FormattedText. Сам FormattedText находится в HBox. Я хочу, чтобы всплывающее окно запускалось, когда пользователь наводит / выводит мышку из hbox. К сожалению, поскольку у меня есть 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

Ответы [ 2 ]

1 голос
/ 17 июня 2020

Ключевым моментом здесь является то, что событие mouseout запускается, когда мышь выходит из любого дочернего элемента элемента, который прослушивает событие. В этом случае, например, при переходе от выделенного текста к затененному тексту вы получаете событие mouseout при перемещении с выделенного текста, которое закрывает всплывающее окно, затем событие наведения указателя мыши на выцветший текст, которое открывает его снова.

Поскольку вы открываете уже открытое всплывающее окно, ничего не происходит, вам нужно только добавить строку при наведении курсора мыши, чтобы проверить элемент, к которому вы перешли. Если это не дочерний элемент текущего элемента, закройте всплывающее окно.

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

Основываясь на ответе Д.Си, я добавил это в JSBin. Мне лично не нравится использовать такие onBeforeRendering и onAfterRendering, поэтому я немного поработал над созданием всего в 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, выход

0 голосов
/ 16 июня 2020

думаю можно обойтись без 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, вывод

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...