【问题标题】:The position of the elements do not remain the same compared to their previous placed position using getBoundingClientRect与之前使用 getBoundingClientRect 放置的位置相比,元素的位置不会保持不变
【发布时间】:2019-12-24 19:46:27
【问题描述】:

我将一些元素拖放到 div 上(包含背景图片)并上传内容。在上传之前,我计算放置的元素顶部,左侧位置 wrt 到父 div,以便顶部,左侧位置可用于将元素与背景图像一起呈现在不同屏幕上时完全相同的位置( png 或 jpeg) 被传递。但问题是元素的放置位置与其初始放置位置相比略有不同。

HTML 上传前

<div id="toget"
     class="dropzone"
     [ngStyle]="{'width':'100%',
                 'background-image': 'url('+urlFloorZoneIn+')',
                 'background-repeat': 'no-repeat',
                 'background-position': 'center',
                 'background-size': '100% 100%',
                 'border':'1px solid black',
                 'height':'340px',
                 'position': 'relative'}">

    <div class="box"
         *ngFor="let existingZone of existingDroppedItemZoneIn"
         [ngStyle] = "{'position': 'absolute' , 
                       'top.%':existingZone.spans[1], 
                       'left.%':existingZone.spans[0]}"
         (dragEnd)="onDragEnd($event,existingZone)">

          {{ existingZone.main }}
        <span>{{existingZone.spans[0]}}</span>
        <span>{{existingZone.spans[1]}}</span>

    </div>

</div>

计算左上角位置的TS代码

onDragEnd(event,b){


    const existingMovingBlockIndex = (this.existingDroppedItemZoneIn.indexOf(this.currentBox));
    if(existingMovingBlockIndex>-1){
        console.log(b)
        console.log(`got drag end x and y ${event.clientX} ${event.clientY}`)
        console.log(this.dr.onDragMove);

        const container_rect = this.parentparent.nativeElement.getBoundingClientRect();
        this.mouse.x = event.clientX - container_rect.left;
        this.mouse.y = event.clientY - container_rect.top;

        const{width,height} = this.parentparent.nativeElement.getBoundingClientRect();
        const perc_x = this.mouse.x / width * 100;
        const perc_y = this.mouse.y / height * 100;

        this.left = perc_x-5;
        this.topLeft = []
        this.topLeft.push(this.left);

        this.top = perc_y-5;
        this.topLeft.push(this.top);

        this.existingDroppedItemZoneIn[existingMovingBlockIndex].spans[0] = (perc_x);
        this.existingDroppedItemZoneIn[existingMovingBlockIndex].spans[1] = (perc_y);


    }
}

CSS

.box {
  width: 10%;
  height: 10%;
  background: rgba(254, 249, 247, 1);
  border: 1.5px solid #e24301;
  margin: 5px;
  line-height: 100px;
  text-align: center;
  font-size: 0.8rem;
}

.dropzone {
  padding: 20px;
  margin: 20px 0;
  background: lightgray;
  min-height: 200px;
  border: 1px solid black;
 }

在渲染之前,我获取上面上传的 HTML 内容的顶部、左侧、背景图像值,并应用 background-imagetopleft 渲染以下内容的值

在不同屏幕渲染后

[![在此处输入图片描述][2]][2]

<ul>
    <li #allFloors
       *ngFor="let floor of buildings.floors"
       [ngStyle]="{'width': singleFloorFlagStyle ?'40%':'100%',
                   'background-image': 'url('+floor.urlFloorZoneIn+')', 
                   'background-repeat': 'no-repeat',
                   'background-position': 'center',
                   'background-size': '100% 100%',
                   'border':'1px solid black',
                   'height': singleFloorFlagStyle ? '340px' : '700px', 
                   'position': 'relative', 'max-width': '80%'}"
                   [ngClass]="{'width':'80% !important'}">

            <span (click)="loadFloorInfo(floor._id)">{{ floor.name }}</span>
            <div class="fs-heatmap-wrapper__content__box"
                *ngFor="let existingZone of floor.droppeditem"
                [ngStyle]="{'position':'absolute',
                            'top.%': existingZone.spans[1],
                            'left.%': existingZone.spans[0]}">

                {{ existingZone.main }}
             </div>      
    </li>
</ul>

CSS

.fs-heatmap-wrapper {
display: grid;
*min-height: 800px;
&__content {
    padding: 70px 40px 0;
    min-height: 300px;
    ul {
        margin: 0;
        padding: 0;
        display: flex;
        flex-wrap: wrap;
        justify-content: center;
        li {
            list-style: none;
            min-width: 48%;
            margin: 12px;
            margin-bottom: 2.5%;
            span {
                cursor: pointer;
                background: #fff;
                text-align: left;
                font-weight: 800;
                font-size: 0.9rem;
                letter-spacing: 0.05rem;
                position: relative;
                top: -30px;
            }
        }
    }

&__box{
width: 100px;       
height: 100px;      
background: rgba(254, 249, 247, 1);     
border: 1.5px solid #e24301;        
margin: 5px;        
line-height: 100px;     
text-align: center;     
font-size: 0.8rem;

    }
  }        
}

【问题讨论】:

  • @kaiido 请有任何建议。
  • 不确定我说的是否正确,但我认为你会明白以这种方式进行调查的重点。 getboundingclientrect 是相对于窗口的,因为涉及到一些绝对定位,如果拖放区与渲染区不在窗口中的完全相同的位置,则被拖放的元素可能会出现在 dropzone 和渲染中的不同位置,而它仍然在窗口中的同一个地方。
  • 我会更新计算的 ts 代码,它将子元素放置在稍微不同的位置。
  • 我正在计算 dropzone 类 div 的顶部、左侧,所以我认为它应该完全位于相同的位置,但它与原始位置略有不同
  • w3schools.com/jsref/met_element_getboundingclientrect.asp 注意:计算边界矩形时会考虑视口区域的滚动量。这意味着每次滚动位置发生变化时,矩形的边缘(上、左、下和右)都会改变它们的值。

标签: javascript html css angular getboundingclientrect


【解决方案1】:

C - 可拖动元素,P - 拖放区父级

问题是您使用鼠标的指针位置来计算 C 相对于 P 的新位置,而 C 位置的实际事实来源是:

C.getBoundingClientRect().left - P.parent.getBoundingClientRect().left

鼠标指针可以放置在 C 上的任何位置。假设我通过将鼠标指向 C 的中心来开始拖动 C,因此您获得的 event.clientX 不是 C 相对于客户端开始渲染的更新位置但它是:

(clientPosition of C + (clientPosition of Mouse Pointer - clientPosition of C))

这绝对不是C的ClientPosition。

因此,仅使用第一个公式即可纠正您的位置。您可以为 Draggable Elements 分配 id,然后访问它们。

此外,在您的 Stackblitz 示例中,一旦 Drag 结束,您在 Dragged 元素上同时使用变换和位置,这也会添加到不正确的位置。使用其中之一。

【讨论】:

  • 第一个公式将为您提供正确的计算,但您不能在 transform 仍然存在的情况下使用它。您必须保留 transform 属性或 top, left 属性。此外,您的父 div 在您的 stackblitz 示例中也不是相对的。
  • 请参考更新后的stackblitz,stackblitz.com/edit/angular-5doank?file=src/app/…
  • 如果它是一个数组,则使用索引作为元素 ID 的唯一标识符。获取顶部和左侧 getBoundingClientRect 是最简单的方法。通过 document.getElementById 访问元素
【解决方案2】:

导致此问题的主要原因是您在 %. 中提供的 top 和 left 属性。与其将值转换为 %,不如尝试直接以像素为单位使用它们。

【讨论】:

  • 我认为 % 会给我更精细的粒度控制,因为在另一个屏幕中我会将框放置在 2 个不同大小的灰色 div 中,这就是我认为 % 会自动放置框与父灰色 div 大小无关
  • 嗯,没错。那么可能你应该检查那些父灰色 div 的宽度(我假设是带有 bg 图像的地板)。根据您的代码,地板的宽度是 80%,这是您在 ngClass 中指定的。如果你能分享代码会很酷
  • 我已经在帖子和stackblitz中提供的代码是stackblitz.com/edit/angular-7qfhdz?file=src/app/…
猜你喜欢
  • 2020-02-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-11-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多