Suggest 3.0.0
输入提示组件, 根据用户的输入给出待选项并展示在输入框下方。 Suggest的内容分为两个区域, 推荐区域(recommendTmpl)会在用户输入开始前渲染, 可以用来给出一些热门推荐。 结果区域(resultTmpl)用来响应用户的输入, 根据用户的输入给出输入提示。
引用方式
import { Suggest } from '$yo-component';
// 如果你的项目中未使用最新的 ykit-config-yo 插件,可能无法使用上面这个语法糖
// 你仍然可以通过下面这种方式来引用
import Suggest from 'yo3/component/suggest';
基础使用
Suggest
一般是一个占满整个页面的组件,它也可以配合模态框系列组件一起使用。在默认条件下,Suggest
的根节点会撑满整个父级容器。
Suggest
的最重要的属性是 results
和 onConditionChange
。使用这两个属性就可以改变结果区域的内容:
<Suggest
onConditionChange={condition => {
this.setState({ results });
}}
results={this.state.results}
/>
你应该把 results
属性和你应用的状态关联起来,这样在输入框的内容发生改变的时候会触发 conditionChange
事件,这时你可以根据新的 condition 字符串(onConditionChange
的唯一参数)去改变 results
,达到更新结果区域的目的。
定制结果列表项的渲染方式
results 默认的渲染方式是 List
,如果 results
属性数组中的每一个元素都有 text
属性, 会直接使用这个属性值作为列表项的内容。或者,就像 List
一样,
你也可以传入 renderItem
属性来指定列表项的渲染方式。它接收的参数和 List
的同名属性一致。以下是一个自定义 renderItem
的例子:
<Suggest
results={[
{value:'beijing'},
{value:'shanghai'},
// ...
]}
renderItem={(item,i) => {
return <p>`第${i}项的value是${item.value}`</p>
}}
noDataTmpl={<div>Nothing to show.</div>}
/>
通过定义 noDataTmpl
可以定制没有 results 数据时展示的内容,它可以接收一个 JSX,在 results.length
为 0
时会使用这个 JSX 渲染结果区域。
自定义结果区域的渲染方式
如果你不希望以默认的 List
形式渲染结果区域,可以通过定义 renderResult
属性来实现,你需要传入一个函数,这个函数可以接收到一个参数 results
,
并用它返回的 JSX/DOMElement 来完全取代原来的 List
:
<Suggest
results={/* ... */}
renderResult={results => {
return (
<CustomResult>
{results.map(result => {
return (
<ResultItem result={result} key={result.key}/>
);
})}
</CustomResult>
);
}}
/>
推荐区域
在输入框没有输入文字时,结果区域会被隐藏,取而代之的是推荐区域。换句话说,用户在打开 Suggest
时首先看到的是输入框以及推荐区域。
使用 recommendTmpl
可以指定推荐区域的渲染方式,它接收一个 JSX。
有些时候,你可能在聚焦到 input 时希望使用一个蒙层盖住下面的推荐区域,这样用户可以很方便的通过点击推荐区域来关闭键盘。使用 showMask
属性可以控制
蒙层是否在聚焦时展示蒙层。参见下面的例子:
<Suggest
recommentTmpl={<CityGrouplist /*...*/ />}
showMask={true}
// ...
/>
使用输入框图标
一般来说,Suggest
的输入框的最右侧都会根据当前的输入状态展示一个图标(例如输入框中有文字时会展示一个叉子用来快速清除输入)。Suggest
组件提供了
四种 icon:delete
、loading
、refresh
和 stop
。通过定义 inputIcon
属性,可以指定当前展示在输入框中的是哪一个图标,如果传入 null
,就不会
显示图标。
delete
图标的点击行为是确定的,即清空当前输入框的内容。对于其他三种图标,你可以指定 onIconTap
属性来定义点击它们的回调:
<Suggest
inputIcon={this.state.icon}
onIconTap={icon => {
switch (icon) {
case 'refresh':
// do something...
case 'stop':
// ...
}
}}
// ...
/>
onIconTap
可以接收一个参数 icon
,它会是上面四种图标的名称的字符串,这样你可以为不同的图标指定不同的点击回调。
输入事件的性能优化
每次 input 中 value 的改变都会触发 onConditionChange
,在用户输入较快时,可能会频繁导致 dom 更新,以及向服务器发送大量的请求,这对于 App 的性能十分不利。
为此我们提供了优化性能的手段——事件截流。
配置 throttleGap
属性即可开启事件截流(默认是开启的,值为 300
)。这个属性值表示间隔多少毫秒触发一次 onConditionChange,这样可以有效地减少无用的输入导致的 onChange。
<Suggest
throttleGap={500}
// ...
/>
这样可以让 onConditionChange
每 500
毫秒触发一次。
一个完整的城市选择器示例
以下的代码就是第一个 Demo 的源码,里面利用了 Grouplist
和 Suggest
实现了一个完整的城市选择器。在这份代码里包含了上面所有介绍的属性的使用。
class CitySelectDemo extends Component {
constructor() {
super();
this.state = {
results: [],
showLoadingIcon: false,
showCancelButton: false
};
}
filterCity(condition) {
return condition ? groupListDataSource
.filter(city=>city.groupKey !== '热门')
.filter(city=>city.py.search(condition) !== -1 || city.text.search(condition) !== -1) : [];
}
render() {
//实现一个如此复杂的组件只用了不到30行代码
//使用React,可以很容易地像搭积木一样用小组件搭建出大组件,而不是不停地重复造轮子
//善用组件化,开发效率可以成倍的提升
return (
<Page title="城市选择示例" onLeftPress={() => location.href = '../index.html'}>
<Suggest
showMask={true}
ref="suggest"
noDataTmpl={(
<div style={{ padding: '1em' }}>
{!this.state.loading ? 'No Result' : 'Loading...'}
</div>
)}
showCancelButton={this.state.showCancelButton}
onCancelButtonTap={()=> {
this.refs.suggest.clearInput();
}}
onFocus={()=> {
this.setState({ showCancelButton: true });
}}
onBlur={()=> {
this.setState({ showCancelButton: false });
}}
recommendTmpl={(
<Grouplist
infinite={true}
itemHeight={44}
infiniteSize={25}
dataSource={groupListDataSource}
sort={(a, b) => {
if (a === '热门') {
return -1;
}
else if (b === '热门') {
return 1;
}
return a.charCodeAt(0) - b.charCodeAt(0);
}}
showIndexNavBar={true}
onIndexNavBarItemHover={(groupKey) => Toast.show(groupKey, 1000)}
onItemTap={item => Toast.show('选择:' + item.text, 1000)}
/>
)}
inputIcon={this.state.loading ? 'loading' : 'delete'}
results={this.state.results}
onConditionChange={value => {
this.setState({ loading: true });
setTimeout(() => {
this.setState({ loading: false, results: this.filterCity(value) });
}, 300);
}}
onItemTap={item => Toast.show('选择:' + item.text, 1000)}
placeholder="输入城市名称或拼音"
throttleGap={500}
/>
</Page>
);
}
}
将Suggest和弹层结合使用
Suggest
最常见的使用方式有两种: 完全使用一个新的页面展示; 或者打开一个模态框来展示。
对于后者来说,你需要做的仅仅是把 Suggest
放入一个模态框系列组件中。
在使用模态层展示时,你可能需要在输入框的右侧显示一个"取消"按钮用来关闭它,设置 showCancelButton
属性为 true
就可以展示这个取消按钮,
然后通过 onCanelButtonTap
来定义它的行为。
下面是一个完整的例子:
class UseWithPopupDemo extends Component {
constructor() {
super();
this.state = {
show: false,
results: [],
defaultCondition: ''
};
}
render() {
return (
<Page title="带弹层的Suggest" onLeftPress={()=>location.href = "../index.html"}>
<div className="container">
<button
className="yo-btn open-modal"
onTouchTap={()=> {
this.setState({ show: true });
}}
>
与Popup一起使用,点我打开
</button>
<Popup
onMaskClick={()=> {
this.setState({ show: false })
}}
show={this.state.show}
height="100%"
>
<Suggest
ref="suggest"
showMask={false}
showCancelButton={true}
onCancelButtonTap={()=> {
this.refs.suggest.clearInput();
this.setState({ show: false });
}}
onConditionChange={value=> {
this.setState({ results: value ? getRandomDataSource(10) : [] });
}}
onItemTap={item=>Toast.show('tapping:' + item.text)}
defaultCondition={this.state.defaultCondition}
results={this.state.results}
recommendTmpl={<p style={{ padding: '1em' }}>设置showCancelButton为true可以展示取消按钮</p>}
noDataTmpl={<div style={{ padding: '1em' }}>No Results</div>}
/>
</Popup>
</div>
</Page>
);
}
}
results { Array } #
渲染在结果区的数据源,数组类型,数组元素的类型可以是字符串/数字,它们会直接作为列表项的内容;
也可以是对象,这个对象必须有text属性。
默认值: null
onConditionChange { Function } #
输入框onChange事件回调,必需。
为了使组件正常工作,你必须定义这个属性,根据每次的value来更新results。
默认值: null
方法参数:
参数名 | 类型 | 描述 | 支持版本 |
---|---|---|---|
value | String | 输入框当前的value |
extraClass { String } #
附加给组件根节点的额外类名。
默认值: null
itemTouchClass { String } #
点击结果区域列表项时添加的className。
默认值: item-light
noDataTmpl { Element } #
没有suggest结果时的模板。 noDataTpl
默认值: null
recommendTmpl { Element } #
推荐区域内容,在搜索条件为空时展示。
默认值: null
onItemTap { Function } #
点击结果项时的回调。
默认值: () =>{}
方法参数:
参数名 | 类型 | 描述 | 支持版本 |
---|---|---|---|
item | Object | 数据源中的元素 | |
index | Number | item在数据源中的index |
renderItem { Function } #
自定义结果项的渲染方式,返回JSX或字符串。
默认值: Suggest.renderItem
方法参数:
参数名 | 类型 | 描述 | 支持版本 |
---|---|---|---|
item | Object | 结果项的数据对象,格式为{value,text} |
renderResult { Function } #
自定义结果容器的渲染方式,返回JSX。
组件默认以List的形式渲染结果区域,如果不希望以List的形式展示结果,可以传入这个函数。组件会使用这个函数返回的JSX渲染结果区域。
默认值: null
方法参数:
参数名 | 类型 | 描述 | 支持版本 |
---|---|---|---|
results | 结果列表 |
infinite { Bool } 3.0.4 #
是否在结果区域的列表开启Infinite模式。注意:开启Infinite模式后,你需要为列表项配置key属性。
默认值: false
itemHeight { Number } 3.0.4 #
结果区域列表项的高度,只在Infinite模式下生效。
默认值: 44
infiniteSize { Number } 3.0.4 #
无穷列表模式下,保留在列表容器中列表项的个数(参见List组件无穷列表模式的说明)。
默认值: 20
showCancelButton { Bool } #
是否显示取消按钮,默认不显示。
默认值: false
cancelButtonText { String } #
取消按钮文本。
默认值: 取消
onCancelButtonClick { Function } #
点击取消按钮时的回调。
默认值: () =>{}
onSubmit { Function } #
点击键盘确定按钮时触发的回调。
默认值: ()=>{}
方法参数:
参数名 | 类型 | 描述 | 支持版本 |
---|---|---|---|
condition | 当前输入框的value |
onFocus { Function } #
输入框聚焦时的回调。
默认值: () =>{}
方法参数:
参数名 | 类型 | 描述 | 支持版本 |
---|---|---|---|
condition | 当前输入框的value |
onBlur { Function } #
输入框失去焦点时的回调。
默认值: () =>{}
方法参数:
参数名 | 类型 | 描述 | 支持版本 |
---|---|---|---|
condition | 当前输入框的value |
defaultCondition { String } #
展示在输入框中的默认值。
默认值: null
placeholder { String } #
输入框的placeholder。
默认值: null
inputIcon { String } #
展示在输入框右侧的icon,有四个icon可供选择:delete,loading,refresh和stop。
delete图标点击以后会清除输入框的内容,其余的三个图标可以通过传入onIconTap属性来定制点击它们的回调。
默认值: 'delete'
onIconTap { Function } #
点击input icon触发的回调。
默认值: () =>{}
方法参数:
参数名 | 类型 | 描述 | 支持版本 |
---|---|---|---|
iconName | 图标名称 | ||
condition | 当前输入框的value |
throttleGap { Number } #
设置此属性以后,文本框的onChange事件的触发频率会降低,例如设置为300会使得onChange每300毫秒触发一次.
通过这种方式,可以控制组件结果区域的render次数,降低和服务器交互的频率。
默认值: 300
showMask { Bool } #
在弹起键盘时,是否显示遮罩层。
clearInput #
清空输入框的内容