腾讯课堂 H5 直播间点赞动效实现

发表于 2年以前  | 总阅读数:367 次

1. 前言

以前在看微信视频号直播的时候,经常点击右下角的点赞按钮。看着它的数字慢慢从一位数变成五位数,还是挺有氛围感的。特别是长按的时候,有个手机震动的反馈,很带感。

虽然之前很好奇这些飘动的点赞动效是怎么实现的,但没有特别去钻研。直到前阵子投入腾讯课堂 H5 直播间的需求,需要自己去实现一个这样的效果时,才开始摸索。

先看看最后的效果:

相比视频号的点赞动效,轨迹复杂了很多。可以看到课堂直播间的这一段点赞动效,大概分为这么三个阶段:

  1. 从无到有,在上升过程中放大成正常大小
  2. 上升过程中左右摇曳,且摇曳的幅度随机
  3. 左右摇曳上升的过程中,渐隐并缩小

在动手之前,我先想到了使用 CSS animation 去实现这种运动轨迹。在完成之后,又用 Canvas 重构了一版,优化了性能。

接下来我们分别来看看这两种实现方式。

2. CSS 实现点赞动效

2.1 轨迹分析

由于点赞动画是在一个二维平面上的,我们可以将它的运动轨迹拆分为 x 轴y 轴 上的两段。

y 轴 上非常简单,我们的点赞图标会做一段垂直上升的匀速运动,从容器底部上升到容器顶部。

x 轴 上是左右摇曳的,用数学的角度说,是一段简谐运动。

但用 css 实现的时候,其实不用这么精细。为了简化计算,我们可以用几个关键帧来串联这段运动轨迹,例如:

@keyframes bubble_swing {
  0% {
    中间
  }
  25% {
    最左
  }
  75% {
    最右
  }
  100% {
    中间
  }
}

2.2 轨迹设计

根据上面的分析,我们可以设计一段相同的上升轨迹,以及几段不同的左右摇曳轨迹。

上升轨迹很简单,同时我们还可以加上透明度(opacity)、大小(transform)的变化,如下:

@keyframes bubble_y {
  0% {
    transform: scale(1);
    margin-bottom: 0;
    opacity: 0;
  }
  5% {
    transform: scale(1.5);
    opacity: 1;
  }
  80% {
    transform: scale(1);
    opacity: 1;
  }
  100% {
    margin-bottom: var(--cntHeight);
    transform: scale(0.8);
    opacity: 0;
  }
}

其中,--cntHeight 指的是容器的高度。也就是说,我们通过让 margin-bottom 不断增大,来控制点赞图标从容器底部上升到容器顶部。

而对于横向运动的轨迹,为了增加运动轨迹的多样性,我们可以设计多段左右摇曳的轨迹,比如说一段 “中间 -> 最左 -> 中间 -> 最右” 的轨迹:

@keyframes bubble_swing_1 {
  0% {
    // 中间
    margin-left: 0;
  }
  25% {
    // 最左
    margin-left: -12px;
  }
  75% {
    // 最右
    margin-left: 12px;
  }
  100% {
    margin-left: 0;
  }
}

这里同样使用 margin 来控制图标的左右移动。类似的,我们还可以设计几段别的轨迹:

// 任意轨迹
@keyframes bubble_swing_2 {
  0% {
    // 中间
    margin-left: 0;
  }
  33% {
    // 最左
    margin-left: -12px;
  }
  100% {
    // 随机位置
    margin-left: 6px;
  }
}

// 简谐反向
@keyframes bubble_swing_3 {
  0% {
    // 中间
    margin-left: 0;
  }
  25% {
    // 最右
    margin-left: 12px;
  }
  75% {
    // 最左
    margin-left: -12px;
  }
  100% {
    margin-left: 0;
  }
}

接下来我们把 x 轴y 轴 的轨迹(@keyframes)结合起来,并设置一个随机的动画时间,比如说:

@for$i from 1 through 3 {
  @for$j from 1 through 2 {
    .bl_#{$i}_#{$j} {
      animation: bubble_y calc(1.5s + $j * 0.5s) linear 1 forwards,
        bubble_swing_#{$i} calc(1.5s + $j * 0.5s) linear 1 forwards;
    }
  }
}

这里生成了 3 * 2 = 6 种不同的轨迹。针对这类重复的选择器,用 SCSS 中的循环语法,可以少写很多代码。

2.3 随机选择图片(雪碧图)

我们每次点赞会出现不同的图标,于是这里设计了一系列选择器给不同的图标,让它们呈现不同的图片。首先我们要准备一张雪碧图,保持所有图标的大小一致,然后同样使用 SCSS 的循环语法:

@for$i from 0 through 7 {
  .b#{$i} {
    background: url('../../images/like_sprites.png') calc(#{$i} * -24px) 0;
  }
}

像上面生成了 8 个选择器,我们在程序执行时就可以随机给图标赋予一个选择器。

2.4 生成一个点赞图标

CSS 的部分差不多了,我们现在来看 JS 是怎么执行的。我们需要有一个容器 div,让它来装载要生成的点赞图标。以及一个按钮来绑定点击事件:

const cacheRef = useRef<LikeCache>({
    bubbleCnt: null,
    likeIcon: null,
    bubbleIndex: 0,
    timer: null,
});

useEffect(() => {
    cacheRef.current.bubbleCnt = document.getElementById('like-bubble-cnt');
    cacheRef.current.likeIcon = document.getElementById('like-icon');
}, []);

在点击事件中,生成一个新的 div 元素,并为它设置 className。接着将它 append 到容器下,最后在一段时间后销毁这个点赞图标元素。如下:

/**
 * 添加 bubble
 */
const addBubble = () => {
  const { bubbleCnt } = cacheRef.current;

  cacheRef.current.bubbleIndex %= maxBubble;
  const d = document.createElement('div');

  // 图片类 b0 - b7
  // 随机动画类 bl_1_1 - bl_3_2
  const swing = Math.floor(Math.random() * 3) + 1;
  const speed = Math.floor(Math.random() * 2) + 1;
  d.className = `like-bubble b${cacheRef.current.bubbleIndex} bl_${swing}_${speed}`;

  bubbleCnt?.appendChild(d);
  cacheRef.current.bubbleIndex++;

  // 动画结束后销毁元素
  setTimeout(() => {
    bubbleCnt?.removeChild(d);
  }, 2600);
};

到这里,我们就实现得差不多了。不过,我们还可以给点击的图标加点动画,让它有一个被按压后弹起的效果:

/**
 * 点击“喜欢”
 */
const onClick = () => {
  const { timer, likeIcon } = cacheRef.current;
  if (!likeIcon) {
    return;
  }

  if (timer) {
    clearTimeout(timer);
    cacheRef.current.timer = null;
  }
  likeIcon.classList.remove('bounce-click');
  // 删除并重新添加类,需要延迟添加
  setTimeout(() => {
    likeIcon.classList.add('bounce-click');
  }, 0);
  cacheRef.current.timer = window.setTimeout(() => {
    likeIcon.classList.remove('bounce-click');
    clearTimeout(timer!);
    cacheRef.current.timer = null;
  }, 300);

  addBubble();
};

2.5 最终效果

最后来看看效果吧!

3. Canvas 实现点赞动效

我们都知道 Canvas 的绘制更流畅一些,能够带来更好的体验。但苦于编码比较复杂,也有一定的学习成本,实现起来要比 CSS 复杂不少。

接下来我们看看基于 Canvas 的点赞动效实现。

3.1 画布创建

首先我们读取一个 Canvas 元素的 id,并通过 getContext 获取它的上下文。除此之外,还传入了一个 canvasScale,指的是画布放大的比例,这个在之后会用到:

constructor(canvasId: string, canvasScale: number) {
  const canvas = document.getElementById(canvasId) as HTMLCanvasElement;
  this.context = canvas.getContext('2d')!;
  this.width = canvas.width;
  this.height = canvas.height;
  this.canvasScale = canvasScale;
  this.img = null;
  this.loadImages();
}

3.2 预加载图片(雪碧图)

在 constructor 这里,我们还通过 loadImages 这个函数,预加载了雪碧图:

import likeSprites from'../../images/like_sprites.png';

/**
 * 预加载图片
 */
loadImages = () => {
  const p = newPromise((resolve: (image: HTMLImageElement) => void) => {
    const img = new Image();
    img.onerror = () => resolve(img);
    img.onload = () => resolve(img);
    img.src = likeSprites;
  });
  p.then((img) => {
    if (img && img.width > 0) {
      this.img = img;
    } else {
      // error('[live-connect]预加载喜欢动效图片失败');
    }
  });
};

3.3 轨迹拆解

同样的,我们需要从 Canvas 的视角来拆解点赞图标的运动轨迹。

y 轴 的运动和 CSS 一样,我们知道起始位置和终止位置就可以得出。

x 轴 的运动可以好好推敲。由于 Canvas 是逐帧绘制的,我们可以模拟出一个比较逼真的简谐运动。这里要来讲一讲大家耳熟能详的初中数学了,下面是我们要使用的一条正弦函数的公式:

y = A sin(Bx + C) + D

参数说明:

  • 振幅是 A
  • 周期是 2π/B
  • 相移是 −C/B
  • 垂直移位是 D

套入点赞动效:

  • 赋予图标元素随机的振幅 A。
  • 赋予图标元素随机的周期,即 B 是随机的。
  • 取 C = 0,即相移为 0。
  • 取 D = 0,即不需要垂直移位。
y = A sinBx。

3.4 横竖位移计算

确定位移轨迹之后,我们先定义一些常量,如下:

/** 图片显示宽高 */
const IMAGE_WIDTH = 30;

/** 图片原始宽高 */
const SOURCE_IMAGE_WIDTH = 144;

/** 图片数量 */
const IMG_NUM = 8;

/** 放大阶段(百分比)*/
const ENLARGE_STAGE = 0.1;

/** 收缩渐隐阶段(百分比)*/
const FADE_OUT_STAGE = 0.8;

首先我们可以设计 x 轴y 轴 两个方向上的位移计算函数,函数参数 progress 是 0 到 1 之间的数值,表示一个过程量(0 -> 1)。

// 起始位置
const basicX = this.width / 2;

// 正弦频率
const frequency = random(2, 10);

// 正弦振幅
const amplitude = random(5, 20) * (random(0, 1) ? 1 : -1) * this.canvasScale;

/**
 * 获取横向位移(x轴)
 */
const getTranslateX = (progress: number) => {
  if (progress < ENLARGE_STAGE) {
    // 放大期间,不进行摇摆位移
    return basicX;
  }
  return basicX + amplitude * Math.sin(frequency * (progress - ENLARGE_STAGE));
};

/**
 * 获取竖向位移(y轴)
 */
const getTranslateY = (progress: number) => {
  return IMAGE_WIDTH / 2 + (this.height - IMAGE_WIDTH / 2) * (1 - progress);
};

3.5 大小和透明度计算

要绘制的图标大小怎么控制呢?在 Canvas 中,其实就是计算一个 scale,表示放缩的比例。

我们根据放大/收缩阶段的过程常量和 progress 变量来调节它的大小。起始阶段先线性放大至 1,最后阶段再线性缩小至 0。

透明度同理,在消失之前都是返回 1,其余时刻线性缩小。

/**
 * 获取放缩比例
 */
const getScale = (progress: number) => {
  let r = 1;
  if (progress < ENLARGE_STAGE) {
    // 放大
    r = progress / ENLARGE_STAGE;
  } elseif (progress > FADE_OUT_STAGE) {
    // 缩小
    r = (1 - progress) / (1 - FADE_OUT_STAGE);
  }
  return r;
};

/**
 * 获取透明度
 */
const getAlpha = (progress: number) => {
  if (progress < FADE_OUT_STAGE) {
    return 1;
  }
  return 1 - (progress - FADE_OUT_STAGE) / (1 - FADE_OUT_STAGE);
};

3.6 Canvas 绘制

绘制时,我们先挑选一张图片。如下:

// 按顺序读取图片
const { curImgIndex } = this;

// 更新顺序
this.curImgIndex = ++this.curImgIndex % IMG_NUM;

3.6.1 画布元素清晰度

接下来需要用到我们之前提到的 canvasScale 了:

const newWidth = IMAGE_WIDTH * this.canvasScale;

为什么这里要乘以一个 canvasScale 呢?因为 Canvas 是位图模式的,它会根据设备的 dpi 来渲染图片。

首先先介绍一下高分屏的概念:

高分屏:在同样大小的屏幕面积上显示更多的像素点,也就是更多的可视信息。常见的就是 SXGA(1400 * 1050),UXGA(1600 * 1200)。1024 * 768 分辨率的屏幕叫普通屏,也就是 XGA 的屏幕,这个分辨率以上的屏幕叫高分屏。

在高分屏上,每平方英寸会有更多的像素。原来在普通屏上绘制的 1 个像素,为了适应高分屏,被迫放大,变成了 4 个像素或者更多。

可以想象成,一张清晰度正常的普通图片为了布满整个背景被强行放大 n 倍,所以看起来模糊了

为了解决这个问题,就需要我们将绘制的图片放大。同时还要控制 Canvas 画布在 CSS 中的宽高。做到绘制内容变大的同时,画布依然呈现原来的大小。这样一来,图片就会因为绘制了更多的内容,而在高分屏上变得清晰且细腻。

3.6.2 绘制元素

绘制我们用到了 drawImage。在调用它之前,我们需要根据计算出的 translateX 和 translateY,调整绘制的起点。并且调整放缩比例和透明度,即 context.scale()context.globalAlpha。如下:

return(progress: number) => {
  // 动画过程 0 -> 1
  if (progress >= 1) return true;

  context.save();
  const scale = getScale(progress);
  const translateX = getTranslateX(progress);
  const translateY = getTranslateY(progress);
  context.translate(translateX, translateY);
  context.scale(scale, scale);
  context.globalAlpha = getAlpha(progress);
  context.drawImage(
    this.img!,
    SOURCE_IMAGE_WIDTH * curImgIndex,
    0,
    SOURCE_IMAGE_WIDTH,
    SOURCE_IMAGE_WIDTH,
    -newWidth / 2,
    -newWidth / 2,
    newWidth,
    newWidth,
  );
  context.restore();
  return false;
};

3.6.3 创建绘制实例

我们用一个 start 函数来生成点赞动画,每当调用它时,都会创建一个 render 方法,并塞入一个 renderList。renderList 中存放的就是当前所有点赞图标的绘制任务。如下:

start = () => {
  const render = this.createRender();
  const duration = random(2100, 2600);
  if (!render) {
    return;
  }
  this.renderList.push({
    render,
    duration,
    timestamp: Date.now(),
  });
  if (!this.scanning) {
    this.scanning = true;
    requestAnimationFrame(this.scan);
  }
  return this;
};

3.6.4 实时绘制

知道了需要绘制哪些对象之后,就需要通过下面的 scan 方法,让 Canvas 在每一帧都去绘制内容。

每次绘制分为这么几个过程:

  1. 清空画布为透明。
  2. 从绘制列表中取出一个点赞图标的 render 方法,并调用它。
  3. 假如它返回了 true,代表点赞图标已经完整经历了整个动效的过程,需要将它从绘制列表中剔除出去。
  4. 重复 2、3 过程,直至列表中没有任务需要执行。
  5. 通过 <span style="font-size: 14px;">requestAnimationFrame 调用 scan 方法自身,等待下一帧重新调用 scan 绘制内容。
scan = () => {
  this.context.clearRect(0, 0, this.width, this.height);
  let index = 0;
  let { length } = this.renderList;
  if (length > 0) {
    requestAnimationFrame(this.scan);
    this.scanning = true;
  } else {
    this.scanning = false;
  }
  while (index < length) {
    const child = this.renderList[index];
    if (!child || !child.render || child.render.call(null, (Date.now() - child.timestamp) / child.duration)) {
      // 结束了,删除该动画
      this.renderList.splice(index, 1);
      length--;
    } else {
      index++;
    }
  }
};

3.7 调用

接下来我们只需要在点击的时候,调用一下 start 方法即可。

/**
 * 点击“喜欢”
 */
const onClick = () => {
  cacheRef.current.LikeAni?.start?.();
};

return (
  <div className={cn('like-wrap', className)}>
    <canvas id={CANVAS_ID} width={CANVAS_WIDTH} height={CANVAS_HEIGHT} className="like-bubble-cnt" />
    <div className={cn('like-icon-cnt', className)} onClick={onClick}>
      <i id="like-icon" className="like-icon" />
    </div>
  </div>
);

在直播场景下,还有很多不同的触发方式。除了自己点击,我们还可以接受来自其他用户的反馈(网络请求)来触发start 方法。或者根据在线人数,多次调用 start 方法来生成一定数量的点赞图标。

3.8 最终效果

4. 性能比较

以下内容是在 MacBook Pro 16 的屏幕上测试的。

4.1 Frame Rendering Stats

在 chrome devtools 中,有两个小功能可以来观察我们绘制的性能情况:

  • Paint flashing:可以高亮当前发生重绘的区域。
  • Frame Rendering Stats,可以观察动画的 fps 和 GPU 使用情况。我们分别来看看 CSS 和 Canvas 两种实现方式的性能情况。

这两个功能,可以在 chrome devtools 中使用快捷键 Command + Shift + P,呼起命令搜索的 Panel 来搜索到。

CSS 性能

我们可以看到高亮区域在频繁闪动,以及 GPU 内存的使用比率较高,这是因为 CSS 的实现方式是不断生成新的元素(并在随后销毁),会消耗更多的内存。

Canvas 性能

相反,Canvas 是集中在画布上绘制并输出的,不会反复创建和销毁元素。会比 CSS 的实现更加流畅,性能更好一点。

除了流畅以外,Canvas 还能够放大画布和画布元素,这也是一个非常重要的优势。这意味着 Canvas 能够绘制出更清晰的内容,生成出来的点赞图标更加细腻。

4.2 Performance

在 chrome devtools 中切换到 Performance 面板,还可以观察动画绘制过程中,页面的一些性能指标。

CSS 性能

CSS 的实现之所以看起比较卡顿,主要是因为绘制任务太频繁。

具体到每一帧,我们可以观察到 LayoutShift 的警告。

每次可视元素在两次渲染帧中的起始位置不同时,就说是发生了 LS(Layout Shift)。改变了起始位置的元素被认为是不稳定元素

Canvas 性能

Canvas 实现的性能情况看起来就比较正常,即使绘制清晰一些的图片也不在话下。

5. 相关

实现参考: https://github.com/antiter/praise-animation

本文由哈喽比特于2年以前收录,如有侵权请联系我们。
文章来源:https://mp.weixin.qq.com/s/wGQ-Dwg4wERTnBmPhj0hsQ

 相关推荐

刘强东夫妇:“移民美国”传言被驳斥

京东创始人刘强东和其妻子章泽天最近成为了互联网舆论关注的焦点。有关他们“移民美国”和在美国购买豪宅的传言在互联网上广泛传播。然而,京东官方通过微博发言人发布的消息澄清了这些传言,称这些言论纯属虚假信息和蓄意捏造。

发布于:1年以前  |  808次阅读  |  详细内容 »

博主曝三大运营商,将集体采购百万台华为Mate60系列

日前,据博主“@超能数码君老周”爆料,国内三大运营商中国移动、中国电信和中国联通预计将集体采购百万台规模的华为Mate60系列手机。

发布于:1年以前  |  770次阅读  |  详细内容 »

ASML CEO警告:出口管制不是可行做法,不要“逼迫中国大陆创新”

据报道,荷兰半导体设备公司ASML正看到美国对华遏制政策的负面影响。阿斯麦(ASML)CEO彼得·温宁克在一档电视节目中分享了他对中国大陆问题以及该公司面临的出口管制和保护主义的看法。彼得曾在多个场合表达了他对出口管制以及中荷经济关系的担忧。

发布于:1年以前  |  756次阅读  |  详细内容 »

抖音中长视频App青桃更名抖音精选,字节再发力对抗B站

今年早些时候,抖音悄然上线了一款名为“青桃”的 App,Slogan 为“看见你的热爱”,根据应用介绍可知,“青桃”是一个属于年轻人的兴趣知识视频平台,由抖音官方出品的中长视频关联版本,整体风格有些类似B站。

发布于:1年以前  |  648次阅读  |  详细内容 »

威马CDO:中国每百户家庭仅17户有车

日前,威马汽车首席数据官梅松林转发了一份“世界各国地区拥车率排行榜”,同时,他发文表示:中国汽车普及率低于非洲国家尼日利亚,每百户家庭仅17户有车。意大利世界排名第一,每十户中九户有车。

发布于:1年以前  |  589次阅读  |  详细内容 »

研究发现维生素 C 等抗氧化剂会刺激癌症生长和转移

近日,一项新的研究发现,维生素 C 和 E 等抗氧化剂会激活一种机制,刺激癌症肿瘤中新血管的生长,帮助它们生长和扩散。

发布于:1年以前  |  449次阅读  |  详细内容 »

苹果据称正引入3D打印技术,用以生产智能手表的钢质底盘

据媒体援引消息人士报道,苹果公司正在测试使用3D打印技术来生产其智能手表的钢质底盘。消息传出后,3D系统一度大涨超10%,不过截至周三收盘,该股涨幅回落至2%以内。

发布于:1年以前  |  446次阅读  |  详细内容 »

千万级抖音网红秀才账号被封禁

9月2日,坐拥千万粉丝的网红主播“秀才”账号被封禁,在社交媒体平台上引发热议。平台相关负责人表示,“秀才”账号违反平台相关规定,已封禁。据知情人士透露,秀才近期被举报存在违法行为,这可能是他被封禁的部分原因。据悉,“秀才”年龄39岁,是安徽省亳州市蒙城县人,抖音网红,粉丝数量超1200万。他曾被称为“中老年...

发布于:1年以前  |  445次阅读  |  详细内容 »

亚马逊股东起诉公司和贝索斯,称其在购买卫星发射服务时忽视了 SpaceX

9月3日消息,亚马逊的一些股东,包括持有该公司股票的一家养老基金,日前对亚马逊、其创始人贝索斯和其董事会提起诉讼,指控他们在为 Project Kuiper 卫星星座项目购买发射服务时“违反了信义义务”。

发布于:1年以前  |  444次阅读  |  详细内容 »

苹果上线AppsbyApple网站,以推广自家应用程序

据消息,为推广自家应用,苹果现推出了一个名为“Apps by Apple”的网站,展示了苹果为旗下产品(如 iPhone、iPad、Apple Watch、Mac 和 Apple TV)开发的各种应用程序。

发布于:1年以前  |  442次阅读  |  详细内容 »

特斯拉美国降价引发投资者不满:“这是短期麻醉剂”

特斯拉本周在美国大幅下调Model S和X售价,引发了该公司一些最坚定支持者的不满。知名特斯拉多头、未来基金(Future Fund)管理合伙人加里·布莱克发帖称,降价是一种“短期麻醉剂”,会让潜在客户等待进一步降价。

发布于:1年以前  |  441次阅读  |  详细内容 »

光刻机巨头阿斯麦:拿到许可,继续对华出口

据外媒9月2日报道,荷兰半导体设备制造商阿斯麦称,尽管荷兰政府颁布的半导体设备出口管制新规9月正式生效,但该公司已获得在2023年底以前向中国运送受限制芯片制造机器的许可。

发布于:1年以前  |  437次阅读  |  详细内容 »

马斯克与库克首次隔空合作:为苹果提供卫星服务

近日,根据美国证券交易委员会的文件显示,苹果卫星服务提供商 Globalstar 近期向马斯克旗下的 SpaceX 支付 6400 万美元(约 4.65 亿元人民币)。用于在 2023-2025 年期间,发射卫星,进一步扩展苹果 iPhone 系列的 SOS 卫星服务。

发布于:1年以前  |  430次阅读  |  详细内容 »

𝕏(推特)调整隐私政策,可拿用户发布的信息训练 AI 模型

据报道,马斯克旗下社交平台𝕏(推特)日前调整了隐私政策,允许 𝕏 使用用户发布的信息来训练其人工智能(AI)模型。新的隐私政策将于 9 月 29 日生效。新政策规定,𝕏可能会使用所收集到的平台信息和公开可用的信息,来帮助训练 𝕏 的机器学习或人工智能模型。

发布于:1年以前  |  428次阅读  |  详细内容 »

荣耀CEO谈华为手机回归:替老同事们高兴,对行业也是好事

9月2日,荣耀CEO赵明在采访中谈及华为手机回归时表示,替老同事们高兴,觉得手机行业,由于华为的回归,让竞争充满了更多的可能性和更多的魅力,对行业来说也是件好事。

发布于:1年以前  |  423次阅读  |  详细内容 »

AI操控无人机能力超越人类冠军

《自然》30日发表的一篇论文报道了一个名为Swift的人工智能(AI)系统,该系统驾驶无人机的能力可在真实世界中一对一冠军赛里战胜人类对手。

发布于:1年以前  |  423次阅读  |  详细内容 »

AI生成的蘑菇科普书存在可致命错误

近日,非营利组织纽约真菌学会(NYMS)发出警告,表示亚马逊为代表的电商平台上,充斥着各种AI生成的蘑菇觅食科普书籍,其中存在诸多错误。

发布于:1年以前  |  420次阅读  |  详细内容 »

社交媒体平台𝕏计划收集用户生物识别数据与工作教育经历

社交媒体平台𝕏(原推特)新隐私政策提到:“在您同意的情况下,我们可能出于安全、安保和身份识别目的收集和使用您的生物识别信息。”

发布于:1年以前  |  411次阅读  |  详细内容 »

国产扫地机器人热销欧洲,国产割草机器人抢占欧洲草坪

2023年德国柏林消费电子展上,各大企业都带来了最新的理念和产品,而高端化、本土化的中国产品正在不断吸引欧洲等国际市场的目光。

发布于:1年以前  |  406次阅读  |  详细内容 »

罗永浩吐槽iPhone15和14不会有区别,除了序列号变了

罗永浩日前在直播中吐槽苹果即将推出的 iPhone 新品,具体内容为:“以我对我‘子公司’的了解,我认为 iPhone 15 跟 iPhone 14 不会有什么区别的,除了序(列)号变了,这个‘不要脸’的东西,这个‘臭厨子’。

发布于:1年以前  |  398次阅读  |  详细内容 »
 相关文章
Android插件化方案 5年以前  |  237228次阅读
vscode超好用的代码书签插件Bookmarks 2年以前  |  8063次阅读
 目录