请优先使用 MIP 现有机制和官方组件来实现业务功能
通常的前端业务代码的功能需求大概包含以下几个方面:
- 异步请求数据;
- 异步渲染节点;
- 操作节点的样式、内容;
- 监听事件并触发行为;
- 异步传输数据;
MIP 目前已经提供了相当完善的机制来覆盖上述功能,因此在绝大部分业务场景下,都可以优先使用 MIP 现有机制和组件来实现。
异步请求数据
MIP 提供了三种方式来实现异步数据的请求:
mip-data 加载异步数据
其中优先使用 mip-data,其使用方法如下所示:
<mip-data
src="https://path/to/your/api"
></mip-data>
加载到的数据可以通过 HTML 节点数据绑定、MIP.getData()
等方式去获取数据。假设上面的例子当中后端接口返回的数据为:
{
"a": 1,
"b": 2,
"c": [3, 4, 5, 6]
}
那么可以通过 m-bind 表达式 将相应的数据展示出来:
<div m-bind:class="{ active: a === 1 }" m-text="'当前 c 的值为:[' + c.join(',') + ']' "></div>
这样数据加载完成之后,就能够变成:
<div class="active">当前 c 的值为:[3,4,5,6]</div>
通过 MIP.setData()
方法进行 mip-data 数据操作可以时时修改相应的绑定结果,比如结合 on 表达式,我们可以举例实现点击按钮时触发上述 div 的 class:
<button on="tap:MIP.setData({ a: a === 1 ? 0 : 1 })" >点击</button>
在上述例子中每点击一次按钮,都会触发数据 a
数值在 0 和 1 之间相互切换,上述 div 也会因此不停地添加或删除 class active
:
<!-- a === 0 -->
<div class="">当前 c 的值为:[3,4,5,6]</div>
<!-- a === 1 -->
<div class="active">当前 c 的值为:[3,4,5,6]</div>
mip-list 加载异步数据
mip-list 主要用于异步加载数据后前端渲染节点,目前支持的功能包括:
- mip-list 组件首次加载时通过 src 属性请求列表首屏数据,并渲染节点;
- 支持通过
.more
事件触发加载分页数据并持续加载列表; - 仅支持 JSONP 格式的请求方式;
对于需要异步请求首屏数据并前端渲染节点的这类需求,可以考虑利用 mip-list 来实现这一功能:
<mip-list
src="https://path/to/your/jsonp/api"
>
<template type="mip-mustache">
<div class="wrapper">
{{#show}}
<header>{{content}}</header>
{{/show}}
</div>
</template>
</mip-list>
<button on="tap:simple-list.more">
假设后端返回的数据格式为:
{
"status": 0,
"data": {
"items": [
{
"show": true,
"content": "Hello"
},
{
"show": false,
"content": "World"
}
]
}
}
那么 mip-list 加载完成时得到的 HTML 为:
<mip-list>
<div role="list">
<div role="listitem">
<div class="wrapper">
<header>Hello</header>
</div>
</div>
<div role="listitem">
<div class="wrapper"></div>
</div>
</div>
</mip-list>
由此可以看到,mip-list 是具有一定的增删节点的能力的,因此可以利用 mip-list 来实现节点的增删功能。mip-list 的节点增删功能需要配合上 mip-data 才能够更好地发挥出来,相关功能我们正在开发当中:mip-list 动态特性升级。
mip-script 异步加载数据
mip-script 为 MIP 提供了限制性的 JS 能力,可以读取数据、操作数据以及发送请求,一般配合 mip-data 的 MIP.setData/MIP.getData/MIP.watch 进行使用。下面的例子展示了当某项数据发生变化时发送请求:
<mip-data>
<script type="application/json">
{
"a": {
"b": 1
}
}
</script>
</mip-data>
<button on="tap:MIP.setData({
a: { b: 2 }
})"
>点我</button>
<mip-script>
MIP.watch('a.b', function (newVal, oldVal) {
fetch('https://path/to/api?val=' + newVal)
.then(function (res) {
return res.json()
})
.then(function (data) {
MIP.setData({
newValue: data
})
})
})
</mip-script>
异步渲染节点
异步渲染节点目前可通过 mip-list 来实现。mip-list 接受一个数组对象作为数据源,当列表项数据长度为 1 时,mip-list 渲染结果自动退化为普通的 mustache 模板渲染。开发者可以通过定义 mustache 模板来定义异步渲染的节点效果。
在使用 mip-list 之前需要注意的是,当前的开发需求是否需要对节点进行增删操作。好的页面设计应该是定义好 MIP 页面的显示框架,然后异步请求数据进行填充。最佳的实践方式仍然是推荐使用 mip-data + m-bind 表达式来实现异步数据对页面的填充工作而非使用 mip-list 来进行节点增删。
操作节点的样式和内容
m-bind 表达式 提供了:m-bind:class
(推荐)、m-bind:style
来提供 mip-data 与节点样式的绑定,这样我们只需要在 on 表达式/mip-script 里面操作 mip-data,就能够实现节点的样式的增加/删除。
对于节点内容文本,我们提供了 m-text 表达式来实现文本计算和展示:
<div
m-bind:class="{ active: a === 1 }"
m-text="'当前 c 的值为:[' + c.join(',') + ']' "
></div>
这样,通过 MIP.setData()
去非常方便地实现节点的样式和文本操作啦:
MIP.setData({
a: 2,
c: [1,2,3,4,5]
})
事件的监听和触发
我们提供了 on 表达式来实现前端事件监听与触发,比如常见的点击事件,可以通过监听 tap 事件:
<button
on="tap:MIP.setData({ count: count == null ? 1 : count + 1 })"
m-text="'当前点击次数为:' + count"
></button>
除了 tap
click
表单元素的 change
事件之外,不同的 MIP 官方组件都会抛出一些自定义事件,我们都可以通过 on 表达式来进行事件的监听以及一些行为的处理。
比如 mip-date-countdown 提供了 timeout
实现定时;mip-position-observer 组件提供了一系列页面滚动事件的监听等等,大大拓展了 on 表达式的能力。
开发者可以利用 on 表达式实现某些组件的事件监听,在监听到事件发生时能够去触发其他组件的方法,或者是提供数据计算的能力,从而利用 m-bind 机制实现数据驱动。
上面已经演示过了 on 表达式与 mip-data 的联动过程,下面的例子展示如何在 on 表达式里触发其他组件的行为:
<button on="tap:simple-text.show">点我展示文本</button>
<button on="tap:simple-text.hide">点我隐藏文本</button>
<p>文本</p>
异步数据传输
目前实现数据传输的方法包括:
- mip-form(优先使用)
- mip-script
基于 mip-form 实现异步数据传输
其中 mip-form 表单组件是用于传统的表单数据提交,用法和 <form>
差不多:
<mip-form method="get" url="https://path/to/your/api">
<input type="text" name="username">
<input type="number" name="age">
<input type="submit" value="提交">
</mip-form>
当然 mip-form 在 form 的基础上还增加了异步数据提交、表单数据前端校验等功能,在这里不做赘述,感兴趣的同学移步 mip-form 的组件文档。
我们还可以与 mip-data / mip-bind 通过 m-bind:value
同时监听 input 的 input-debounced
事件实现数据的双向绑定:
<div m-text="'当前输入的名字为:' + username"></div>
<mip-form method="get" url="https://path/to/api">
<input type="text" name="username" m-bind:value="username"
on="input-debounced:MIP.setData({ username: event.value })">
</mip-form>
mip-form 提供了 .submit
来实现 on 表达式控制表单的提交:
<button on="tap:simple-form.submit()">点击提交</button>
<div m-text="'当前输入的名字为:' + username"></div>
<mip-form method="get" url="https://path/to/api">
<input type="text" name="username" m-bind:value="username"
on="input-debounced:MIP.setData({ username: event.value })">
</mip-form>
在这种 on 表达式控制表单提交的形式下,我们甚至可以将 mip-form 设置为隐藏 layout="nodisplay"
,完全依靠 on 表达式和 bind 表达式来实现对 mip-form 的数据传输控制:
<button on="tap:simple-form.submit()">点击提交</button>
<div m-text="'当前输入的名字为:' + username"></div>
<mip-form method="get" url="https://path/to/api"
layout="nodisplay">
<input type="text" name="username" m-bind:value="username"
on="input-debounced:MIP.setData({ username: event.value })">
</mip-form>
基于 mip-script 实现异步数据传输
由于 mip-script 能够使用 fetch/fetchJsonp,因此必然能够实现异步数据传输,这里就不再赘述了。但由于 mip-script 的体积较大,从性能的角度考虑,应该优先使用 mip-form 来实现数据提交。
总结
MIP 现有机制已经基本能够涵盖绝大部分的前端业务场景,并且提供了丰富的官方组件来进一步完善和提升 MIP 的功能和体验。因此在开发者提交第三方组件之前,请优先考虑这些功能是否已经有现成的机制或者组件实现了,这样将会大大降低第三方组件的开发和审核时间成本。