You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Angular中悬停侧边展开div抖动问题求助

侧边展开Div悬停抖动问题修复

问题描述

需要实现侧边展开div的悬停交互:默认状态下div大部分隐藏在屏幕外,仅小部分露出;鼠标悬停露出区域时展开整个div,鼠标移出整个div区域时收起。当前实现存在抖动问题。

当前代码

component.ts

import { Component, Input, OnInit } from '@angular/core';
import { BookingRatingModel } from './booking-rating';

@Component({
  selector: 'app-booking-section',
  templateUrl: './booking-section.component.html',
  styleUrls: ['./booking-section.component.scss']
})
export class BookingSectionComponent implements OnInit {
  @Input() bookingRating: BookingRatingModel = new BookingRatingModel(10, 'Nie do opisania');

  constructor() { }

  ngOnInit(): void {
  }

  openDetails(){
    const rating = document.getElementById('rating');
    if(rating)
      rating.style.right = "28rem"
    const ratingDetails = document.getElementById('rating-details');
    if(ratingDetails)
      ratingDetails.style.right = "0"
  }

  closeDetails(){
    const rating = document.getElementById('rating');
    if(rating)
      rating.style.right = "0"
    const ratingDetails = document.getElementById('rating-details');
    if(ratingDetails)
      ratingDetails.style.right = "-28rem"
  }
}

component.html

<div 
    class="rating"
    id="rating"
    (mouseenter)='openDetails()'
    (mouseleave)='closeDetails()'>
    <div class="upper">
        <div class="title">{{"Sprawdź opinie" | uppercase}}</div>
    </div>
    <mat-icon class="icon">star</mat-icon>
    <div class="number">{{bookingRating.getNumber()}}</div>
</div>
<div 
    class="rating-details" 
    id="rating-details"
    (mouseleave)='closeDetails()'>
</div>

已尝试的无效方案

  • 移除rating元素上的closeDetails绑定,但div会始终保持展开状态;
  • 为动画添加0.3秒延迟,但鼠标在延迟期间移出时,div无法正常收起;
  • 替换为mouseover/mouseout事件,问题未解决且事件触发次数增加。

修复方案

抖动核心原因:两个div分别监听事件,展开时元素位置变化导致mouseleave被意外触发,进而反复调用展开/收起逻辑。

解决思路:用父容器包裹两个div,统一监听父容器的悬停事件;通过CSS类控制状态,配合过渡动画实现流畅交互,避免直接操作DOM样式。

修改后代码

component.ts

import { Component, Input, OnInit } from '@angular/core';
import { BookingRatingModel } from './booking-rating';

@Component({
  selector: 'app-booking-section',
  templateUrl: './booking-section.component.html',
  styleUrls: ['./booking-section.component.scss']
})
export class BookingSectionComponent implements OnInit {
  @Input() bookingRating: BookingRatingModel = new BookingRatingModel(10, 'Nie do opisania');
  isOpen = false;

  constructor() { }

  ngOnInit(): void {
  }

  toggleDetails(isOpen: boolean) {
    this.isOpen = isOpen;
  }
}

component.html

<div class="rating-container" 
     (mouseenter)="toggleDetails(true)" 
     (mouseleave)="toggleDetails(false)">
    <div class="rating" [class.expanded]="isOpen">
        <div class="upper">
            <div class="title">{{"Sprawdź opinie" | uppercase}}</div>
        </div>
        <mat-icon class="icon">star</mat-icon>
        <div class="number">{{bookingRating.getNumber()}}</div>
    </div>
    <div class="rating-details" [class.expanded]="isOpen">
        <!-- 详情内容 -->
    </div>
</div>

component.scss

.rating-container {
  position: fixed;
  right: 0;
  top: 50%;
  transform: translateY(-50%);
  display: flex;
  align-items: center;
}

.rating {
  position: relative;
  right: 0;
  transition: right 0.3s ease;
  /* 默认状态下仅小部分露出 */
  width: 6rem;
  padding: 1rem;
  background: #fff;
  cursor: pointer;
}

.rating.expanded {
  right: 28rem;
}

.rating-details {
  position: relative;
  right: -28rem;
  transition: right 0.3s ease;
  width: 28rem;
  padding: 1rem;
  background: #f5f5f5;
}

.rating-details.expanded {
  right: 0;
}

说明

  • 父容器rating-container统一管理悬停状态,避免元素移动导致的事件误触发;
  • 使用Angular属性绑定[class.expanded]控制状态,符合组件化开发规范;
  • CSS过渡动画确保展开/收起过程流畅,彻底消除抖动。

内容的提问来源于stack exchange,提问作者MuzealnaDotacja

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.27 04:13:23