312019.8

带摩擦因子的加速度距离计算公式

因为要写一个库,用以模拟现实世界的运动逻辑。在经典力学里,我们常常用匀速运动来说事,但现实中哪有那么好的事情,摩擦力等阻力会让速度慢下来,重力加速度会让速度越来越快等等。

已知:某物体以 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 / a

5. 计算停下来之前滑行的路程

在该时间内物体前进的距离是多少呢?

sx = ax * tx/ 2

经过上面这些步骤我们就算出了物体滑行的距离。

12:44:20 已有0条回复
302019.8

多端统一开发

这段时间关注了一些利用 react 实现跨平台开发的方案,几乎无一例外,都不能很好的满足我的需要。我的理想是,特别针对移动端开发,写一份代码,然后编译到不同平台,直接运行,除了修改编译工具配置和少量的全局覆盖以外,不对应用本身的代码做任何修改。

我写 Nautil 的目的也是这样。

目前我接触到的跨端开发方案有:

  • taro 京东出品,相对比较成熟,需要理解其工作原理,在写法上需要开发者自己遵循一些规则
  • kbone 微信小程序团队自己成员开发的针对微信小程序方案,理念上提供虚拟 DOM 挂载节点,从而让整个应用像运行在 web 内部一样,不需要考虑兼容性问题
  • remax 理念上和 kbone 很像,同时提供自己的一整套构建、框架,不足在于需要根据不同的小程序引入不同的库,当然,这个可以用构建工具来 alias

目前我自己使用了 kbone 希望能出现更好的方案来解决我的需求。

10:01:05 已有0条回复
232019.8

手绘风格组件

Great minds discuss ideas;
Average minds discuss events;
Small minds discuss people

——埃莉诺·罗斯福(Eleanor Roosevelt)

09:11:14 已有0条回复
222019.8

webpack umd library only for root, replace exports

webpack 导出的 umd 模块在传入了 output.library 的情况下,会输出四个条件语句,大概如下:

if(typeof exports === 'object' && typeof module === 'object')
  module.exports = factory(require("a"), require("b"));
else if(typeof define === 'function' && define.amd)
  define(["a", "b"], factory);
else if(typeof exports === 'object')
  exports["o"] = factory(require("a"), require("b"));
else
  root["o"] = factory(root["a"], root["b"]);

这样的 umd 模式。其中,关于依赖、导出接口名都可以定制,其中依赖部分通过 externals 配置来定制,导出接口名通过 library 来定制。

但是,现在的一个情况是,在第三个条件句,即红色部分,这个部分会在标准的 commonjs 中被引用。所谓标准的 commonjs 是由 commonjs 官方定义的,只有 exports 和 require 两个关键字的模块方案。而 nodejs 虽然遵循 commonjs,但是在其基础上实现了 module 关键字,将 exports 作为 module.exports 的引用,因此被成为 commonjs2。

我们现在去看这个部分,倘若一个模块在遵循标准 commonjs 的情况下,导出如下:

// a.js
exports.a = function a() {}
// b.js
exports.b = function b() {}
// main.js
export.a = require('./a.js')
export.b = require('./b.js')

外部使用这个包,实际上应该是:

const { a, b } = require('./main.js')

但是在 webpack 的 umd 模块下使用时变成了:

// bundle.js
exports.o = factory()

那么在外面的其他程序去用这个包时就需要变成下面这种方式才可以:

const { o } = require('./bundle.js')
const { a, b } = o

这显然不符合我们的期望,我们希望即使 webpack 打包之后,仍然保持原有的使用方式。所以,我写了一个方法来修改这个部分的输出,经过处理之后,webpack 这个部分的输出将会是:

else if(typeof exports === 'object')
	{ var a = factory(require("a"), require("b")); for (var i in a) exports[i] = a[i]; }

即替换掉原来的输出形式,将原本的输出接口直接赋值到 exports 上,这样就保持了原本的逻辑。

具体做法如下:

// webpack.config.js
const { bufferify } = require('webpack-bufferify')
const plugins = [
  bufferify(function(content, file, assets, compilation, compiler) {
    if (file.split('.').pop() !== 'js') {
      return
    }
    const { optimization } = compiler.options
    content = content.toString()
    content = optimization.minimize === true
      ? content.replace(/exports\[.*?\]=(.*?):/, `function(e,a){for(var i in a)e[i]=a[i]}(exports,$1):`)
      : content.replace(/exports\[.*?\](.*?);/, `{ var a$1; for (var i in a) exports[i] = a[i]; }`)
    return content
  }),
]

module.exports = {
  ...,
  plugins,
}

webpack-bufferify 是我写的一个组件,用以替换 webpack 输出的结果内容。通过上面的处理,就可以实现我们的目的。

13:13:25 已有0条回复
122019.8

收集 scroll 事件

scroll 事件是不支持冒泡的,那么怎么收集呢?当然是在捕获阶段进行收集了。

document.addEventListener('scroll', (e) => {
  const target = e.target
  const isTop = Object.getPrototypeOf(target).constructor.name === 'HTMLDocument'
  const scrollLeft = isTop ? window.scrollX : target.scrollLeft
  const scrollTop = isTop ? window.scrollY : target.scrollTop
  console.log({ target, scrollLeft, scrollTop })
}, true)

这样就可以通过兼容方式收集到滚动事件的信息了。

11:22:46 已有0条回复