吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 439|回复: 6
收起左侧

[其他原创] 一个基于 Javascript 实现的标签云动画实现原理和代码解析

[复制链接]
向善的灯 发表于 2024-12-22 16:36
本帖最后由 向善的灯 于 2024-12-24 22:51 编辑

在构建现代Web应用时,标签云(Tag Cloud)作为一种展示关键词重要性的可视化工具,广泛应用于博客、新闻网站等。标签云通过字体大小、颜色等视觉元素来展示标签的权重。ReactPress是一个基于Next.js的博客&CMS系统,本文将详细介绍ReactPress中标签云的实现原理,并解析其核心代码。
Kapture 2024-12-22 at 16.35.11.gif

在线预览地址:https://blog.gaoredu.com/

实现原理

ReactPress的标签云实现主要基于以下步骤和原理:

  1. 数据准备:首先,需要获取标签及其权重数据。这些数据通常来自数据库,每个标签包含一个名称和一个权重值。

  2. 初始化布局:根据标签的权重和数量,初始化标签在画布上的位置。标签可以均匀分布,也可以随机分布。

  3. 动画效果:使用CSS动画或JavaScript动画库(如GreenSock)来实现标签的浮动效果,增加用户交互性。

  4. 交互处理:当鼠标悬停在标签上时,标签会放大并突出显示,离开时恢复原位。

  5. 渲染更新:根据鼠标移动或用户交互,动态更新标签的位置和样式。

核心代码解析

以下代码是ReactPress标签云实现的核心部分,基于纯JavaScript和DOM操作。在实际项目中,这部分代码可以进一步封装为React组件。

interface TagParams {
  radius: number;
  d: number;
  dtr: number;
  distr: boolean;
  tSpeed: number;
  size: number;
}

class Tag {
  // 私有成员,用于存储HTML中的div元素
  private oDiv: HTMLDivElement;
  // 私有成员,用于存储所有<a>标签的HTMLCollection
  private aA = null;
  // 私有成员,用于存储计算过程中的sin和cos值
  private sa;
  private ca;
  private sb;
  private cb;
  private sc;
  private cc;

  // 保护成员,定义了一些常量,用于后续的动画和位置计算
  protected radius = 90; // 半径
  protected d = 200; // 距离常量
  protected dtr = Math.PI / 180; // 角度转弧度
  protected mcList = []; // 用于存储所有标签的元数据
  protected distr = true; // 分布模式,true为均匀分布,false为随机分布
  protected tSpeed = 11; // 动画速度
  protected size = 200; // 视图大小
  // 鼠标位置的初始值
  protected readonly mouseX = 0;
  protected readonly mouseY = 10;
  protected readonly howElliptical = 1; // 椭圆度

  constructor(params?: TagParams) {
    const { radius, d, dtr, distr, tSpeed, size } = params || {};
    this.radius = radius || this.radius;
    this.d = d || this.d;
    this.dtr = dtr || this.dtr;
    this.distr = distr || this.distr;
    this.tSpeed = tSpeed || this.tSpeed;
    this.size = size || this.size;
  }

  // 初始化容器
  private initContainer(container: HTMLDivElement | string) {
    if (this.oDiv) {
      this.oDiv = this.oDiv;
    } else if (container instanceof HTMLDivElement) {
      this.oDiv = container;
    } else {
      this.oDiv = document.querySelector(container);
    }
  }

  /**
   * 初始化方法,为所有<a>标签添加事件监听器,并初始化位置
   */
  public init = (container?: HTMLDivElement | string) => {
    let i = 0;
    let oTag = null;
    // 初始化
    this.initContainer(container);
    // 获取左右的标签
    this.aA = this.oDiv.getElementsByTagName('a');
    for (i = 0; i < this.aA.length; i++) {
      oTag = {};
      this.aA[i].onmouseover = (function (obj) {
        return function () {
          obj.on = true;
          this.style.zIndex = 9999;
          this.style.color = '#fff';
          this.style.padding = '5px 10px';
          this.style.filter = 'alpha(opacity=100)';
          this.style.opacity = 1;
        };
      })(oTag);
      this.aA[i].onmouseout = (function (obj) {
        return function () {
          obj.on = false;
          this.style.zIndex = obj.zIndex;
          this.style.color = '#fff';
          this.style.padding = '5px 8px';
          this.style.filter = 'alpha(opacity=' + 100 * obj.alpha + ')';
          this.style.opacity = obj.alpha;
          this.style.zIndex = obj.zIndex;
        };
      })(oTag);
      oTag.offsetWidth = this.aA[i].offsetWidth;
      oTag.offsetHeight = this.aA[i].offsetHeight;
      this.mcList.push(oTag);
    }
    this.sineCosine(0, 0, 0);
    this.positionAll();
    requestAnimationFrame(this.update);
  };

  // 动画更新方法
  private update = () => {
    // ...(省略部分代码,核心逻辑见下文)
  };

  // 根据分布模式初始化所有标签的位置
  private positionAll = () => {
    // ...(省略部分代码,核心逻辑见下文)
  };

  // 根据最新的位置数据更新标签的实际显示位置
  private doPosition = () => {
    // ...(省略部分代码,核心逻辑见下文)
  };

  // 计算sin和cos值的方法
  private sineCosine = (a, b, c) => {
    // ...(省略部分代码,核心逻辑见下文)
  };
}

export default Tag;
代码详解
  1. 类定义和初始化

    • Tag类定义了标签云的核心逻辑。
    • 构造函数接收一个可选的params对象,用于覆盖默认的参数设置。
  2. 容器初始化

    • initContainer方法用于初始化标签云的容器,可以是传入的DOM元素或选择器字符串。
  3. 初始化方法

    • init方法遍历容器内的所有<a>标签,为每个标签添加mouseovermouseout事件监听器,并初始化标签的元数据列表mcList
    • 调用sineCosine方法初始化sin和cos值,调用positionAll方法初始化标签位置,并使用requestAnimationFrame启动动画循环。
  4. 动画更新

    • update方法根据鼠标位置计算新的sin和cos值,更新每个标签的位置和样式,并使用requestAnimationFrame进行下一帧的渲染。
  5. 位置初始化

    • positionAll方法根据分布模式(均匀或随机)计算每个标签的三维坐标,并设置其初始位置。
  6. 位置更新

    • doPosition方法根据最新的三维坐标计算标签在二维平面上的位置,并更新其样式。
  7. sin和cos计算

    • sineCosine方法接收角度值,计算并存储sin和cos值,用于后续的位置和样式计算。
核心代码

目前核心代码已经开源:
https://github.com/fecommunity/reactpress/blob/master/client/src/components/TagCloud/tag.ts

总结

ReactPress的标签云实现通过纯JavaScript和DOM操作,实现了标签的初始化、位置计算和动画效果。这种实现方式虽然灵活,但在React项目中,更推荐将逻辑封装为React组件,利用React的状态管理和生命周期方法,实现更简洁和可维护的代码结构。

通过本文的介绍,希望读者能够理解标签云的实现原理,并能在此基础上进行自定义和优化,以适应不同的应用场景。

本帖被以下淘专辑推荐:

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

hbu126 发表于 2024-12-22 18:05
高手,多谢分享
songli28 发表于 2024-12-22 22:04
crystalZ 发表于 2024-12-22 23:08
backaxe 发表于 2024-12-23 08:32
效果还是不错的,用了AI吗?
 楼主| 向善的灯 发表于 2024-12-24 22:51
hbu126 发表于 2024-12-22 18:05
高手,多谢分享

感谢支持
xieyinghao 发表于 2024-12-25 10:09

感谢大佬分享,66666
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-12-27 23:50

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表