欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

用Rax开发一个联想搜索输入框,内附封装后的npm组件

程序员文章站 2022-03-12 09:13:21
来淘系实习已经一个半月了,在这里接触了一个之前未了解过的开发框架:Rax。从最开始拿到需求看着Rax一脸蒙蔽,到现在渐渐熟悉用Rax做开发,这个过程中也让我遇到了Rax的大大小小的问题。下面就来分享一下如何用Rax开发一个联想搜索输入框。需求——开篇我们拿到手的需求是这样的:有一个输入框,它支持联想搜索,当输入框里有输入时,右侧会出现一个清空的icon,点击这个icon可以可以去清空这个输入框,可能会配“热搜词”,点击“热搜词”将该“热搜词”补全到输入框内。下面是手淘主搜的例子:尝试——碰壁这....

来淘系实习已经一个半月了,在这里接触了一个之前未了解过的开发框架:Rax。从最开始拿到需求看着Rax一脸蒙蔽,到现在渐渐熟悉用Rax做开发,这个过程中也让我遇到了Rax的大大小小的问题。下面就来分享一下如何用Rax开发一个联想搜索输入框。

需求——开篇

我们拿到手的需求是这样的:有一个输入框,它支持联想搜索,当输入框里有输入时,右侧会出现一个清空的icon,点击这个icon可以可以去清空这个输入框,可能会配“热搜词”,点击“热搜词”将该“热搜词”补全到输入框内。下面是手淘主搜的例子:

用Rax开发一个联想搜索输入框,内附封装后的npm组件

尝试——碰壁

这里我们考虑用Rax提供的TextInput组件去实现这个需求,该组件主要有下面这些属性(这里只放了部分属性,并非该组件的完整属性)

用Rax开发一个联想搜索输入框,内附封装后的npm组件

当我们看到点击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端看上去是没问题的,符合我们预期的效果。

用Rax开发一个联想搜索输入框,内附封装后的npm组件
weex端,发现当输入框里已经有中文的时候,我们无法在后面继续输入中文。这就不符合我们的预期,如果把这样一个输入框放在我们的项目里会非常影响用户体验的。

用Rax开发一个联想搜索输入框,内附封装后的npm组件

思考——解决

大胆猜测在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端:

用Rax开发一个联想搜索输入框,内附封装后的npm组件
weex端:

用Rax开发一个联想搜索输入框,内附封装后的npm组件
可以看到,在两种容器里都达到了我们预期的效果。

封装——复用

当我们实现这个功能后考虑到以后复用,决定在Rax的TextInput组件上封装一下,重写它的onInput事件,并加上常用的函数防抖逻辑。

npm包:debounce-text-input

源码:debounce-text-input

使用参考:

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端:

用Rax开发一个联想搜索输入框,内附封装后的npm组件

weex端:

用Rax开发一个联想搜索输入框,内附封装后的npm组件

效果——结尾

最终我们这个需求顺利完成,效果如下:

用Rax开发一个联想搜索输入框,内附封装后的npm组件

本文地址:https://blog.csdn.net/FelixHsp/article/details/107140510