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

AngularJS中实现上下字段点击配对并绘制连接线的方法

AngularJS实现上下字段点击配对连线

实现思路

用AngularJS管理选中状态与配对数据,借助SVG绘制连线(SVG支持坐标计算与动态元素添加,适合这类连线场景)。核心逻辑是:

  • 记录首次点击的字段(上方/下方)
  • 第二次点击对应区域字段时,建立配对关系
  • 基于两个字段的DOM坐标计算连线起点与终点,动态生成SVG连线

完整代码实现

HTML结构

<div ng-app="matchApp" ng-controller="MatchController">
  <!-- 上方字段容器 -->
  <div class="field-container top-container">
    <div class="field" 
         ng-repeat="field in topFields" 
         ng-click="selectField(field, 'top')"
         ng-class="{'selected': field.selected, 'matched': field.matched}">
      {{field.name}}
    </div>
  </div>

  <!-- SVG连线容器,绝对定位覆盖在上下容器之间 -->
  <svg class="connection-svg"></svg>

  <!-- 下方字段容器 -->
  <div class="field-container bottom-container">
    <div class="field" 
         ng-repeat="field in bottomFields" 
         ng-click="selectField(field, 'bottom')"
         ng-class="{'selected': field.selected, 'matched': field.matched}">
      {{field.name}}
    </div>
  </div>
</div>

AngularJS控制器

angular.module('matchApp', [])
.controller('MatchController', ['$scope', '$document', function($scope, $document) {
  // 初始化上下各10个字段
  $scope.topFields = Array.from({length:10}, (_,i) => ({id: `top-${i+1}`, name: `上方字段${i+1}`, selected: false, matched: false}));
  $scope.bottomFields = Array.from({length:10}, (_,i) => ({id: `bottom-${i+1}`, name: `下方字段${i+1}`, selected: false, matched: false}));

  let selectedField = null; // 存储首次选中的字段
  const svg = $document[0].querySelector('.connection-svg');

  // 字段点击事件
  $scope.selectField = function(field, type) {
    // 如果字段已配对,不响应点击
    if (field.matched) return;

    // 首次选中字段
    if (!selectedField) {
      field.selected = true;
      selectedField = {field, type};
      return;
    }

    // 点击同区域字段,切换选中状态
    if (selectedField.type === type) {
      selectedField.field.selected = false;
      field.selected = true;
      selectedField = {field, type};
      return;
    }

    // 跨区域选中,建立配对
    selectedField.field.selected = false;
    field.selected = false;
    selectedField.field.matched = true;
    field.matched = true;

    // 计算连线坐标并绘制
    drawConnection(selectedField.field.id, field.id);
    selectedField = null;
  };

  // 绘制连线函数
  function drawConnection(topId, bottomId) {
    const topEl = $document[0].querySelector(`[ng-repeat="field in topFields"]:nth-child(${topId.split('-')[1]})`);
    const bottomEl = $document[0].querySelector(`[ng-repeat="field in bottomFields"]:nth-child(${bottomId.split('-')[1]})`);
    
    // 获取元素中心坐标
    const topRect = topEl.getBoundingClientRect();
    const bottomRect = bottomEl.getBoundingClientRect();
    const svgRect = svg.getBoundingClientRect();

    const startX = topRect.left + topRect.width/2 - svgRect.left;
    const startY = topRect.bottom - svgRect.top;
    const endX = bottomRect.left + bottomRect.width/2 - svgRect.left;
    const endY = bottomRect.top - svgRect.top;

    // 创建SVG连线元素
    const line = $document[0].createElementNS('http://www.w3.org/2000/svg', 'line');
    line.setAttribute('x1', startX);
    line.setAttribute('y1', startY);
    line.setAttribute('x2', endX);
    line.setAttribute('y2', endY);
    line.setAttribute('stroke', '#2196F3');
    line.setAttribute('stroke-width', 2);
    svg.appendChild(line);
  }
}]);

CSS样式

.field-container {
  display: flex;
  justify-content: space-around;
  padding: 20px;
  margin-bottom: 80px; /* 给SVG留空间 */
}

.bottom-container {
  margin-top: 80px;
}

.field {
  padding: 10px 20px;
  border: 1px solid #ddd;
  border-radius: 4px;
  cursor: pointer;
  transition: all 0.3s;
}

.field.selected {
  background-color: #E3F2FD;
  border-color: #2196F3;
}

.field.matched {
  background-color: #C8E6C9;
  border-color: #4CAF50;
  cursor: not-allowed;
}

.connection-svg {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  pointer-events: none; /* 不影响字段点击 */
  z-index: -1;
}

关键说明

  1. 状态管理:通过selected(选中状态)和matched(已配对状态)两个属性控制字段样式与交互逻辑,避免重复配对。
  2. 坐标计算:利用getBoundingClientRect()获取字段的位置信息,转换为SVG内部坐标后绘制连线。
  3. SVG层级:设置pointer-events: none确保SVG不会干扰字段的点击事件,同时用绝对定位覆盖整个页面,保证连线能在任意位置绘制。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.15 16:32:42