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

Angular实现主圆周围环绕8个可填充图文小圆的布局方法

Angular 中心主圆+周边8个小圆布局实现方案

你当前硬编码每个小圆偏移值的方案本质是把动态计算的结果写死成了固定像素,一旦主圆尺寸、小圆尺寸、间距发生变化,所有类的定位值都要重写,且小圆内填充内容尺寸变化时很容易出现错位。推荐用极坐标动态计算+Angular样式绑定的方案实现,不需要手动维护每个小圆的位置,灵活性和适配性完全满足需求。

核心原理

  • 以主圆的圆心为坐标原点,8个小圆均匀分布在和主圆同心的圆周上,相邻小圆夹角固定为45°(360°/8)
  • 通过三角函数自动计算每个小圆相对于圆心的x/y轴偏移量,自动生成定位坐标,不需要单独为每个小圆写定位类
  • 把主圆尺寸、小圆尺寸、圆间距做成可配置输入参数,修改参数时所有位置自动重算
  • 通过内容投影开放主圆和每个小圆的内容插槽,支持放置文本、图片、任意自定义组件

具体实现

1. 组件TypeScript逻辑

import { Component, Input } from '@angular/core';

@Component({
  selector: 'app-circle-surround-layout',
  templateUrl: './circle-surround-layout.component.html',
  styleUrls: ['./circle-surround-layout.component.css']
})
export class CircleSurroundLayoutComponent {
  // 可配置项,按需传入即可
  @Input() mainCircleDiameter = 150; // 主圆直径,单位px
  @Input() subCircleDiameter = 50; // 小圆直径,单位px
  @Input() circleGap = 10; // 主圆和小圆的间距,单位px
  @Input() mainCircleBg = '#2563eb';
  @Input() subCircleBg = '#ef4444';

  // 8个小圆对应的角度值,从0°开始每45°一个
  readonly subCircleAngles = Array.from({length: 8}, (_, idx) => idx * 45);

  // 计算主圆动态样式
  get mainCircleStyle() {
    return {
      width: `${this.mainCircleDiameter}px`,
      height: `${this.mainCircleDiameter}px`,
      borderRadius: '50%',
      backgroundColor: this.mainCircleBg,
      position: 'relative' as const,
      margin: '100px',
      display: 'flex',
      alignItems: 'center',
      justifyContent: 'center'
    };
  }

  // 计算每个小圆的定位样式
  getSubCircleStyle(angle: number) {
    // 圆周半径 = 主圆半径 + 间距 + 小圆半径,即小圆中心到主圆中心的距离
    const layoutRadius = (this.mainCircleDiameter / 2) + this.circleGap + (this.subCircleDiameter / 2);
    // 角度转弧度,JS三角函数默认0°指向正右方,偏移-90°让第一个小圆显示在正上方
    const radian = (angle - 90) * Math.PI / 180;
    // 计算偏移量,减去小圆半径一半让小圆中心和计算坐标点对齐
    const offsetX = layoutRadius * Math.cos(radian) - (this.subCircleDiameter / 2);
    const offsetY = layoutRadius * Math.sin(radian) - (this.subCircleDiameter / 2);

    return {
      width: `${this.subCircleDiameter}px`,
      height: `${this.subCircleDiameter}px`,
      borderRadius: '50%',
      backgroundColor: this.subCircleBg,
      position: 'absolute' as const,
      left: `calc(50% + ${offsetX}px)`,
      top: `calc(50% + ${offsetY}px)`,
      display: 'flex',
      alignItems: 'center',
      justifyContent: 'center',
      overflow: 'hidden'
    };
  }
}

2. 组件HTML模板

<div [ngStyle]="mainCircleStyle">
  <!-- 主圆内容插槽 -->
  <ng-content select="[mainContent]"></ng-content>

  <!-- 循环渲染所有小圆 -->
  <div 
    *ngFor="let angle of subCircleAngles; let i = index"
    [ngStyle]="getSubCircleStyle(angle)"
  >
    <!-- 每个小圆对应独立内容插槽 -->
    <ng-content [select]="'[subContent' + i + ']'"></ng-content>
  </div>
</div>

3. 组件CSS

不需要写任何定位相关的硬编码样式,只需要保留组件基础显示设置:

:host {
  display: block;
}

组件调用示例

在业务页面直接引入组件,传入配置参数,填充自定义内容即可:

<app-circle-surround-layout
  [mainCircleDiameter]="200"
  [subCircleDiameter]="60"
  [circleGap]="15"
  mainCircleBg="#165DFF"
  subCircleBg="#FF7D00"
>
  <!-- 主圆自定义内容 -->
  <div mainContent class="text-white font-bold">
    中心主圆<br>支持任意内容
  </div>

  <!-- 按顺序填充0-7号小圆的内容,顺序为正上方顺时针排列 -->
  <div subContent0>1</div>
  <img subContent1 src="assets/star.png" alt="星级图标">
  <div subContent2>选项3</div>
  <div subContent3>4</div>
  <div subContent4>5</div>
  <div subContent5>6</div>
  <div subContent6>7</div>
  <div subContent7>8</div>
</app-circle-surround-layout>

方案优势

  • 零硬编码定位:不需要手动给每个小圆写top/left偏移,调整尺寸、间距仅需修改传入的配置参数,所有位置自动计算
  • 适配性强:小圆内置flex居中布局,不管放文本、图片还是复杂组件,都不会出现内容错位
  • 易扩展:后续如果需要调整小圆数量(比如改为6个、12个环绕),仅需修改subCircleAngles的生成逻辑,其余代码不需要改动
  • 易交互:需要加hover放大、选中高亮、旋转动画等效果时,直接在动态样式里加对应CSS属性即可,不影响定位逻辑

如果需要做响应式适配,只需要把尺寸参数绑定到页面resize监听的返回值上,即可实现窗口大小变化时布局自动缩放。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.26 13:27:19