即使工作完成,MutationObserver和window.onresize也不会停止

时间:2019-01-11 23:14:56

标签: javascript ecmascript-6

我对这种类型的功能不是很熟悉(MutationObserver甚至更多)。 我以为可以通过设置setTimeout来保存,但是不,它在this._Resizing方法上循环运行,我不知道如何理解或解决此问题。

这个想法是即使窗口更改大小,也要在SVG上保持相同的显示比例,即使是通过脚本完成也是如此。首先更改窗口大小(大小为50%,然后单击按钮以切换大小100) / 200像素)

如果我使用JS对象,那么正是因为它是对象编程的原理之一,所以它能够被乘以它。

此处的代码仅用于说明我的问题,而此按钮仅用于说明它:这是示例的原理。

在我的真实界面中没有按钮,但是其他元素可以更改大小,并且可能会干扰不同元素SVG的剩余大小。

这是犯罪的对象:

const vBxEnum = Object.freeze({ "left": 0, "top": 1, "width": 2, "height": 3 });

class SVG_kit {
  constructor(zID_SVG) {

    this.$_SVG = document.getElementById(zID_SVG);
    this._viewBox = this.$_SVG.getAttribute("viewBox").split(' ').map(v => +v);
    this.svg_rect = this.$_SVG.getBoundingClientRect();

    this._scale = this._viewBox[vBxEnum.width] / this.svg_rect.width;

    // do same ratio for height                    
    this._viewBox[vBxEnum.height] = this.svg_rect.height * this._scale;
    this.$_SVG.setAttribute("viewBox", this._viewBox.join(' '));

    this.TimeOutResize = 0;
    this.count = 0;           // just to see resize infinite loop in action !

    window.onresize = e => this._Resizing();

    let observer4Size = new MutationObserver(m => this._Resizing());

    observer4Size.observe(this.$_SVG, { attributes: true });
  }

  _Resizing() {
    this.TimeOutResize = setTimeout(function (thisObj) {
      console.log('resiz', ++thisObj.count); // resize never stop !

      thisObj.svg_rect = thisObj.$_SVG.getBoundingClientRect();

      thisObj._viewBox[vBxEnum.width] = thisObj.svg_rect.width * thisObj._scale;
      thisObj._viewBox[vBxEnum.height] = thisObj.svg_rect.height * thisObj._scale;

      thisObj.$_SVG.setAttribute("viewBox", thisObj._viewBox.join(' '));

      clearTimeout(thisObj.TimeOutResize);
    }, 100, this);
  }
} /// SVG_kit

var
  svg_SZ    = '100px',
  svg_E1    = document.getElementById('First-SVG'),
  Sz_Button = document.getElementById("Bt-ChgSize");

var First_SVG = new SVG_kit('First-SVG');

Sz_Button.onclick = function ()
{
  svg_E1.style.width = svg_SZ;
  svg_SZ = (svg_SZ === '100px') ? '200px' : '100px';
}
svg {
  margin: 1em;
  height: 200px;
  width: 50%;
  box-shadow: 0 0 1em #CCC;
  background-color: #8ed1d6;
}
<button id='Bt-ChgSize'>change Size (100px / 200px)</button>

<svg id="First-SVG" viewBox="0 0 1820 480">
  <circle fill="#F7941E" stroke="#231F20" stroke-width="10" cx="250" cy="250" r="200" opacity="0.6" />
</svg>

1 个答案:

答案 0 :(得分:2)

您将用此代码陷入困境。

$.ajax({ url: "/api/Customers/UpdateCustomer", type: "PUT", data: { vm }, success: function () { Location("customers/Index"); //button.parents("tr").remove(); } }); 观察者DOM元素及其所有子元素,以了解是否要移动/添加/删除元素或更改属性。

在初始化时,您正在使用一个容器来监视SVG容器,并检查其属性。进行任何更改时,您都会致电MutationObserver

然而,在Resizing()内的这一行:

Resizing

您正在更改SVG容器的属性,该属性然后再次调用 thisObj.$_SVG.setAttribute("viewBox", thisObj._viewBox.join(' ')); ,并重复该循环。

老实说,为此Resizing既多余又不必要。您可以单独绑定一个MutationObserver并从那里处理事件(您确实这样做了),但是,由于您确实想要一个,因此下面的代码可以满足您的要求:

onResize
const vBxEnum = Object.freeze({ "left": 0, "top": 1, "width": 2, "height": 3 });

class SVG_kit {
  constructor(zID_SVG) {

    this.$_SVG = document.getElementById(zID_SVG);
    this._viewBox = this.$_SVG.getAttribute("viewBox").split(' ').map(v => +v);
    this.svg_rect = this.$_SVG.getBoundingClientRect();

    this._scale = this._viewBox[vBxEnum.width] / this.svg_rect.width;

    // do same ratio for height                    
    this._viewBox[vBxEnum.height] = this.svg_rect.height * this._scale;
    this.$_SVG.setAttribute("viewBox", this._viewBox.join(' '));

    this.TimeOutResize = 0;
    this.count = 0;           // just to see resize infinite loop in action !
    this._width = null;
    window.onresize = e => this._Resizing();
    let observer4Size = new MutationObserver(this._checkStyleChange.bind(this));

    observer4Size.observe(this.$_SVG, { attributes: true });
  }
  _checkStyleChange(mutations) {
    let callResizing = false;
    var element = this.$_SVG;
    var oldWidth = this._width;
    mutations.forEach(function(mutation) {
     if (mutation.target === element && mutation.attributeName === 'style') {
       if (oldWidth !== element.style.width) {
         oldWidth = element.style.width;
         callResizing = true;
        }
      }
    });
    if (callResizing) this._Resizing();
  }

  _Resizing() {
  console.log("Resizing");
  let thisObj = this;

      thisObj.svg_rect = thisObj.$_SVG.getBoundingClientRect();

      thisObj._viewBox[vBxEnum.width] = thisObj.svg_rect.width * thisObj._scale;
      thisObj._viewBox[vBxEnum.height] = thisObj.svg_rect.height * thisObj._scale;

      thisObj.$_SVG.setAttribute("viewBox", thisObj._viewBox.join(' '));

      clearTimeout(thisObj.TimeOutResize);
  }
} /// SVG_kit

var
  svg_SZ    = '100px',
  svg_E1    = document.getElementById('First-SVG'),
  Sz_Button = document.getElementById("Bt-ChgSize");

var First_SVG = new SVG_kit('First-SVG');

Sz_Button.onclick = function ()
{
  svg_E1.style.width = svg_SZ;
  svg_SZ = (svg_SZ === '100px') ? '200px' : '100px';
//  First_SVG._Resizing();
}
svg {
  margin: 1em;
  height: 200px;
  width: 50%;
  box-shadow: 0 0 1em #CCC;
  background-color: #8ed1d6;
}