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

如何开发可选中的jQuery气泡组件?求fcinq团队菜单同款实现方向

开发可选中的jQuery气泡组件(附fcinq团队气泡效果参考方向)

一、先拆解目标效果的核心特征

先捋清楚你提到的fcinq网站「Our Team」气泡效果的核心:一群承载团队成员信息的气泡,点击选中某一个时,该气泡放大并展开详情,其他气泡自动调整位置缩小,整体保持紧凑不重叠的布局,同时全程伴随平滑过渡动画。这类效果本质是「力导向布局(让气泡智能排列)」+「交互状态切换(选中/非选中的样式、尺寸变化)」的结合体。

二、开发步骤与关键实现点

1. 基础结构与样式准备

先搭好HTML骨架,每个气泡独立封装,默认只显示基础信息,选中后展示详情:

<div class="bubble-container">
  <div class="bubble" data-member-id="1">
    <div class="bubble-inner">
      <div class="bubble-avatar"><img src="avatar1.jpg" alt="Member 1"></div>
      <div class="bubble-name">John Doe</div>
      <div class="bubble-details" style="display:none;">
        <p>Senior Developer</p>
        <p>john@example.com</p>
      </div>
    </div>
  </div>
  <!-- 重复添加更多气泡元素 -->
</div>

基础CSS搞定默认样式、选中状态样式,以及过渡动画:

.bubble-container {
  position: relative;
  width: 100%;
  height: 600px;
  overflow: hidden;
}
.bubble {
  position: absolute;
  border-radius: 50%;
  background: #f5f5f5;
  cursor: pointer;
  transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  padding: 10px;
}
.bubble.selected {
  transform: scale(1.6);
  z-index: 10;
  background: #fff;
  box-shadow: 0 8px 32px rgba(0,0,0,0.15);
}
.bubble-details {
  position: absolute;
  bottom: -70px;
  left: 50%;
  transform: translateX(-50%);
  text-align: center;
  width: 220px;
  font-size: 14px;
}

2. 力导向布局实现(核心:让气泡自动排列不重叠)

原生jQuery没有内置布局算法,这里给你两种可行方案:

方案一:自己实现简易碰撞检测布局(纯jQuery)

适合气泡数量不多的场景,逻辑是随机初始化位置,然后循环检测重叠,推开重叠的气泡:

$(document).ready(function() {
  const $container = $('.bubble-container');
  const $bubbles = $('.bubble');
  const containerW = $container.width();
  const containerH = $container.height();
  const defaultSize = 80; // 默认气泡直径

  // 初始化随机位置
  $bubbles.each(function() {
    const x = Math.random() * (containerW - defaultSize);
    const y = Math.random() * (containerH - defaultSize);
    $(this).css({
      left: x,
      top: y,
      width: defaultSize,
      height: defaultSize
    });
  });

  // 碰撞检测与位置调整
  function fixCollisions() {
    let hasOverlap = false;
    $bubbles.each(function(i) {
      const $b1 = $(this);
      const pos1 = $b1.position();
      const r1 = $b1.width() / 2;
      const center1 = { x: pos1.left + r1, y: pos1.top + r1 };

      $bubbles.each(function(j) {
        if (i === j) return;
        const $b2 = $(this);
        const pos2 = $b2.position();
        const r2 = $b2.width() / 2;
        const center2 = { x: pos2.left + r2, y: pos2.top + r2 };

        // 计算两个气泡中心的距离
        const distance = Math.sqrt(Math.pow(center1.x - center2.x, 2) + Math.pow(center1.y - center2.y, 2));
        // 如果距离小于两个半径之和,说明重叠了
        if (distance < r1 + r2) {
          // 计算推开的角度,把气泡往反方向推
          const angle = Math.atan2(center1.y - center2.y, center1.x - center2.x);
          const newX = center2.x + (r1 + r2) * Math.cos(angle);
          const newY = center2.y + (r1 + r2) * Math.sin(angle);
          $b1.css({ left: newX - r1, top: newY - r1 });
          hasOverlap = true;
        }
      });
    });
    // 如果还有重叠,继续检测调整
    if (hasOverlap) setTimeout(fixCollisions, 60);
  }
  fixCollisions();
});

方案二:结合D3.js的力导向图(更专业,适合复杂场景)

如果你觉得自己写碰撞检测太麻烦,用D3的d3.forceSimulation能快速实现智能布局,再用jQuery绑定交互:

$(document).ready(function() {
  const $container = $('.bubble-container');
  const width = $container.width();
  const height = $container.height();

  // 准备成员数据
  const members = [
    { id: 1, name: 'John Doe', avatar: 'avatar1.jpg', role: 'Senior Developer', selected: false },
    { id: 2, name: 'Jane Smith', avatar: 'avatar2.jpg', role: 'UX Designer', selected: false },
    // 更多成员数据
  ];

  // 初始化D3力导向模拟
  const simulation = d3.forceSimulation(members)
    .force('charge', d3.forceManyBody().strength(-120)) // 气泡之间的排斥力,数值越小排斥越强
    .force('center', d3.forceCenter(width/2, height/2)) // 让整体布局居中
    .force('collision', d3.forceCollide().radius(d => d.selected ? 120 : 40)); // 碰撞检测半径,选中时更大

  // 绑定数据到DOM元素
  const bubbles = d3.select('.bubble-container')
    .selectAll('.bubble')
    .data(members)
    .enter()
    .append('div')
    .attr('class', 'bubble')
    .html(d => `
      <div class="bubble-inner">
        <div class="bubble-avatar"><img src="${d.avatar}" alt="${d.name}"></div>
        <div class="bubble-name">${d.name}</div>
        <div class="bubble-details" style="display:none;">
          <p>${d.role}</p>
        </div>
      </div>
    `);

  // 实时更新气泡位置
  simulation.on('tick', () => {
    bubbles.style('left', d => d.x - (d.selected ? 120 : 40) + 'px')
           .style('top', d => d.y - (d.selected ? 120 : 40) + 'px')
           .style('width', d => (d.selected ? 240 : 80) + 'px')
           .style('height', d => (d.selected ? 240 : 80) + 'px');
  });

  // 用jQuery绑定选中交互
  $('.bubble').on('click', function() {
    const $this = $(this);
    const memberData = d3.select(this).datum();

    // 取消所有气泡的选中状态
    members.forEach(m => m.selected = false);
    memberData.selected = true;

    // 更新样式与详情显示
    $('.bubble').removeClass('selected').find('.bubble-details').hide();
    $this.addClass('selected').find('.bubble-details').show();

    // 重启模拟,让布局重新调整
    simulation.alpha(0.6).restart();
  });
});

3. 选中交互的核心逻辑

不管用哪种布局方案,选中交互都要覆盖这几点:

  • 切换选中气泡的类名,放大尺寸并提升层级,突出显示
  • 显示当前气泡的详情,隐藏其他气泡的详情
  • 触发布局重新计算,让其他气泡自动避让,避免重叠
  • 靠CSS的transition属性实现平滑过渡,提升体验

4. 细节优化建议

  • 响应式适配:监听窗口resize事件,重新计算容器尺寸和布局
  • 初始加载动画:让气泡从中心位置扩散到目标位置,增强视觉吸引力
  • 键盘导航:支持Tab键切换选中气泡,提升无障碍访问性
  • 性能优化:气泡数量多时,限制碰撞检测频率,用requestAnimationFrame替代setTimeout

三、为什么没找到现成插件?

这类效果属于定制化较强的交互,通用插件很难完全匹配不同网站的细节需求(比如气泡内容、布局规则、选中后的展示逻辑)。所以基于基础布局算法+自定义交互逻辑,是实现这类效果最灵活的方式。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.21 06:29:56