mipengine / mip2

MIP (移动网页加速器)通过优化网页JS、控制资源加载顺序,达到加速网页的效果。
https://www.mipengine.org/
MIT License
184 stars 49 forks source link

打通数据驱动与事件驱动机制 #679

Open Brunoon opened 5 years ago

Brunoon commented 5 years ago

要解决什么问题

目前有: 1、数据驱动:通过 mip-data、mip-bind 能够将元素的属性和数据进行绑定,从而实现数据的变化影响元素的样式 2、事件驱动:通过 on 语法监听组件和全局抛出的事件,并触发元素的行为或者改变数据

所以现在 "事件->数据" 是可行的,但是 "数据->事件" 还没有支持,如果数据的变化能够触发特定事件或者行为,就能够完全由数据驱动,只需要修改数据就可以控制页面的样式与行为,便于开发与维护。

描述一下你理想中的解决方案

参考 amp 绑定特定属性触发行为的做法,比如 amp-lightbox,可以绑定 open 属性,控制组件的显示与隐藏状态,对应 open 和 close 行为。

该方案可以通过为组件添加 observedAttributes 和 attributeChangedCallback 实现。

描述你的备选方案

mip-data 监听数据的变化,当数据变化时抛出 data-changed 事件,从而触发相应行为。

由于数据变化不容易检测,而且对性能有较大影响,因此该方案不建议使用。

clark-t commented 5 years ago

679

目前为了解决 MIP 官方组件的 attributeChanged 实现程度较低的问题,新增了内置组件 <mip-data-watch> 来实现数据到事件的转换:

<mip-data-watch
  watch="data.key"
  on="change:element-id.doSomething(xxx)"
></mip-data-watch>

其中 watch 的取值与 MIP.watch 的第一个值相同,即仅支持点运算符的数据访问,为了支持更为复杂的表达式,我们可以选择将负责表达式的计算结果写到 data.key 里面来即可:

<div on="tap:MIP.setData({ data: { key: (a.b + c.d * 10086) } })">赋值</div>

从而扩展了 mip-data-watch 的适用范围。

clark-t commented 5 years ago

现在有个比较尴尬的点是,如果想要在一些全局方法或者是 MIP 组件方法里面获取 mip-data 数据,在目前情况下是不能直接实现的,但可以使用 <mip-data-watch> 拐个弯来获取:

<div on="tap:MIP.setData({
  url: 'https://www.baidu.com?user=' + user + '&age=' + age
})">click me</div>
<mip-data-watch 
  watch="url" 
  on="change:MIP.navigateTo(url=event.newValue)" 
  layout="nodisplay"></mip-data-watch>

这里存在两个问题:

  1. 如果 url 没有任何变化的话,就永远不会触发 onchange 事件;
  2. 无法控制当前的 url 变化后的值是不是真正需要的;

因此最好能够提供一些方法来解决这些问题

clark-t commented 5 years ago

新的想法是,新增一个官方组件 <mip-action> 提供全部的表达式解析支持:

<div on="tap:ac.execute">
<mip-action
  id="ac"
  conditon="abc > 0 && cde < 0"
  execute="id.doSomething(arg1=abc + cde, arg2=efg)"
></mip-action>
Brunoon commented 5 years ago

目前来看 <mip-action> 能够比较好地解决这个问题, 但是由于写法上与一般的 action 不同,在页面中容易引起混乱并导致用户写错, 是否能够全部 action 都支持表达式解析?

clark-t commented 5 years ago

经讨论之后认为,对于 MIP.navigateTo、MIP.scrollTo 等这些使用类似 AMP 的新版参数形式的写法下,支持受限制的运算之后,能够以最小的代价和最小的影响面来让行为读取到 mip-data 里的数据:

<mip-data>
  <script type="application/json">
  {
    "a": 1
  }
  </script>
</mip-data>
<div on="MIP.navigateTo(url='https://www.baidu.com?a=' + a)">click me</div>

同时 mip-action-macro 的功能主要是提供一个 conditon 判断条件来通过当前的状态判断是否要执行方法:

<mip-action-macro
  condition="a > 1"
  on="execute:MIP.navigateTo(url=host + '?a=' + a)"
></mip-action-macro>
clark-t commented 5 years ago

目前 MIP on 表达式里面可以使用 MIP.navigateTo、MIP.scrollTo 等等全局对象方法,但是这些方法并没有在 mip-script 当中暴露出来,形式上就不够统一,但是把他们开放给 mip-script 又担心开发者过渡依赖 mip-script 导致网页体验变差。 所以到底需不需要暴露出去呢?