构建工程
fre 是一个 react17-like 的框架,它完全复现了 react17 的时间切片,异常恢复,lane 等先进特性,但尺寸只有 1kb
parcel 是一个 0 配置打包工具,它封装了一些常用工具,内部还有一套巧妙的 AST 和 缓存 算法
因为活动页是一个非常纯粹的单页 spa,所以基本上不需要 create-react-app 甚至是 webpack,而 fre 本身也可以完全替代 react,所以经过评估,我使用了 fre 和 parcel 进行了项目的总体构建
干净纯粹,没有一个多余的文件,没有一行多余的代码……
但在评估的过程中,需要考虑一些事情
1. parcel 的 dev server 问题
有时候需要跨域的时候,我们只能用 node 去重写 parcel 的 dev server,这个就很尴尬,因为我们用它就是为了不去写构建的代码,所以如果项目需要跨域等等,那用 parcel 会得不偿失
所以我和后端事先沟通好,让他加了域名白名单,这样以后我们前端都不需要做特殊的跨域处理了
解决了这个问题,那么基本上 parcel 就没什么大坑
2. public-url
parcel build index.html --public-url http://m.ximalaya.com/gatekeeper/share-fragment/11251754
还有一点就是 public-url,也就是我们线上需要配置的 cdn 地址,这个 feature 是我之前提的,直到 parcel2 才被支持
至此,parcel 就可以愉快的用起来啦,我们只写了一行配置~
3. fre 和 react 的差异
fre 不支持 class,然后 context 和 suspense 都是外置的
很多第三方库都不支持 fre,所以 fre 适用的场景也比较有限,但社区内有不少库提供了对 fre 的支持:
1\. wouter // 路由库
2\. goober // css-in-js 库
3\. user-context-selector // 更好的 context
...
所以理论上只要你乐意,都能找到更好的替代品,无论是代码质量还是测试覆盖率,都远超 react 生态中的库
以上,介于上面提到的各种权衡,我认为我手上的这个项目正好合适
由于换成了我最熟悉的框架和打包工具,所以整个开发过程十分流畅,但除了基本的工程,这个活动页业务方面也有一些东西比较值得存档
业务交互
上个截图先,可以看到这是一个非常简单的页面
1. 图片吸色
比较有意思的是图片吸色,意思是给你一张图片,你从中分析出来一个比较合适的颜色,然后用作背景
说实话这个需求在 安卓/ios 断是有现成的库的,然而对我们 h5 来说,机会没有库或者库的表现并不好
所以只好自己写一个了
export function getColor(ctx, pre = 20) {
if (!ctx.getImageData) ctx = ctx.getContext('2d')
const matrix = []
for (let x = 0; x <= ctx.canvas.width; x = x + pre) {
for (let y = 0; y <= ctx.canvas.height; y = y + pre) {
matrix.push([x, y])
}
}
let res = matrix.map(p => ctx.getImageData(p[0], p[1], 1, 1).data).filter(c => {
const l = c[0] * 0.30 + c[1] * 0.59 + c[2] * 0.11
return l > 50 && l < 200
}).map(c => {
const g = c.slice().sort((a, b) => b - a)
g[3] = (g[0] - g[g.length - 1]) / g[0]
return g
}).sort((a, b) => b[3] - a[3])
return res[res.length >>> 1]
}
短短 18 行代码,却无需太复杂的算法,也不用 AI 去分析,就可以得到一个合适的颜色
主要思路是对 canvas 进行取样,然后去除掉明度过爆过脏的颜色,然后再对饱和度进行筛选,不要太纯或太灰的颜色
这个和传统的颜色分析不同,因为它取得不是「出现最多」的颜色
比如你穿了一身灰,然后带了一顶绿帽子,我肯定不会取灰色,而是取绿色
因为其实从传统美术的角度来说,画面的和谐度并不在于【色调】,而在明度饱和度等的平衡度
最终大家都很满意,我也很欣慰
这个代码大家可以在业务中直接复制用,甚至还可以进行扩展,进行色相的分析
2. css 动画
这个页面中,还是有一些动画效果的,比如涟漪,比如头像的转动……
.ripple {
position: absolute;
height: 100px;
width: 100px;
top: 10px;
}
.ripple:before {
animation: ripple 2s ease-out infinite;
border: solid 1px #fff;
border-radius: 50%;
bottom: 0;
box-sizing: border-box;
content: "";
left: 0;
position: absolute;
right: 0;
top: 0;
}
.ripple:after {
animation: ripple 2s 1s ease-out infinite;
border: solid 1px #fff;
border-radius: 50%;
bottom: 0;
box-sizing: border-box;
content: "";
left: 0;
position: absolute;
right: 0;
top: 0;
}
@keyframes ripple {
0% {
opacity: 0.2;
}
100% {
opacity: 0;
transform: scale(2);
}
}
一般来说我很少用 js 写动画,但是 css 动画有个毛病,就是它属于「浏览器行为」,会被「js 行为」阻塞
这里就不得不说 fre 的时间切片了,当然这玩意 react 也有,本质上是调度浏览器行为和 js 行为的
就是同样的一段 css 动画,你在 vue 等没有时间切片的框架中会卡的不要不要的
但是在 fre 或 react 中会丝毫顺滑,所以为了利用这个优势,我已经很久没写过 js 动画啦
不过针对音频播放,上面的涟漪只是个简单实现
更靠谱的感觉应该是音频可视化,就是随着旋律进行律动,这个就需要分析 audio 的 buffer 才行
这个嘛,有需求了再说,哈哈哈哈
3. ios 的 currentTime 坑
ios 有个天坑,就是直接设置 currentTime 无效,这是因为 ios 必须要要等到 canplay 之后才能设置
if(isIOS()){
audio.addEventListener("canplay", function() {
audio.currentTime = currentTime;
});
} else {
audio.currentTime = currentTime;
}
总结
在我使用 fre 开发项目之前,我们公司都是使用的 react 和 umi,实习生要哭了,他们发现我连 webpack 都不用,简直惊呆了,哈哈哈哈
在合理评估下,使用新技术是一件愉快的事情,虽然 fre 对我来说是亲儿子,也没什么新鲜感
害,比较可惜的是,我转岗了,之后就要去写客户端了,可能就不怎么写活动页啦,但是类似的思路,大家可以供参考
之后争取给大家带来一些有关于客户端的文章吧呜呜
最后放一下相关的地址: