滴滴首页动画实现

滴滴首页动画实现

首先我们得看下具体长啥样

didi.gif

这个不是有手就行?

  • 首屏的车流滚动,经过分析,并不是一个video标签,此处应该做了判断,pc端用video,移动端使用图片的解决方案,

image.png

其实到这里大概就清楚了,DOM能很清晰的反应这段代码的逻辑。

so,说干就干。

首先你得拥有一段视频

自己准备

视频如何处理?

选择的工具:nodejsffmpegchild_process

  • 如果视频过长,可以选择先把视频截取自己需要的部分
    // 视频截取
    const { spawn } = require('child_process')
    const videoPath = './video/hot-girl.mp4'
    const outPath = './out'
    const segmentTime = 60 // 视频时长

    // 切割视频
    const ffmpeg = spawn('ffmpeg', [
        '-i', videoPath,
        '-c', 'copy',
        '-map', '0',
        '-f', 'segment',
        '-segment_time', segmentTime,
        `${outPath}/out%03d.mp4`
    ]);
    ffmpeg.on('close', (code) => {
    console.log(`child process exited with code ${code}`)
    })
    ffmpeg.stderr.on('data', (data) => {
        console.log(data.toString())
    })

复制代码
  • 把视频按帧截图,或者按时间截图
    const picVideoPath = './out/out011.mp4'
    const picOutPath = './out/pic'
    const ffmpegArgs = [
        '-i', picVideoPath,
        '-vf', 'thumbnail',
        '-frames:v', '1',
        '-c:v', 'png',
        '-f', 'image2pipe',
        'pipe:1',
        `${picOutPath}/girl%d.png`
      ];
    const ffmpeg = spawn('ffmpeg', ffmpegArgs);
复制代码
  • 那么问题来了,如果原视频画质较高,那么截图可能会超过你的想象(1M及以上)

如何处理?

imagemin imagemin-jpegtran imagemin-pngquant imagemin-webp 此处可自行选择使用imagemin-webpor imagemin-pngquant,我自己选择的是webp,因为webp的效率超乎你的想象,举个例子:1.5M经过imagemin-pngquant压缩之后再使用imagemin-webp,最后仅剩下区区20K。

// 待压缩的图片所在的文件夹
const sourcePath = path.resolve("./out/pic");

// 压缩后的图片的输出路径 
const targetPath = path.resolve("./images");

/**
 * 读取文件夹下的所有图片列表
 * @param {Function} cb 
 */
const getImagesList = (cb) => {
  fs.readdir(sourcePath, (err, files) => {
    if (!err) {
      return cb(files.map((name) => path.join(sourcePath, name)));
    }

    console.log(err);
  });
};

/**
 * 压缩图片
 * @param {Array} files 
 */
const compress = async (files) => {
  return await imagemin(files, {
    destination: targetPath,
    plugins: [
      imageminJpegtran(),
      // imageminPngquant({
      //   quality: [0.2, 0.2],
      // }),
      imageminWebp({
        quality: 10,
      })
    ],
  });
};

const run = () => {
  getImagesList(async (files) => {
    for (let index = 0; index < files.length; index++) {
      try {
        console.log(`${index+1}/${files.length}`)

        // 图片一张一张处理,降低处理失败的概率。
        await compress([files[index]]);
      } catch (error) {
        console.log(error);
      }
    }
  });
};

run();
/** 以上代码是copy的,忘了出处。sry */
复制代码

前期工作准备完毕,那么就该直接开始操作了!

此处注意,如果你切割出来的图片较多,请搭建一个静态文件服务或者??,不要放到当前项目下,可能会导致打包失败!超过限制

  1. 根据原有思路,那么我们其实只需要去处理一下url就好了,那其实就是
<template>
    <img v-for="i in 1000" :src="`xxxx.com/img${i}.webp`" v-if="activeIndex ===i">
</template>
....
data () {
    return {
        activeIndex:1
    }
}
...

.... 

setInterVal(this.aciveIndex++,100)

复制代码

但是这个会有什么问题呢?那就是图片加载速度跟不上你切换的速度,那么会咋样?

image.png

中间部分图片加载不出来就会导致看起来画面掉帧,卡顿等

并且,通过v-if控制图片,还会导致资源反复加载,如果有同学挂着睡觉一晚上,明早起来房子没了,车子没了。。。。

  • 仔细观察一下滴滴官网,发现他们的并没有出现这种情况? 没有思考出为什么他们的没有这个情况?可能是请求头的原因?还是什么情况? 大家可以帮忙参考一下

image.png 这是我设置的返回响应

image.png

滴滴的返回值

目前我为了解决这个问题,使用了用js把图片二进制流获取到,再生成base64,这样虽然也会有请求狂刷,但是不会造成额外的流量开销。

const total = 900;
const isLoaded = ref(0);
const images = ref<Array<string>>([]);
async function preloadImages() {
  for (let i = 1; i <= total; i++) {
    const data = await apis.utils.getImages<Blob>(`girl${i}.webp`);
    const url = URL.createObjectURL(new Blob([data],{type: 'image/webp'}));
    images.value[i] = url;
    isLoaded.value++;
    if(isLoaded.value >= 50) {
      changeActive();
    }
  }
}
// 自执行函数
(async () => {
  await preloadImages();
})();

const imageUrl = computed(() => {
  return images.value[active.value]
});
....
<template>
      <img :src="imageUrl" />
</template>

复制代码

预览地址

v4.lvzy.xyz:18888/login

用手机端打开更好~

pc的加载没有做处理,可能会白屏一段时间~

login.gif

2023-4-3更新

已修复请求刷新的问题。

可以访问地址测试,首屏未作加载动画,已跟滴滴动画一样,不会狂刷请求了。。

期间尝试过很多办法,去处理这个问题

  • 通过map存储jsx,有这个url就去取值
  • 通过map存储Image
  • 通过隐藏dom节点,查找对应img,再克隆
  • base64
  • 通过map存储Image对象,找到图片容器夫父节点,appendClild或者replaceChild处理

通过最后一种方式以解决~

完美撒花~

大家可以自行查看network,试试效果~

Ikun专属源码链接[gitlab](src/components/images-video/index.tsx · master · Administrator / vue2.7_vite_ts · GitLab (lvzy.xyz))

猜你喜欢

转载自juejin.im/post/7216584694791454777