在 nautil 中发明 react 双向绑定的功能,原来早有前人实践过了,而且还是 react 官方博客发布。从思路和用法上几乎一样,只是官方方法仅支持 input 等表单组件,而无法满足自定义组件的使用。不过,值得骄傲的是,我发明的 createTwoWayBinding 函数还是有不错的思想,而且借助了 Proxy 的力量。总之,自己以为很牛叉的东西,可能前人早都做过了,我们总是在炒冷饭中自鸣得意。
babel remove class static properties
在开发 nautil 过程中我发现,react 本身会在 production 模式下去掉 prop-types 的校验,但是在我们自己写的业务代码中,会给每个 class 增加 propTypes,于是找到了一个 babel 插件,这个插件可以去掉 react 组件类中声明的 propTypes 这个静态属性。于是我想直接用这个插件,可以删除 nautil 中的 props 属性吗?最后发现是不以的,这个插件写死了被移除的属性是 propTypes,所以,我必须自己写一个插件来实现这个功能。经过对该插件的改造,我增加了一个 properties 参数,可以实现移除任意类的静态属性。并且发布到了 npm,你可以在这里了解。
echarts x 轴最后一个刻度右对齐
在我们的数据图表中,x 轴的最后一个 label 应该是右对齐的。echarts 官方没有参数来配置这个功能,导致文字被截掉了半截。挺失望的,这种情况实在是太有需求了。在不能修改源码的情况下,我们只能通过自己手动来实现这个需求。
xAxis: {
type: 'category',
boundaryGap: true,
data: xAxisData,
axisTick: {
show: false,
},
axisLine: {
lineStyle: {
width: 1,
color: '#ccc',
}
},
axisLabel: {
color: '#89889C',
showMinLabel: true,
showMaxLabel: true,
formatter: (() => {
let currentYear = ''
return (value, index) => {
const year = value.substr(0, 4)
const month = value.substr(4, 2)
const shouldNotShowYear = index > 0 && currentYear === year
const isLast = value === xAxisData[xAxisData.length - 1]
const text = shouldNotShowYear ? month : year + '/' + month
const label = isLast && !shouldNotShowYear ? `{a|${text}}` : text
currentYear = year
return label
}
})(),
rich: {
a: {
width: 70,
align: 'left',
},
},
},
上面红色部分是关键,我们要让最后一个 label 靠右对齐,但是它受到宽度的限制,所以我们干脆来了一个宽度,直接将 label 的宽度和文字的整体高度相等,这样就可以让文字显示完整了。
但是,你可能会说,我怎么知道文字的总体宽度是多少?label 的字数可多可少,不可控啊。我会告诉你,有一个东西可以帮助你在 canvas 中获取文本的宽高,你听说过吗?通过 canvas 计算文字宽高之后,赋值给 rich 里面的 width。echarts 内部会根据你给定的宽度重新布局 x 轴文本的展示,由于我们设置了 showMaxLabel,所以,无论如何最后一个 label 都会展示,如果空间不够,它会把前一个 label 隐藏起来。
touches, targetTouches, changedTouches
在移动端 touch 事件中,有 touches, targetTouches, changedTouches 这三个属性,它们都是一个 Touch 对象的列表,但它们所代表的意思不同:
- touches: 当前在屏幕上的触点,因为同一时间,用户可能有多个手指同时触摸在屏幕上,touches 中保存了所有触点信息
- changedTouches: 触发当前这个 touch 事件的真正触点信息,当然,也可能有两个以上的手指同时触发,比如 touchmove 事件,可以由两个以上手指同时触发
- targetTouches: 列出 touches 中与 touchstart 事件时所在 target element 相同的 Touch 对象,如果由于 touchmove 移动出了 touchstart 时的 element,那么 targetTouches 不会包含不在 element 中的那些触点信息。
因为 touch 事件和 mouse 事件不同,touch 事件指出事件发生时屏幕上的所有触点信息,表明可能存在多个触点。但是由于事件是不连续的,为了区分触点,Touch 对象会有一个 identifier 属性,它是一个 0 开始的索引值。手指放到屏幕时,会用一个 identifier 标记它,这样开发者就可以知道当前 changedTouches 中每个触点和其他触点的具体对应关系了。
带摩擦因子的加速度距离计算公式
因为要写一个库,用以模拟现实世界的运动逻辑。在经典力学里,我们常常用匀速运动来说事,但现实中哪有那么好的事情,摩擦力等阻力会让速度慢下来,重力加速度会让速度越来越快等等。
已知:某物体以 v1 的初始速度被加速前进,t1 秒后,速度达到了 v2(v2 > v1)。
求:t2(t2 > t1)时停止加速,物体滑行多长距离之后停下来?
当看到这个题目,作为文科生,我完全懵逼,把毕生学到当物理学知识翻出来也找不到快速解决的办法。所以,只能通过自己的推演慢慢解决这道题目。
分析
这道题的特别之处在于受到了阻力影响,且运动过程分为两段。那么接下来我们来进行受力分析。

第 1 阶段由于受到比 f 大的 F 力的助推,所以呈实际受力为 F – f 的推力,匀加速运动。第 2 阶段由于只受 f 阻力,所以呈匀减速运动。
关于加速运动用到的公式有如下:
- 求加速度公式 a = (v2 – v1) / t
- 求距离公式 s = v1t + at2/2
且公式中如果 v1 为 0,那么更加简单。
由于第 2 阶段物体停下来,只受 f 阻力影响,因此,我们只需要知道 f 所带来的减速度,以及 t2 时的即时速度即可算出滑行需要的时间,进而算出滑行距离。
开始解题
1.计算第一阶段加速度
a1 = (v2 – v1) / t
2.计算到达 t2 时的速度
vx = a1 * t2 = (v2 – v1) * t2 / t
3.计算计算阻力减速度
即时速度比较好算,但是 f 所带来的减速度是多少呢?
根据牛顿第二定律 F = ma。因为质量固定,所以摩擦力 f 所产生的减速度 ax 是固定的。同时根据动摩擦力公式 f = µFn = µG = µmg(µ 为动摩擦因子)。质量和重力加速度都是固定的,所以最终 ax 的大小仅仅和动摩擦因子有关,也就是物质表面的粗糙程度,ax = ƒ(µ)。
现在,我们假设在没有阻力的情况下所产生的加速度为 a0:
kµ = ax / a0
即损失加速度与理想状态(无阻力)加速度之比,k 为一个常量系数,表示摩擦因子与加速度损失之间的某种特定关系,那么
ax = ƒ(µ) ≈ µa0
而对于同一个事物,µ 是固定不变的。又因为
ax = a0 – a1
所以
ax = µa0 = a0 – a1
=> a0 = a1 / (1 – µ)
=> ax = a0 – a1 = a1 / (1 – µ) – a1
=> ax = µa1 / (1 – µ) = µ(v2 – v1) / t(1 – µ)
现在我们得到了摩擦力带来的减速度。
4. 计算停下来要花的时间
我们就可以得到从 t2 开始减速到停止所需要花费的时间:
tx = vx / ax
5. 计算停下来之前滑行的路程
在该时间内物体前进的距离是多少呢?
sx = ax * tx2 / 2
经过上面这些步骤我们就算出了物体滑行的距离。
多端统一开发
这段时间关注了一些利用 react 实现跨平台开发的方案,几乎无一例外,都不能很好的满足我的需要。我的理想是,特别针对移动端开发,写一份代码,然后编译到不同平台,直接运行,除了修改编译工具配置和少量的全局覆盖以外,不对应用本身的代码做任何修改。
我写 Nautil 的目的也是这样。
目前我接触到的跨端开发方案有:
- taro 京东出品,相对比较成熟,需要理解其工作原理,在写法上需要开发者自己遵循一些规则
- kbone 微信小程序团队自己成员开发的针对微信小程序方案,理念上提供虚拟 DOM 挂载节点,从而让整个应用像运行在 web 内部一样,不需要考虑兼容性问题
- remax 理念上和 kbone 很像,同时提供自己的一整套构建、框架,不足在于需要根据不同的小程序引入不同的库,当然,这个可以用构建工具来 alias
目前我自己使用了 kbone 希望能出现更好的方案来解决我的需求。
Great minds discuss ideas;
Average minds discuss events;
Small minds discuss people——埃莉诺·罗斯福(Eleanor Roosevelt)


