对于红包雨动画的红包有些总是超出屏幕问题的解决

下面是整体问题的过程,最下面会附带源码.

问:

// 开启红包雨
const openRain = () => {
  console.log('点击了openRain');
  const hongbaos = Array.from({ length: 20 }); // 创建具有指定长度的数组
  const maxLeft = document.body.offsetWidth - 40;
  
  // 获取app元素节点
  // const appWidth = document.getElementById('app');
  // const maxLeft = appWidth.offsetWidth - 50;
  
  console.log(maxLeft,'maxLeft')

  // 添加遮罩层
  addOverlay();

  // 创建容器元素
  const container = document.createElement('div');
  container.className = 'container';

  for (let i = 0; i < hongbaos.length; i++) {
    const img = document.createElement('img');
    img.src = './hongbao.png';
    img.className = 'img';
    img.style.left = `${Math.random() * maxLeft}px`;
    img.style.animationDuration = `${Math.random() * 2 + 2}s`;
    img.style.animationDelay = `${i * 0.5}s`; // 设置不同的延迟时间
    container.appendChild(img);
  }

  // 在项目body节点上挂载container红包雨
  document.body.appendChild(container);这段代码怎么实现降红包雨的范围控制在app节点的宽度中

回答:

你可以先获取到 app 元素节点,然后再根据它的宽度来设置红包雨的范围。修改代码如下:

```
const openRain = () => {
  console.log('点击了openRain');
  const hongbaos = Array.from({ length: 20 }); // 创建具有指定长度的数组
  const appWidth = document.getElementById('app').offsetWidth - 50;
  const maxLeft = appWidth > 0 ? appWidth : document.body.offsetWidth - 40;
  
  console.log(maxLeft,'maxLeft')

  // 添加遮罩层
  addOverlay();

  // 创建容器元素
  const container = document.createElement('div');
  container.className = 'container';

  for (let i = 0; i < hongbaos.length; i++) {
    const img = document.createElement('img');
    img.src = './hongbao.png';
    img.className = 'img';
    img.style.left = `${Math.random() * maxLeft}px`;
    img.style.animationDuration = `${Math.random() * 2 + 2}s`;
    img.style.animationDelay = `${i * 0.5}s`; // 设置不同的延迟时间
    container.appendChild(img);
  }

  // 在项目body节点上挂载container红包雨
  document.body.appendChild(container);
}
```

这样,如果获取到了 app 元素节点,就会根据它的宽度来设置红包雨的范围;否则就使用默认值。

问:

Math.random()是什么代码?

回答:

`Math.random()` 是 JavaScript 中的一个函数,作用是返回一个大于等于 0 且小于 1 的伪随机数。也就是说,它可以用来生成一个随机的小数。

在本例中,我们使用 `Math.random()` 来生成每个红包的随机位置和动画时长。例如,`img.style.left = `${Math.random() * maxLeft}px`'` 这行代码会将红包的 `left` 样式设置为一个随机值,这个随机值由 `Math.random()` 生成并乘以一个最大值(即红包雨的范围),单位是像素。这样就能让红包以随机的位置出现在屏幕上,并处于不同的运动状态。

问:

// 开启红包雨
const openRain = () => {
  console.log('点击了openRain');
  const hongbaos = Array.from({ length: 20 }); // 创建具有指定长度的数组
  // const maxLeft = document.body.offsetWidth - 40;
  
  // 获取app元素节点
  const appWidth = document.getElementById('app').offsetWidth;
  const maxLeft = appWidth > 0 ? appWidth : document.body.offsetWidth - 40;
  
  console.log(maxLeft,'maxLeft')

  // 添加遮罩层
  addOverlay();

  // 创建容器元素
  const container = document.createElement('div');
  container.className = 'container';

  for (let i = 0; i < hongbaos.length; i++) {
    const img = document.createElement('img');
    img.src = './hongbao.png';
    img.className = 'img';
    img.style.left = `${Math.random() * maxLeft}px`;
    img.style.animationDuration = `${Math.random() * 2 + 2}s`;
    img.style.animationDelay = `${i * 0.5}s`; // 设置不同的延迟时间
    container.appendChild(img);
  }为什么我代码中计算了const maxLeft = appWidth > 0 ? appWidth : document.body.offsetWidth - 40;获取到了maxLeft的宽度是app的宽度,当app宽度是375的时候有的图片宽度比这个数还要大是为什么导致的?

回答:

根据你提供的代码,获取 `maxLeft` 的宽度是通过判断 `appWidth` 是否大于0来确定的。如果 `appWidth` 大于0,则使用 `appWidth` 作为 `maxLeft` 的值;否则使用 `document.body.offsetWidth - 40` 作为 `maxLeft` 的值。

如果你发现有些图片的宽度比 `appWidth` 还要大,可能是因为图片的实际宽度超过了容器的宽度,导致图片显示不完整。

你可以尝试调整容器的宽度或者采用其他方式来确保图片能够完整显示。例如,可以将容器的宽度设置为适应图片的宽度,或者使用 `object-fit` 属性来控制图片的缩放和裁剪方式。

另外,你也可以在开发者工具中检查元素的盒模型,以确定图片的实际宽度和容器的宽度是否匹配。

问:

是的,确实是这个原因,我计算maxLeft的时候直接使用了appWidth的宽度,应该将图片的宽度减去,才能实现在app内部展示红包雨,请问怎么做才能实现

回答:

要确保红包雨在 `app` 容器内部展示,并且不超出容器的边界,你可以按照以下步骤进行操作:

1. 获取 `app` 元素节点的宽度。
2. 获取红包图片的宽度。
3. 计算 `maxLeft = appWidth - 红包图片宽度`,确保红包不会超出容器的右边界。
4. 在循环创建红包元素时,将 `img.style.left` 的值设置为 `Math.random() * maxLeft + 'px'`。

下面是修改后的代码示例:

```javascript
const openRain = () => {
  console.log('点击了openRain');
  const hongbaos = Array.from({ length: 20 }); // 创建具有指定长度的数组
  
  // 获取 app 元素节点的宽度
  const appWidth = document.getElementById('app').offsetWidth;
  
  // 获取红包图片的宽度
  const hongbaoWidth = document.getElementById('hongbao').offsetWidth;
  
  // 计算 maxLeft
  const maxLeft = appWidth - hongbaoWidth;
  
  console.log(maxLeft, 'maxLeft');

  // 添加遮罩层
  addOverlay();

  // 创建容器元素
  const container = document.createElement('div');
  container.className = 'container';

  for (let i = 0; i < hongbaos.length; i++) {
    const img = document.createElement('img');
    img.src = './hongbao.png';
    img.id = 'hongbao'; // 给红包图片设置一个 ID
    img.className = 'img';
    img.style.left = `${Math.random() * maxLeft}px`;
    img.style.animationDuration = `${Math.random() * 2 + 2}s`;
    img.style.animationDelay = `${i * 0.5}s`; // 设置不同的延迟时间
    container.appendChild(img);
  }

  // 在项目 body 节点上挂载 container 红包雨
  document.body.appendChild(container);
}
```

请注意,为了获取红包图片的宽度,我们给红包图片元素设置了一个唯一的 ID (`hongbao`),并通过 `document.getElementById('hongbao').offsetWidth` 来获取其宽度。确保你的红包图片也具有相应的 ID。

这样修改后,红包雨将在 `app` 容器内部展示,并根据容器宽度和红包图片宽度计算出恰当的范围。

问:

#app{
  /* width: 100%; */
  width: 10rem;
  height: 100%;
  max-width: 540px;
  margin: 0 auto;
  position: relative;
  -webkit-tap-highlight-color:rgba(0,0,0,0);
}
我设置了app的宽度用10rem,
const appWidth = document.getElementById('app').offsetWidth;那么使用这行js获取app宽度的时候是rem单位还是px单位

回答:

使用 `offsetWidth` 获取的宽度是以像素(px)为单位的,而不是 `rem` 单位。无论你在 CSS 中使用何种单位来设置宽度,`offsetWidth` 都会返回元素的实际像素宽度。

所以,在你的代码中,`const appWidth = document.getElementById('app').offsetWidth;` 获取到的 `appWidth` 是以像素为单位的值。

问:

我要获取他的rem怎么获取

回答:

要获取元素的 `rem` 单位的宽度,你可以使用以下方法:

1. 获取根元素的字体大小(即 `html` 元素的 `font-size`)。
2. 将根元素的字体大小与元素的像素宽度进行比例计算,以得到相应的 `rem` 值。

下面是一个示例代码:

```javascript
// 获取根元素的字体大小(以像素为单位)
const rootFontSize = parseFloat(getComputedStyle(document.documentElement).fontSize);

// 获取 app 元素的像素宽度
const appWidthPx = document.getElementById('app').offsetWidth;

// 将像素宽度转换为 rem 值
const appWidthRem = appWidthPx / rootFontSize;

console.log(appWidthRem); // 输出 app 元素的宽度(以 rem 为单位)
```

请注意,这种方法假定根元素的字体大小是基于浏览器默认的 `16px` 设置。如果你在 CSS 中修改了根元素的字体大小,需要相应地进行调整计算。

问:

// 开启红包雨
const openRain = () => {
  console.log('点击了openRain');
  const hongbaos = Array.from({ length: 20 }); // 创建具有指定长度的数组
  // const maxLeft = document.body.offsetWidth - 40;
  
  // 获取根元素的字体大小(以像素为单位)
  const rootFontSize = parseFloat(getComputedStyle(document.documentElement).fontSize);

  // 获取 app 元素的像素宽度
  const appWidthPx = document.getElementById('app').offsetWidth;

  // 将像素宽度转换为 rem 值
  const appWidthRem = appWidthPx / rootFontSize;

  console.log(appWidthRem,'输出 app 元素的宽度(以 rem 为单位)'); // 输出 app 元素的宽度(以 rem 为单位)
  const maxLeft = appWidthRem > 0 ? appWidthRem - 3 : document.body.offsetWidth - 40;
  console.log(maxLeft,'maxLeft')

  // 添加遮罩层
  addOverlay();

  // 创建容器元素
  const container = document.createElement('div');
  container.className = 'container';

  for (let i = 0; i < hongbaos.length; i++) {
    const img = document.createElement('img');
    img.src = './hongbao.png';
    img.className = 'img';
    img.style.left = `${Math.random() * maxLeft}px`;
    img.style.animationDuration = `${Math.random() * 2 + 2}s`;
    img.style.animationDelay = `${i * 0.5}s`; // 设置不同的延迟时间
    container.appendChild(img);
  }

  // 在项目body节点上挂载container红包雨
  document.body.appendChild(container);现在是完整的红包雨代码,但是现在红包于是几乎一条线下落的请问为什么?哪里逻辑出了问题

回答:

在这段代码中,红包图片的位置是由 `left` 属性来设置的。但是你使用的随机数 `Math.random() * maxLeft` 是在 `0` 到 `maxLeft` 之间生成的一个浮点数,这可能导致红包图片的位置出现小数,从而使红包几乎在一条线上下落。

为了解决这个问题,你可以将生成的随机数转换为整数,从而确保红包的位置只会以像素为单位发生变化。例如,你可以使用 `Math.floor()` 方法将浮点数向下取整为最接近的整数,然后再将其作为 `left` 属性的值:

```javascript
img.style.left = `${Math.floor(Math.random() * maxLeft)}px`;
```

这样就可以确保红包图片的位置只会以像素为单位发生变化,而不会出现小数。

问:

// 开启红包雨
const openRain = () => {
  console.log('点击了openRain');
  const hongbaos = Array.from({ length: 20 }); // 创建具有指定长度的数组
  // const maxLeft = document.body.offsetWidth - 40;
  
  // 获取根元素的字体大小(以像素为单位)
  const rootFontSize = parseFloat(getComputedStyle(document.documentElement).fontSize);

  // 获取 app 元素的像素宽度
  const appWidthPx = document.getElementById('app').offsetWidth;

  // 将像素宽度转换为 rem 值
  const appWidthRem = appWidthPx / rootFontSize;

  console.log(appWidthRem,'输出 app 元素的宽度(以 rem 为单位)'); // 输出 app 元素的宽度(以 rem 为单位)
  const maxLeft = appWidthRem > 0 ? appWidthRem - 3 : document.body.offsetWidth - 40;
  console.log(maxLeft,'maxLeft')

  // 添加遮罩层
  addOverlay();

  // 创建容器元素
  const container = document.createElement('div');
  container.className = 'container';

  for (let i = 0; i < hongbaos.length; i++) {
    const img = document.createElement('img');
    img.src = './hongbao.png';
    img.className = 'img';
    img.style.left = `${Math.random() * maxLeft}px`;
    img.style.animationDuration = `${Math.random() * 2 + 2}s`;
    img.style.animationDelay = `${i * 0.5}s`; // 设置不同的延迟时间
    container.appendChild(img);
  }

  // 在项目body节点上挂载container红包雨
  document.body.appendChild(container);现在是完整的红包雨代码,但是现在红包于是几乎一条线下落的,我上面的maxLeft单位是rem,下面的img.style.left计算出来的单位是px,请帮我修改

回答:

你可以将 `maxLeft` 的单位从 rem 转换为像素 (px) 单位,然后在设置 `left` 属性时直接使用像素值。可以通过以下方式进行修改:

```javascript
// 将 rem 转换为像素
const maxLeftPx = maxLeft * rootFontSize;

// ...

for (let i = 0; i < hongbaos.length; i++) {
  const img = document.createElement('img');
  img.src = './hongbao.png';
  img.className = 'img';
  img.style.left = `${Math.random() * maxLeftPx}px`; // 使用像素值
  img.style.animationDuration = `${Math.random() * 2 + 2}s`;
  img.style.animationDelay = `${i * 0.5}s`; // 设置不同的延迟时间
  container.appendChild(img);
}

// ...
```

通过这样的修改,`maxLeft` 单位会与 `img.style.left` 计算出来的单位保持一致,都是像素单位 (px)。这样就可以确保红包以正确的像素值进行位置设置,而不会出现几乎一条线下落的情况。

整体代码:

// 添加遮罩层
const addOverlay = () => {
  const overlay = document.createElement('div');
  overlay.className = 'overlay';
  overlay.style.position = 'fixed';
  overlay.style.top = '0';
  overlay.style.left = '0';
  overlay.style.width = '100%';
  overlay.style.height = '100%';
  overlay.style.backgroundColor = 'rgba(0, 0, 0, 0.5)';
  overlay.style.zIndex = '20';
  document.body.appendChild(overlay);
}

// 移除遮罩层
const removeOverlay = () => {
  const overlay = document.querySelector('.overlay');
  if (overlay) {
    overlay.remove();
  }
}





// 开启红包雨
const openRain = () => {
  console.log('点击了openRain');
  const hongbaos = Array.from({ length: 26 }); // 创建具有指定长度的数组
  
  // 获取根元素的字体大小(以像素为单位)
  const rootFontSize = parseFloat(getComputedStyle(document.documentElement).fontSize);

  // 获取 app 元素的像素宽度
  const appWidthPx = document.getElementById('app').offsetWidth;

  // 将像素宽度转换为 rem 值
  const appWidthRem = appWidthPx / rootFontSize;

  console.log(appWidthRem,'输出 app 元素的宽度(以 rem 为单位)'); // 输出 app 元素的宽度(以 rem 为单位)
  const maxLeft = appWidthRem > 0 ? appWidthRem - 3 : document.body.offsetWidth - 40;
  // 将 rem 转换为像素
  const maxLeftPx = maxLeft * rootFontSize;
  console.log(maxLeftPx,'maxLeftPx')
  console.log(maxLeft,'maxLeft')

  // 添加遮罩层
  addOverlay();

  // 创建容器元素
  const container = document.createElement('div');
  container.className = 'container';

  for (let i = 0; i < hongbaos.length; i++) {
    const img = document.createElement('img');
    img.src = './hongbao.png';
    img.className = 'img';
    img.style.left = `${Math.random() * maxLeftPx}px`;
    img.style.animationDuration = `${Math.random() * 2 + 2}s`;
    img.style.animationDelay = `${i * 0.1}s`; // 设置不同的延迟时间
    container.appendChild(img);
  }

  // 在项目body节点上挂载container红包雨
  document.body.appendChild(container);

  // 设置定时器,在四秒后移除红包雨和遮罩层
  // setTimeout(() => {
  //   removeOverlay();
  //   container.remove();
  // }, 4000);
}

上面的代码最开始写了遮罩层,下面的openRain()函数是红包雨的触发代码.

  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值