用Rax开发一个联想搜索输入框,内附封装后的npm组件
来淘系实习已经一个半月了,在这里接触了一个之前未了解过的开发框架:Rax。从最开始拿到需求看着Rax一脸蒙蔽,到现在渐渐熟悉用Rax做开发,这个过程中也让我遇到了Rax的大大小小的问题。下面就来分享一下如何用Rax开发一个联想搜索输入框。
需求——开篇
我们拿到手的需求是这样的:有一个输入框,它支持联想搜索,当输入框里有输入时,右侧会出现一个清空的icon,点击这个icon可以可以去清空这个输入框,可能会配“热搜词”,点击“热搜词”将该“热搜词”补全到输入框内。下面是手淘主搜的例子:
尝试——碰壁
这里我们考虑用Rax提供的TextInput组件去实现这个需求,该组件主要有下面这些属性(这里只放了部分属性,并非该组件的完整属性)
当我们看到点击icon清空输入框这个功能时,首先想到用受控组件去做,当点击icon时去改变value属性的值。(虽然TextInput有自带的clear方法,可以用来清空输入框,但是考虑到我们可能还要有赋值的场景,不考虑用clear方法)
import { createElement, useState, Fragment } from 'rax';
import View from 'rax-view';
import Text from 'rax-text';
import TextInput from 'rax-textinput';
import { EventObject } from 'rax-textinput/lib/types';
import './index.css';
function SearchInput() {
const [value, setValue] = useState<string>('');
const onInput = (e: EventObject) => {
setValue(e.value);
// 发起请求
// ...
}
return (
<Fragment>
<View className="container">
<TextInput className="input"
value={value}
onInput={onInput}/>
{
value
&& (
<Text onClick={() => setValue('')}>
清空
</Text>
)
}
</View>
<Text>
value: {value}
</Text>
</Fragment>
);
}
export default SearchInput;
因为我们的项目需要用到web端和weex端,看一下在两个容器中的效果。
web端看上去是没问题的,符合我们预期的效果。
weex端,发现当输入框里已经有中文的时候,我们无法在后面继续输入中文。这就不符合我们的预期,如果把这样一个输入框放在我们的项目里会非常影响用户体验的。
思考——解决
大胆猜测在weex端不能连续输入中文的原因:我们使用的受控组件,用户使用ios系统在输入中文时,会自动在两个字的拼音中间加入空格,而我们在onInput事件中给value赋值导致了拼音输入中断。
考虑换用非受控组件来完成我们这个需求。分析一下,输入框的值可以被两种方式改变:
(1)通过输入框输入
(2)点击“清空”,清空输入框。或者点击“热搜词”,将其赋值到输入框
对这两种赋值方式做处理:
import { createElement, useState, Fragment } from 'rax';
import View from 'rax-view';
import Text from 'rax-text';
import TextInput from 'rax-textinput';
import { EventObject } from 'rax-textinput/lib/types';
import './index.css';
function SearchInput() {
const [value, setValue] = useState<string>('');
const [defaultValue, setDefaultValue] = useState<string>('');
const [inputKey, setInputKey] = useState<number>(0);
// (1)输入框输入事件
const onInput = (value: string) => {
setValue(value);
// 发起请求
// ...
}
// (2)设置输入框的值(非输入事件)
const setInputValue = (text: string) => {
// 重新渲染输入框,并将要设的值赋给defaultValue
setInputKey(inputKey + 1);
setDefaultValue(text);
/*
可以考虑延迟重新渲染,优先触发输入事件
setTimeout(() => {
setInputKey(inputKey + 1);
setDefaultValue(text);
}, 20);
*/
// 触发输入事件
onInput(text);
}
return (
<Fragment>
<View className="container">
<TextInput className="input"
key={inputKey}
defaultValue={defaultValue}
onInput={(e: EventObject) => onInput(e.value)}/>
{
value
&& (
<Text onClick={() => setInputValue('')}>
清空
</Text>
)
}
</View>
<Text>
value: {value}
</Text>
</Fragment>
);
}
export default SearchInput;
我们看下效果
web端:
weex端:
可以看到,在两种容器里都达到了我们预期的效果。
封装——复用
当我们实现这个功能后考虑到以后复用,决定在Rax的TextInput组件上封装一下,重写它的onInput事件,并加上常用的函数防抖逻辑。
使用参考:
import { createElement, useState, Fragment } from 'rax';
import View from 'rax-view';
import Text from 'rax-text';
import DebounceTextInput from 'debounce-text-input';
import { EventObject } from 'rax-textinput/lib/types';
import './index.css';
function SearchInput() {
const [value, setValue] = useState<string>('');
const onInput = (text: string) => {
setValue(text);
// 网络请求
// ...
}
return (
<Fragment>
<View className="container">
<DebounceTextInput className="input"
value={value}
debounceInterval={600}
onInput={(e: EventObject) => onInput(e.value)}/>
{
value
&& (
<Text onClick={() => onInput('')}>
清空
</Text>
)
}
</View>
<Text>
debounceInterval: 600
</Text>
<Text>
value: {value}
</Text>
<Text onClick={() => onInput('felix')}>
set: felix
</Text>
</Fragment>
);
}
export default SearchInput;
web端:
weex端:
效果——结尾
最终我们这个需求顺利完成,效果如下:
本文地址:https://blog.csdn.net/FelixHsp/article/details/107140510
上一篇: C. Orac and LCM
下一篇: 随记,定个小目标