js 动画库、2048核心逻辑、面试题add[1][2][3]+4

news2025/7/23 3:50:50

1、js 动画库 web animation api

(1)初始化代码

  • hmtl、css 部分
    • 初始化全局背景黑色
    • 初始化黄色小球
  • js 部分
    • 监听全局点击事件
    • 创建并添加元素 class="pointer" 的 div 标签
      • 设置 left、top 位置
      • 监听动画结束事件,移除该元素
    • 定位小球到画面中心
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <link rel="stylesheet" href="./css/js动画库.css">
</head>
<body>
  <div class="ball"></div>
  <script src="./js/js动画库.js"></script>
</body>
</html>
const ball = document.querySelector('.ball');

function init() {
  const x = window.innerWidth / 2;
  const y = window.innerHeight / 2;
  ball.style.transform = `translate(${x}px, ${y}px)`
}
init()
body {
  padding: 0;
  margin: 0;
  width: 100%;
  height: 100vh;
  background-color: #000;
}
.ball {
  width: 100px;
  height: 100px;
  background-color: yellow;
  border-radius: 50%;
}

 (2)实现步骤

①点击小球移动

animate():不改变 dom 树,因此不需要浏览器主线程管理,就不会阻塞主线程

window.addEventListener("click", (e) => {
  const x = e.clientX;
  const y = e.clientY;
  move(x, y);
});

function move(x, y) {
  ball.animate(
    [
      {
        transform: `translate(0px, 0px)`,
      },
      {
        transform: `translate(${x}px, ${y}px)`,
      }
    ],
    2000
  )
}

②小球不回到中心位置
ball.animate(
  [
    {
      transform: `translate(0px, 0px)`,
    },
    {
      transform: `translate(${x}px, ${y}px)`,
    }
  ],
  {
    duration: 1000,
    fill: 'forwards',
  }
)

③获取小球当前位置
function move(x, y) {
  // 获取小球位置
  const rect = ball.getBoundingClientRect();
  const ballX = rect.left;
  const ballY = rect.top;

  ball.animate(
    [
      {
        transform: `translate(${ballX}px, ${ballY}px)`,
      },
      {
        transform: `translate(${x}px, ${y}px)`,
      }
    ],
    {
      duration: 1000,
      fill: 'forwards',
    }
  )
}

④清除上一个动画
// 注意:只能在获取小球位置后清除
ball.getAnimations().forEach(animation=>{
  animation.cancel();
})
⑤小球先原地拉伸,后移动
ball.animate(
  [
    {
      transform: `translate(${ballX}px, ${ballY}px)`,
    },
    {
      transform: `translate(${ballX}px, ${ballY}px) scaleX(1.5)`,
      offset: 0.6, // 该部分动画所占时长
    },
    {
      transform: `translate(${x}px, ${y}px) scaleX(1.5)`,
      offset: 0.8,
    },
    {
      transform: `translate(${x}px, ${y}px)`,
    }
  ],
  {
    duration: 1000,
    fill: 'forwards',
  }
)

⑤拉伸角度跟随鼠标位置
const rad = Math.atan2(y - ballY, x - ballX);
const deg = (rad * 180) / Math.PI;
ball.animate(
  [
    {
      transform: `translate(${ballX}px, ${ballY}px) rotate(${deg}deg)`,
    },
    {
      transform: `translate(${ballX}px, ${ballY}px) rotate(${deg}deg) scaleX(1.5)`,
      offset: 0.6, // 该部分动画所占时长
    },
    {
      transform: `translate(${x}px, ${y}px) rotate(${deg}deg) scaleX(1.5)`,
      offset: 0.8,
    },
    {
      transform: `translate(${x}px, ${y}px) rotate(${deg}deg)`,
    }
  ],
  {
    duration: 1000,
    fill: 'forwards',
  }
)

(3)完整代码

const ball = document.querySelector(".ball");

function init() {
  const x = window.innerWidth / 2;
  const y = window.innerHeight / 2;
  ball.style.transform = `translate(${x}px, ${y}px)`;
}
init();

window.addEventListener("click", (e) => {
  const x = e.clientX;
  const y = e.clientY;
  move(x, y);
});

function move(x, y) {
  // 获取小球位置
  const rect = ball.getBoundingClientRect();
  const ballX = rect.left;
  const ballY = rect.top;
  // 注意:只能在获取小球位置后清除
  ball.getAnimations().forEach((animation)=>{
    animation.cancel();
  })
  const rad = Math.atan2(y - ballY, x - ballX);
  const deg = (rad * 180) / Math.PI;
  ball.animate(
    [
      {
        transform: `translate(${ballX}px, ${ballY}px) rotate(${deg}deg)`,
      },
      {
        transform: `translate(${ballX}px, ${ballY}px) rotate(${deg}deg) scaleX(1.5)`,
        offset: 0.6, // 该部分动画所占时长
      },
      {
        transform: `translate(${x}px, ${y}px) rotate(${deg}deg) scaleX(1.5)`,
        offset: 0.8,
      },
      {
        transform: `translate(${x}px, ${y}px) rotate(${deg}deg)`,
      }
    ],
    {
      duration: 1000,
      fill: 'forwards',
    }
  )
}

2、实现 2048 的核心逻辑——合并

Array.prototype.print = function () {
  console.log(this.join("\n"));
};

// 棋盘
const matrix = [
  [0, 2, 2, 0],
  [0, 0, 2, 2],
  [2, 4, 4, 2],
  [2, 4, 4, 4],
];

/**
 * 移动
 * @param {*} matrix 棋盘
 * @param {*} direction 方向
 */
function move(matrix, direction) {
  const rows = matrix.length;
  const cols = matrix[0].length;
  /**
   * 是否越界
   * @param {*} i
   * @param {*} j
   * @returns
   */
  function _inRange(i, j) {
    return i >= 0 && i < rows && j >= 0 && j < cols;
  }
  // 配置方向
  const nexts = {
    up: (i, j) => [i + 1, j],
    down: (i, j) => [i - 1, j],
    left: (i, j) => [i, j + 1],
    right: (i, j) => [i, j - 1],
  };
  /**
   * 下一个位置
   * @param {*} i
   * @param {*} j
   * @returns
   */
  function _nextPos(i, j) {
    const [ni, nj] = nexts[direction](i, j);
    if (!_inRange(ni, nj)) {
      return null;
    }
    return [ni, nj];
  }

  /**
   * 得到下一个非0的位置
   * @param {*} i
   * @param {*} j
   * @returns
   */
  function _nextNonZeroPos(i, j) {
    const pos = _nextPos(i, j);
    if (!pos) {
      return null;
    }
    const [ni, nj] = pos;
    if (matrix[ni][nj] !== 0) {
      return pos;
    }
    return _nextNonZeroPos(ni, nj); // 递归
  }

  /**
   * 计算某个位置最新的值,同时计算该行或该列所有的最新值
   * @param {*} i
   * @param {*} j
   */
  function _calc(i, j) {
    const pos = _nextNonZeroPos(i, j);
    if (!pos) {
      return;
    }
    const [ni, nj] = pos;
    const v = matrix[i][j]; // 当前位置值
    const nv = matrix[ni][nj]; // 下一个位置值
    if (v === 0) {
      matrix[i][j] = nv;
      matrix[ni][nj] = 0;
      _calc(i, j); // 递归
    } else if (v === nv) {
      matrix[i][j] *= 2;
      matrix[ni][nj] = 0;
    }
    const nextPos = _nextPos(i, j);
    _calc(...nextPos);
  }
  
  if(direction === 'up') {
    for (let i = 0; i < cols; i++) {
      _calc(0, i);
    }
  }
  if(direction === 'down') {
    for (let i = 0; i < cols; i++) {
      _calc(rows - 1, i);
    }
  }
  if(direction === 'left') {
    for (let i = 0; i < cols; i++) {
      _calc(i, 0);
    }
  }
  if(direction === 'right') {
    for (let i = 0; i < cols; i++) {
      _calc(i, cols - 1);
    }
  }
}

matrix.print();
move(matrix, "down");
console.log("======================");
matrix.print();

3、实现 add

让下面代码成立

const r1 = add[1][2][3] + 4; // 期望结果 10
const r2 = add[10][20] + 30; // 期望结果 60
const r3 = add[100][200][300] + 400; // 期望结果 1000

(1)实现思路

  • 从 add 的调用得出,add 是对象且属性是未知的
  • 如何读取未知属性对象呢?——完成一个代理辅助函数

(2)实现步骤

①读值
function createProxy() {
  return new Proxy(
    {},
    {
      get(target, prop) {
        console.log(prop);
      },
    }
  );
}

const add = createProxy();
add[100]; // 100
②返回值

步骤思路1:由 add[1][2][3] 可以看出返回值也必须是一个代理,这样在执行完 add[1] 后能继续执行后面的

const a1 = add[1];
const a2 = a1[2];
const a3 = a2[3];

步骤思路2:累计计算

以下代码报错的原因是 add[1] 是对象,而 2 是原始类型,二者无法相加

function createProxy(value = 0) {
  return new Proxy(
    {},
    {
      get(target, prop) {
        console.log(prop);
        return createProxy(value + Number(prop));
      },
    }
  );
}

const add = createProxy();
const a = add[1] + 2;
console.log(a); // 报错 TypeError: Cannot convert a Symbol value to a number

步骤思路3:对象转为原始类型

function createProxy(value = 0) {
  const handler = () => value;
  return new Proxy(
    {},
    {
      get(target, prop) {
        if(prop === Symbol.toPrimitive) {
          return handler;
        }
        return createProxy(value + Number(prop));
      },
    }
  );
}

const add = createProxy();
const a = add[1] + 2;
console.log(a); // 3
③完整代码-结果验证
function createProxy(value = 0) {
  const handler = () => value;
  return new Proxy(
    {},
    {
      get(target, prop) {
        if(prop === Symbol.toPrimitive) {
          return handler;
        }
        return createProxy(value + Number(prop));
      },
    }
  );
}

// 实现add
const add = createProxy();
// 让下面代码成立
const r1 = add[1][2][3] + 4; // 期望结果 10
const r2 = add[10][20] + 30; // 期望结果 60
const r3 = add[100][200][300] + 400; // 期望结果 1000
console.log(r1); // 10
console.log(r2); // 60
console.log(r3); // 1000

4、Sass 星空

(1)初始化代码

注意:html 引入的是 css 文件

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <link rel="stylesheet" href="./css/Sass星空.css">
</head>
<body>
  <div class="layer1"></div>
  <div class="layer2"></div>
  <div class="layer3"></div>
  <div class="layer4"></div>
  <div class="layer5"></div>
  <div class="title">Sass 星空</div>
</body>
</html>

编写的 css 是在 scss 文件中,后续再通过编译生成对应的 css 文件即可

body {
  padding: 0;
  margin: 0;
  background-color: #10141A;
}

.title {
  font-size: 40px;
  background: linear-gradient(to top, #000 0%, #fff 100%);
  -webkit-background-clip: text;
  background-clip: text;
  -webkit-text-fill-color: transparent;
  color: transparent;
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
}

(2)实现步骤

①用 函数+阴影 实现 n 个随机星星
@function star($n) {
  $result: '#{random(100)}vw #{random(100)}vh 0 #fff';
  @for $i from 2 through $n {
    $result: '#{$result},#{random(100)}vw #{random(100)}vh 0 #fff'
  }
  @return unquote($result);
}

.layer1 {
  position: fixed;
  width: 20px;
  height: 20px;
  border-radius: 50%;
  box-shadow: star(100);
}

 

②scss 编译成 css
  • 在 scss 文件目录中下载 sass
  • npm install sass
  • 执行编译命令
  • sass Sass星空.scss Sass星空.css
③让星星动起来
.layer1 {
  position: fixed;
  width: 20px;
  height: 20px;
  border-radius: 50%;
  box-shadow: star(100);
  animation: moveUp 10s linear infinite;
}
@keyframes moveUp {
  to {
    transform: translateY((-100vh));
  }
}

④断层无感处理
.layer1 {
  position: fixed;
  width: 20px;
  height: 20px;
  left: 0;
  top: 0;
  border-radius: 50%;
  box-shadow: star(100);
  animation: moveUp 10s linear infinite;
}
.layer1::after {
  content: '';
  position: inherit;
  width: inherit;
  height: inherit;
  border-radius: inherit;
  box-shadow: inherit;
  left: 0;
  top: 100vh;
}

⑤循环多层
$n: 5;
$duration: 400s;
$count: 1000;
@for $i from 1 through $n {
  $duration: floor($duration / 2);
  $count: floor($count / 2);
  .layer#{$i} {
    position: fixed;
    width: #{$i}px;
    height: #{$i}px;
    left: 0;
    top: 0;
    border-radius: 50%;
    box-shadow: star($count);
    animation: moveUp $duration linear infinite;
  }
  .layer#{$i}::after {
    content: '';
    position: inherit;
    width: inherit;
    height: inherit;
    border-radius: inherit;
    box-shadow: inherit;
    left: 0;
    top: 100vh;
  }
}

(3)完整代码

body {
  padding: 0;
  margin: 0;
  width: 100%;
  height: 100vh;
  background-color: #10141A;
}

.title {
  font-size: 40px;
  background: linear-gradient(to top, #000 0%, #fff 100%);
  -webkit-background-clip: text;
  background-clip: text;
  -webkit-text-fill-color: transparent;
  color: transparent;
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
}

@function star($n) {
  $result: '#{random(100)}vw #{random(100)}vh 0 #fff';
  @for $i from 2 through $n {
    $result: '#{$result},#{random(100)}vw #{random(100)}vh 0 #fff'
  }
  @return unquote($result);
}

$n: 5;
$duration: 400s;
$count: 1000;
@for $i from 1 through $n {
  $duration: floor($duration / 2);
  $count: floor($count / 2);
  .layer#{$i} {
    position: fixed;
    width: #{$i}px;
    height: #{$i}px;
    left: 0;
    top: 0;
    border-radius: 50%;
    box-shadow: star($count);
    animation: moveUp $duration linear infinite;
  }
  .layer#{$i}::after {
    content: '';
    position: inherit;
    width: inherit;
    height: inherit;
    border-radius: inherit;
    box-shadow: inherit;
    left: 0;
    top: 100vh;
  }
}

@keyframes moveUp {
  to {
    transform: translateY((-100vh));
  }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2397530.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

华为OD机试真题——书籍叠放(2025B卷:200分)Java/python/JavaScript/C/C++/GO最佳实现

2025 B卷 200分 题型 本专栏内全部题目均提供Java、python、JavaScript、C、C++、GO六种语言的最佳实现方式; 并且每种语言均涵盖详细的问题分析、解题思路、代码实现、代码详解、3个测试用例以及综合分析; 本文收录于专栏:《2025华为OD真题目录+全流程解析+备考攻略+经验分…

PyTorch-Transforms的使用(二)

对图像进行处理 安装open cv ctrlP 看用法 ToTensor的使用 常见的Transforms 归一化的图片 两个长度为三的数组&#xff0c;分别表示三个通道的平均值和标准差 Resize&#xff08;&#xff09; Compose&#xff08;&#xff09; 合并执行功能&#xff0c;输入进去一个列表&a…

Pytorch知识点2

Pytorch知识点 1、官方教程2、张量&#x1f9f1; 0、数组概念&#x1f9f1; 1. 创建张量&#x1f4d0; 2. 张量形状与维度&#x1f522; 3. 张量数据类型➗ 4. 张量的数学与逻辑操作&#x1f504; 5. 张量的就地操作&#x1f4e6; 6. 复制张量&#x1f680; 7. 将张量移动到加速…

AWS API Gateway 配置WAF(中国区)

问题 需要给AWS API Gateway配置WAF。 AWS WAF设置 打开AWS WAF首页&#xff0c;开始创建和配置WAF&#xff0c;如下图&#xff1a; 设置web acl名称&#xff0c;然后开始添加aws相关资源&#xff0c;如下图&#xff1a; 选择资源类型&#xff0c;但是&#xff0c;我这里出…

【前端面经】百度一面

写在前面&#xff1a;面经只是记录博主遇到的题目。每题的答案在编写文档的时候已经有问过deepseek&#xff0c;它只是一种比较普世的答案&#xff0c;要学得深入还是靠自己 Q&#xff1a; <html><style>.a {background-color: red;width: 200px;height: 100px;}…

[免费]微信小程序网上花店系统(SpringBoot后端+Vue管理端)【论文+源码+SQL脚本】

大家好&#xff0c;我是java1234_小锋老师&#xff0c;看到一个不错的微信小程序网上花店系统(SpringBoot后端Vue管理端)【论文源码SQL脚本】&#xff0c;分享下哈。 项目视频演示 【免费】微信小程序网上花店系统(SpringBoot后端Vue管理端) Java毕业设计_哔哩哔哩_bilibili 项…

css使用scoped之后样式失效问题

项目中的vue代码原本用的style标签来写css&#xff0c;现在想改成<style langscss scoped>&#xff0c;但是改完之后发现样式不对&#xff1a; 原来是&#xff1a; 将style改成scoped之后变成了&#xff1a;检查发现是之前定义的一些变量无法被识别&#xff0c;导致这些样…

【NLP】将 LangChain 与模型上下文协议 (MCP) 结合使用

&#x1f50e;大家好&#xff0c;我是Sonhhxg_柒&#xff0c;希望你看完之后&#xff0c;能对你有所帮助&#xff0c;不足请指正&#xff01;共同学习交流&#x1f50e; &#x1f4dd;个人主页&#xff0d;Sonhhxg_柒的博客_CSDN博客 &#x1f4c3; &#x1f381;欢迎各位→点赞…

使用NMEA Tools生成GPS轨迹图

前言 在现代科技快速发展的时代&#xff0c;GPS定位技术已经广泛应用于各种领域&#xff0c;如导航、物流、运动追踪等。为了获取和分析GPS数据&#xff0c;我们常常需要使用一些专业的工具。本文将详细介绍如何使用一款名为“NMEA Tools”的APK应用&#xff0c;结合GPSVisual…

1. pytorch手写数字预测

1. pytorch手写数字预测 1.背景2.准备数据集2.定义模型3.dataloader和训练4.训练模型5.测试模型6.保存模型 1.背景 因为自身的研究方向是多模态目标跟踪&#xff0c;突然对其他的视觉方向产生了兴趣&#xff0c;所以心血来潮的回到最经典的视觉任务手写数字预测上来&#xff0…

AXI 协议补充(二)

axi协议存在slave 和master 之间的数据交互,在ahb ,axi-stream 高速接口 ,叠加大位宽代码逻辑中,往往有时序问题,valid 和ready 的组合电路中的问题引发的时序问题较多。 本文根据axi 协议和现有解决反压造成的时序问题的方法做一个详细的科普。 1. 解决时序问题的方法:…

Linux 基础指令入门指南:解锁命令行的实用密码

文章目录 引言&#xff1a;Linux 下基本指令常用选项ls 指令pwd 命令cd 指令touch 指令mkdir 指令rmdir 指令 && rm 指令man 指令cp 指令mv 指令cat 指令more 指令less 指令head 指令tail 指令date 指令cal 指令find 指令按文件名搜索按文件大小搜索按修改时间搜索按文…

标准精读:2025 《可信数据空间 技术架构》【附全文阅读】

《可信数据空间 技术架构》规范了可信数据空间的技术架构,明确其作为国家数据基础设施的定位,以数字合约和使用控制技术为核心,涵盖功能架构(含服务平台与接入连接器的身份管理、目录管理、数字合约管理等功能)、业务流程(登记、发现、创建空间及数据流通利用)及安全要求…

山东大学软件学院项目实训-基于大模型的模拟面试系统-面试官和面试记录的分享功能(2)

本文记录在发布文章时&#xff0c;可以添加自己创建的面试官和面试记录到文章中这一功能的实现。 前端 首先是在原本的界面的底部添加了两个多选框&#xff08;后期需要美化调整&#xff09; 实现的代码&#xff1a; <el-col style"margin-top: 1rem;"><e…

Webug4.0靶场通关笔记05- 第5关SQL注入之过滤关键字

目录 一、代码审计 1、源码分析 2、SQL注入分析 &#xff08;1&#xff09;大小写绕过 &#xff08;2&#xff09;双写绕过 二、第05关 过滤型注入 1、进入靶场 2、sqlmap渗透 &#xff08;1&#xff09;bp抓包保存报文 &#xff08;2&#xff09;sqlmap渗透 &…

ONLYOFFICE文档API:更强的安全功能

在数字化办公时代&#xff0c;文档的安全性与隐私保护已成为企业和个人用户的核心关切。如何确保信息在存储、传输及协作过程中的安全&#xff0c;是开发者与IT管理者亟需解决的问题。ONLYOFFICE作为一款功能强大的开源办公套件&#xff0c;不仅提供了高效的文档编辑与协作体验…

解析楼宇自控系统:分布式结构的核心特点与优势展现

在建筑智能化发展的进程中&#xff0c;楼宇自控系统作为实现建筑高效运行与管理的关键&#xff0c;其系统结构的选择至关重要。传统的集中式楼宇自控系统在面对日益复杂的建筑环境和多样化的管理需求时&#xff0c;逐渐暴露出诸多弊端&#xff0c;如可靠性低、扩展性差、响应速…

C#数字图像处理(三)

文章目录 前言1.图像平移1.1 图像平移定义1.2 图像平移编程实例 2.图像镜像2.1 图像镜像定义2.2 图像镜像编程实例 3.图像缩放3.1 图像缩放定义3.2 灰度插值法3.3 图像缩放编程实例 4.图像旋转4.1 图像旋转定义4.2 图像旋转编程实例 前言 在某种意义上来说&#xff0c;图像的几…

SQL Transactions(事务)、隔离机制

目录 Why Transactions? Example: Bad Interaction Transactions ACID Transactions COMMIT ROLLBACK How the Transaction Log Works How Data Is Stored Example: Interacting Processes Interleaving of Statements Example: Strange Interleaving Fixing the…

【机器学习基础】机器学习入门核心:Jaccard相似度 (Jaccard Index) 和 Pearson相似度 (Pearson Correlation)

机器学习入门核心&#xff1a;Jaccard相似度 &#xff08;Jaccard Index&#xff09; 和 Pearson相似度 &#xff08;Pearson Correlation&#xff09; 一、算法逻辑Jaccard相似度 (Jaccard Index)**Pearson相似度 (Pearson Correlation)** 二、算法原理与数学推导1. Jaccard相…