简体   繁体   English

获取不正确的 offsetWidth 和 offsetHeight 值

[英]Get incorrect offsetWidth and offsetHeight values

Here is my angular2 code.这是我的 angular2 代码。

Template模板

 <div #picker class="slider"> <div class="slider-track"> <div #sliderSelectionEl class="slider-selection"></div> <div #sliderHandle1 class="slider-handle"></div> <div #sliderHandle2 class="slider-handle"></div> </div> <div #tooltipEl class="tooltip"> <div class="tooltip-arrow"></div> <div #tooltipInner class="tooltip-inner"></div> </div> <input type="text" class="span2" value="" id="sl2"><br/> </div>


Component成分

import {Component, OnInit, Input, ViewChild, ElementRef, Renderer} from '@angular/core';
    export class SliderComponent implements OnInit {
      @ViewChild('picker') picker: ElementRef;

      constructor(private renderer: Renderer, private el: ElementRef) {

      }

      ngAfterViewInit() {
        this.renderer.setElementClass(this.picker.nativeElement, 'slider-horizontal', true);

        console.log(this.picker.nativeElement.offsetWidth);
        console.log(this.picker.nativeElement.offsetHeight);
      }
    }

 .slider-horizontal { width: 210px; height: 20px; }

The problem is the printed values are different for each time loading.问题是每次加载时打印的值都不同。 I guess this issue is due to the browser have not completed loading the div.我猜这个问题是由于浏览器没有完成加载div。 Do you know what is the solution for this?你知道解决这个问题的方法是什么吗?

You can detect size changes by using您可以使用以下方法检测尺寸变化

MutationObserver突变观察者

Probably the biggest audience for this new api are the people that write JS frameworks, [...] Another use case would be situations where you are using frameworks that manipulate the DOM and need to react to these modifications efficiently ( and without setTimeout hacks! ).可能这个新 api 的最大受众是编写 JS 框架的人,[...] 另一个用例是您使用框架来操作 DOM 并且需要有效地对这些修改做出反应的情况(并且没有 setTimeout hacks! )。

Here is how you can use it to detect changes in elements :以下是如何使用它来检测元素的变化:

// select the target node
var target = document.querySelector('#some-id'); // or 

// create an observer instance
var observer = new MutationObserver(function(mutations) {
    mutations.forEach(function(mutation) {
        console.log(mutation.type);
    });
});

// configuration of the observer:
var config = { attributes: true, childList: true, characterData: true }

// pass in the target node, as well as the observer options
observer.observe(target, config);

// later, you can stop observing
observer.disconnect();

For your case, you could use it inside your ngAfterViewInit and refresh your offsets size.对于您的情况,您可以在ngAfterViewInit使用它并刷新您的偏移量大小。 You can be more specific and only detect some mutations, and only then extract your offsets.您可以更具体,只检测一些突变,然后才提取您的偏移量。

more info :更多信息 :

doc: https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver文档: https : //developer.mozilla.org/en-US/docs/Web/API/MutationObserver

compatibility : https://caniuse.com/#feat=mutationobserver兼容性: https : //caniuse.com/#feat=mutationobserver

Demo :演示

 var observer = new MutationObserver(function(mutations) { mutations.forEach(function(mutation) { console.log(mutation); if(mutation.attributeName == 'class') // detect class change /* or if(mutation.target.clientWidth == myWidth) */ showOffset(mutation.target); observer.disconnect(); }); }); var config = { attributes: true} var demoDiv = document.getElementById('demoDiv'); var logs = document.getElementById('logs'); // wait for document state to be complete if (document.readyState === "complete") { ngAfterViewInit(); } document.onreadystatechange = function () { if (document.readyState === "complete") { ngAfterViewInit(); } } // observe changes that effects demoDiv + add class function ngAfterViewInit(){ observer.observe(demoDiv, config); demoDiv.classList.add('slider-horizontal'); } // show offsetWidth + height. // NB offset width and height will be bigger than clientWidth because I added a border. If you remove the border you'll see 220px,20px function showOffset(element){ offsetMessage = "offsetWidth:" + demoDiv.offsetWidth + " offsetHeight: " + demoDiv.offsetHeight; console.log(offsetMessage); logs.innerHTML = offsetMessage; }
 .slider-horizontal { border: 2px solid red; width: 210px; height: 20px; background: grey; }
 <div id='demoDiv'> I am a demo div </div> <div style="margin-top: 20px;"> logs : <span id='logs' style=" padding: 5px; border: 1px solid black"></span></div>

You have to schedule calls to 'offsetWidth' after rendering cycle, angular executes draw on the end of microtask queue, so you could try setTimeout(..., 0) or run Promise.resolve().then(...) outside of zonejs.您必须在渲染周期后安排对 'offsetWidth' 的调用,angular 在微任务队列的末尾执行 draw,因此您可以尝试setTimeout(..., 0)或在Promise.resolve().then(...)运行Promise.resolve().then(...) zonejs 的。 Hope it helps.希望能帮助到你。

In order to get correct offset values you can use: ngAfterContentChecked with the AfterContentChecked Interface.为了获得正确的偏移值,您可以使用: ngAfterContentChecked 和 AfterContentChecked 接口。

This method is called after every change detection run.每次更改检测运行后都会调用此方法。 So, inside this method use a flag (or counter) and setTimeOut:因此,在此方法中使用标志(或计数器)和 setTimeOut:

if (this.counter <= 10) {
      // this print offsetwidth of my element
      console.log('mm ' + this.container.nativeElement.offsetWidth);


      // setTimeOut allow to run another changedetection 
      // so ngAfterContentChecked will run again
      setTimeout(() => { }, 0);

      //you could use a counter or a flag in order to stop getting the right width
      this.counter++;
    }

Hope it helps!希望能帮助到你! Feel free to comment随意评论

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM