共计 3299 个字符,预计需要花费 9 分钟才能阅读完成。
介绍
《你的性情主导色》是往年网易云音乐前端团队开发的一款测试用户主导色的 H5 利用,上线后反应很好,刷爆了微博和朋友圈。
我的项目的次要开发者 imyzf
发表了一篇文章《官网揭秘!你的色彩是这样算进去的》,解释了一些动效和最初主导色的计算方面的问题。但因为波及到了具体的业务,所以作者没有开源出源码,然而热心的作者给了很多的提醒。我就是依据这些提醒,揭秘了我比拟感兴趣的局部。
在线 Demo
因为始终没有在生产环境中应用 Vue3.0
和vite
,所以源码局部我应用了 Vue3.0
+vite
实现。
页面预加载
答题类页面与个别的 H5 页面的不同之处在于,用户的操作门路是确定的,即每个页面的下一页路由是固定的,所以在 router 层面做了优化,提前预加载了下一个页面
因为流动页面应用了大量的视频和动效等,所以想在用户浏览选择题目标过程中把下一页的页面渲染结束,这样切换到下一页面的时候会很晦涩,体验很好。
最后就想着怎么利用 vue-router
实现页面的预加载。然而搞了一圈发现,都是基于 webpack
或者 vite
的懒加载,提前加载了一些资源,并不会提前渲染出页面。
起初通过看 vue-router
文档,才找到了灵感,利用命名视图,同时展现 2 个视图,应用 css
暗藏下一页,这时候尽管不显示,然而页面曾经渲染进去了。
通过批改 router-view
的 name
属性,实现页面的切换。也就是说,其实我的路由是没有变动的。
// 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 | |
} | |
} | |
]; |
看下面的代码,Index1
、Index2
和 Session1
等其实就是每一页的组件了,通过批改 currentViewName
和nextViewName
就能够达到页面切换的目标。
最终的成果是下图这样的,下一页曾经提前渲染进去:
翻页动效
作者提醒说应用 canvas
实现了页面切换时候的幕布拉动成果,次要使用了最外围的 canvas API
是 bezierCurveTo
。
通过查问得悉,bezierCurveTo
须要 3 个 点用来绘制三次贝赛尔曲线,在线体验
看下图,想要实现拉动动画,P1 P2 P3
的 X
轴坐标须要继续变动,而后绘制曲线,就可能实现拉动的成果了。
我这里应用了比拟轻量的 JavaScript
动画库animejs
,用来管制下面几个点的继续挪动。3 个动画成果别离挪动了P1 P2 P3
的X
轴坐标,再配合曲线的绘制,就达到了根本的拉动幕布成果。
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 和提出倡议。