乐趣区

关于前端:你的性格主导色揭秘

介绍

《你的性情主导色》是往年网易云音乐前端团队开发的一款测试用户主导色的 H5 利用,上线后反应很好,刷爆了微博和朋友圈。

我的项目的次要开发者 imyzf 发表了一篇文章《官网揭秘!你的色彩是这样算进去的》,解释了一些动效和最初主导色的计算方面的问题。但因为波及到了具体的业务,所以作者没有开源出源码,然而热心的作者给了很多的提醒。我就是依据这些提醒,揭秘了我比拟感兴趣的局部。

在线 Demo

因为始终没有在生产环境中应用 Vue3.0vite,所以源码局部我应用了 Vue3.0+vite实现。

页面预加载

答题类页面与个别的 H5 页面的不同之处在于,用户的操作门路是确定的,即每个页面的下一页路由是固定的,所以在 router 层面做了优化,提前预加载了下一个页面

因为流动页面应用了大量的视频和动效等,所以想在用户浏览选择题目标过程中把下一页的页面渲染结束,这样切换到下一页面的时候会很晦涩,体验很好。

最后就想着怎么利用 vue-router 实现页面的预加载。然而搞了一圈发现,都是基于 webpack 或者 vite 的懒加载,提前加载了一些资源,并不会提前渲染出页面。

起初通过看 vue-router 文档,才找到了灵感,利用命名视图,同时展现 2 个视图,应用 css 暗藏下一页,这时候尽管不显示,然而页面曾经渲染进去了。

通过批改 router-viewname 属性,实现页面的切换。也就是说,其实我的路由是没有变动的。

// App.vue
<template>
  <router-view :name="currentViewName"></router-view>
  <router-view :name="nextViewName"></router-view>
</template>

// 留神,这里应用两个 viewName 实现了页面的跳转,next 的页面被预加载
const currentViewName = computed(() => store.getters.currentViewName);
const nextViewName = computed(() => store.getters.nextViewName);

// router 的定义局部
const routes = [
  {
    path: '/',
    components: {
      default: Index1,
      index2: Index2,
      session1: Session1,
      session2: Session2,
      session5: Session5
    }
  }
];

看下面的代码,Index1Index2Session1 等其实就是每一页的组件了,通过批改 currentViewNamenextViewName就能够达到页面切换的目标。

最终的成果是下图这样的,下一页曾经提前渲染进去:

翻页动效

作者提醒说应用 canvas 实现了页面切换时候的幕布拉动成果,次要使用了最外围的 canvas APIbezierCurveTo

通过查问得悉,bezierCurveTo 须要 3 个 点用来绘制三次贝赛尔曲线,在线体验

看下图,想要实现拉动动画,P1 P2 P3X 轴坐标须要继续变动,而后绘制曲线,就可能实现拉动的成果了。

我这里应用了比拟轻量的 JavaScript 动画库animejs,用来管制下面几个点的继续挪动。3 个动画成果别离挪动了P1 P2 P3X轴坐标,再配合曲线的绘制,就达到了根本的拉动幕布成果。

  const heights = [0, 0.5 * pageHeight, pageHeight];
  points = {
    p1: {
      x: pageWidth,
      y: heights[0]
    },
    p2: {
      x: pageWidth,
      y: heights[1]
    },
    p3: {
      x: pageWidth,
      y: heights[2]
    },
    p4: {
      x: pageWidth,
      y: heights[2]
    },
    p5: {
      x: pageWidth,
      y: heights[0]
    }
  };

  // P1 点的变动
  anime({
    targets: points.p1,
    x: 0,
    easing: 'easeInQuart',
    delay: 50,
    duration: 500
  });

  // P2 点的变动
  anime({
    targets: points.p2,
    x: 0,
    easing: 'easeInSine',
    duration: 500
  });

  anime({
    targets: points.p2,
    y: 0.6 * pageHeight,
    easing: 'easeInSine',
    duration: 500
  });

  // P3 点的变动
  anime({
    targets: points.p3,
    x: 0,
    easing: 'easeInQuart',
    delay: 50,
    duration: 500
  });

  // 画曲线
  anime({
    duration: 550,
    update: function () {
      // 革除上一次的绘制
      ctx.clearRect(0, 0, pageWidth, pageHeight);
      ctx.beginPath();
      ctx.moveTo(points.p1.x, points.p1.y);
      // 幕布的上半区域
      ctx.bezierCurveTo(
        points.p1.x,
        points.p1.y,
        points.p2.x,
        points.p2.y - 0.2 * pageHeight,
        points.p2.x,
        points.p2.y
      );
      // 幕布的下半区域
      ctx.bezierCurveTo(
        points.p2.x,
        points.p2.y + 0.2 * pageHeight,
        points.p3.x,
        points.p3.y,
        points.p3.x,
        points.p3.y
      );
      // 已拉动局部的矩形区域
      ctx.lineTo(points.p4.x, points.p4.y);
      ctx.lineTo(points.p5.x, points.p5.y);
      ctx.closePath();
      ctx.fill();
      ctx.strokeStyle = '#f1f1f1';
      ctx.stroke();}
  });

最终实现的成果是这样的:

这个动效因为每一页都须要应用,所以思考实现一个通用的全局组件。

思考到应用的时候个别组件须要写到vue 模板下面,很不不便,所以最好通过一个全局函数间接显示这段动效,相似于showAnimation();

首先须要实现一个独立的组件,因为想笼罩掉页面的所有信息,所以应用了 Vue3.0 最新提供的teleport 组件:

<!-- 这个 canvas 会被渲染为 app 的子级 -->
  <teleport to="#app">
    <canvas class="mask-canvas" ref="canvas" :class="{'mask-canvas-posi': isShow}"></canvas>
  </teleport>

而后须要把组件通过 Vue 插件的形式注册到全局属性,因为我想应用 Composition API,所以最终决定应用 provide + inject 的形式注册和应用全局 property。个别的状况下应用 app.config.globalProperties 就能够了,然而这种配合 Composition API 写起来会比拟麻烦,不举荐。

(Mask as any).install = (app: App): void => {
  // Vue3 的 Composition API 倡议应用 provide + inject 的形式注册和应用全局 property
  app.provide('mask', Mask);
};

// 应用的时候
const Mask = inject('mask');

最初,因为翻页动效和路由都在一起应用,就持续封装了个 useNext 函数,这样在个别的 view 组件应用的话,就非常简单了,同时做了翻页动效和翻页的操作:

nextPage();

到这里我能够夸夸 Composition API 了,十分的简略和不便,通过这个全局通用组件的封装,我彻底喜爱上了这种形式。

云层动效

这部分是我感觉最乏味的,以前用 three.js 实现过一个 3D 照片墙,然而这个云层动效真的牛,也是最难破解的,还好被我搞定了,下篇具体阐明破解的过程。

源码

最初放上源码,感兴趣的同学能够看一下,欢送 Star 和提出倡议。

退出移动版