我想分享我处理级联表单字段的 3 种方法。
- 第一种方法是通用的,使用状态变量。
- 第二种是使用普通变量和一个布尔状态变量来触发状态效果(刷新页面)。
- 第三种是带有普通变量的动态表单字段。
在这篇文章中,我们看到第一种方法,即基于国家、州、城市数据处理级联表单字段的常用方法。
套餐
react-native-element-dropdown react-native-paper
我们正在使用react-native-element-dropdown作为下拉字段
基页
import react, { usestate, useeffect } from "react"; import { view, text, stylesheet, touchableopacity } from "react-native"; import { dropdown } from "react-native-element-dropdown"; export default function app() { return ( <view style={styles.container}> <view> <text>country</text> <zdropdown data={[]} labelfield="" valuefield="" value={null} isfocus={false} onchange={null} /> <text>state</text> <zdropdown data={[]} labelfield="" valuefield="" value={null} isfocus={false} onchange={null} /> <text>city</text> <zdropdown data={[]} labelfield="" valuefield="" value={null} isfocus={false} onchange={null} /> </view> <view> <text>selected country</text> <text style={styles.selectedvalue}>{country.selectedcountry.name}</text> <text>selected state</text> <text style={styles.selectedvalue}>{state.selectedstate.name}</text> <text>selected city</text> <text style={styles.selectedvalue}>{city.selectedcity.name}</text> </view> <touchableopacity onpress={null} style={styles.clrbtn}> <text style={styles.clrbtntxt}>reset</text> </touchableopacity> </view> ); } const zdropdown = ({ data, labelfield, valuefield, value, onfocus, onblur, onchange, isfocus, }) => { return ( <dropdown mode={"auto"} style={[styles.dropdown, isfocus ? { bordercolor: "dodgerblue" } : {}]} placeholderstyle={styles.placeholderstyle} selectedtextstyle={styles.selectedtextstyle} inputsearchstyle={styles.inputsearchstyle} iconstyle={styles.iconstyle} search={data.length > 5} maxheight={300} searchplaceholder="search..." data={data} labelfield={labelfield} valuefield={valuefield} placeholder={!isfocus ? "select item" : "..."} value={value} onfocus={onfocus} onblur={onblur} onchange={onchange} /> ); }; const styles = stylesheet.create({ // style props });
zdropdown 是一个自定义组件。
样本数据
const listcountry = [ { countryid: "1", name: "india" }, { countryid: "2", name: "uk" }, { countryid: "3", name: "canada" }, { countryid: "4", name: "us" }, ]; const listsate = [ { stateid: "1", countryid: "1", name: "state1_india" }, { stateid: "4", countryid: "2", name: "state1_uk" }, { stateid: "7", countryid: "3", name: "state1_canada" }, { stateid: "10", countryid: "4", name: "state1_us" }, ]; const listcity = [ { cityid: "1", stateid: "1", countryid: "1", name: "city1_state1_country1", }, { cityid: "6", stateid: "2", countryid: "1", name: "city6_state2_country1", }, { cityid: "7", stateid: "3", countryid: "1", name: "city7_state3_country1", }, { cityid: "23", stateid: "8", countryid: "3", name: "city23_state8_country3", }, { cityid: "30", stateid: "10", countryid: "4", name: "city30_state10_country4", }, { cityid: "35", stateid: "12", countryid: "4", name: "city35_state12_country4", }, { cityid: "36", stateid: "12", countryid: "4", name: "city36_state12_country4", }, ];
表单变量
我们使用 4 个状态变量,其中 3 个用于表单字段,其余一个用于触发焦点效果。
export default function app() { const [country, setcountry] = usestate({ data: [], selectedcountry: {}, value: null, }); const [state, setstate] = usestate({ data: [], selectedstate: {}, value: null, }); const [city, setcity] = usestate({ data: [], selectedcity: {}, value: null }); const [ddfocus, setddfocus] = usestate({ country: false, state: false, city: false, }); return ( <view style={styles.container}> <view> <text>country</text> <zdropdown data={country.data} labelfield="name" valuefield="countryid" value={country.value} isfocus={ddfocus.country} onchange={null} /> <text>state</text> <zdropdown data={state.data} labelfield="name" valuefield="stateid" value={state.value} isfocus={ddfocus.state} onchange={null} /> <text>city</text> <zdropdown data={city.data} labelfield="name" valuefield="cityid" value={city.value} isfocus={ddfocus.city} onchange={null} /> </view> . . . </view> ); }
焦点和模糊事件比 onchange 事件更容易被触发,因此对于焦点更改,这里使用一个单独的状态变量,以免弄乱下拉数据更改。
负载国家
从示例数据中加载国家/地区下拉列表。 (可以使用api调用)
export default function app() { . . . const loadcountry = () => { // load data from api call setcountry({ data: [...listcountry], selectedcountry: {}, value: null }); }; useeffect(() => { loadcountry(); }, []); return ( . . . )
对焦/模糊
当选择一个下拉菜单时,该字段必须被聚焦,而其余字段应该被模糊。我们正在使用一个函数来处理这个问题。
const focusfield = (fld = '') => { const obj = { country: false, state: false, city: false }; if (fld) obj[fld] = true; setddfocus(obj); };
<text>country</text> <zdropdown . . . isfocus={ddfocus.country} onfocus={() => focusfield('country')} onblur={() => focusfield('')} onchange={null} /> <text>state</text> <zdropdown . . . isfocus={ddfocus.state} onfocus={() => focusfield('state')} onblur={() => focusfield('')} onchange={null} /> <text>city</text> <zdropdown . . . isfocus={ddfocus.city} onfocus={() => focusfield('city')} onblur={() => focusfield('')} onchange={null} />
我们现在已经完成了一半。
加载状态状态
在选择的国家/地区,我们需要根据所选国家/地区加载相应的州 states。
更新国家/地区字段,根据国家/地区选择加载州并关注国家/地区。
<text>country</text> <zdropdown . . . onchange={(item) => { setcountry({ ...country, selectedcountry: item, value: item.countryid, }); loadstate(item.countryid); focusfield(""); }} />
当国家/地区发生变化时,州和城市都会发生变化。因此,在设置新值之前,我们需要清除现有数据。
const loadstate = async (cntid) => { // load data from api call setstate({ data: [], selectedstate: {}, value: null }); setcity({ data: [], selectedcity: {}, value: null }); const arr = listsate.filter((ele) => ele.countryid === cntid); setstate({ ...state, data: [...arr] }); console.log("respective states ", arr); };
负载城市
并根据选择加载城市字段。
<text>state</text> <zdropdown . . . onchange={(item) => { setstate({ ...state, selectedstate: item, value: item.stateid }); loadcity(item.stateid); focusfield(""); }} />
const loadcity = async (stid) => { // load data from api call setcity({ data: [], selectedcity: {}, value: null }); const arr = listcity.filter((ele) => ele.stateid === stid); setcity({ ...city, data: [...arr] }); };
一切就绪,表单字段现在可以正常工作了。
如果我们再处理 2 个附加功能,我们就完成了。一种是休息页面,另一种是验证表单并显示警告。
重置页面
表单变量和焦点变量应该被清除。
. . . const resetform = () => { focusfield(""); setcountry({ data: [...listcountry], selectedcountry: {}, value: null }); setstate({ data: [], selectedstate: {}, value: null }); setcity({ data: [], selectedcity: {}, value: null }); }; . . . <touchableopacity onpress={() => resetform()} style={styles.clrbtn}> <text style={styles.clrbtntxt}>reset</text> </touchableopacity> . . .
警告
如果父字段值为空,我们必须显示警告消息。为此,我们使用 paper 中的 snackbar 组件。
import { snackbar } from "react-native-paper"; export default function app() { . . . const [visible, setvisible] = usestate(false); const [snackmsg, setsnackmsg] = usestate(""); const ontogglesnackbar = () => setvisible(!visible); const ondismisssnackbar = () => setvisible(false); . . . return ( <view style={styles.container}> . . . <snackbar duration={2000} visible={visible} ondismiss={ondismisssnackbar}> {snackmsg} </snackbar> </view> ); }
由于 state 和 city 字段有父字段,因此必须验证它们。
<Text>State</Text> <ZDropDown onFocus={() => { focusField('state'); if (!country.value) { setSnackMsg('Select country'); onToggleSnackBar(); focusField('country'); } }} . . . /> <Text>City</Text> <ZDropDown onFocus={() => { focusField('city'); if (!country.value) { setSnackMsg('Select country'); onToggleSnackBar(); focusField('country'); } else if (!state.value) { setSnackMsg('Select state'); onToggleSnackBar(); focusField('state'); } }} . . . />
是的,就是这样!我们完成了。谢谢。
完整代码参考这里