欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

react antd-mobile ActionSheet+tag實(shí)現(xiàn)多選方式

 更新時(shí)間:2023年10月23日 11:15:32   作者:YING-FINE  
這篇文章主要介紹了react antd-mobile ActionSheet+tag實(shí)現(xiàn)多選方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教

實(shí)現(xiàn)效果如下

在手機(jī)下方彈出彈窗

選擇月份點(diǎn)確定后

再次點(diǎn)擊申請(qǐng)?jiān)路荩耙堰x的月份會(huì)自動(dòng)選上

全部功能描述

1、點(diǎn)擊輸入框,自動(dòng)彈出選擇彈窗(使用actionsheet,這部分不過(guò)多闡釋)

2、彈窗可多選的內(nèi)容由后臺(tái)接口傳入(或自己寫(xiě)數(shù)據(jù),看需求)

3、灰色部分為后臺(tái)返回的不可選擇的標(biāo)簽,不允許用戶點(diǎn)擊選擇(disabled)

4、選擇一個(gè)或多個(gè)標(biāo)簽后,點(diǎn)擊確定,保存選擇的標(biāo)簽,并在輸入框中顯示選擇的內(nèi)容。倘若沒(méi)有點(diǎn)擊確定,直接點(diǎn)取消或彈框外的區(qū)域關(guān)閉彈窗,則不會(huì)保存所選標(biāo)簽

4、再次點(diǎn)擊輸入框,彈窗會(huì)自動(dòng)勾選上之前選過(guò)的彈窗。之后操作可如上循環(huán)。

功能實(shí)現(xiàn)

一、從后臺(tái)獲取所有月份信息

這里就是普通的通過(guò)redux的網(wǎng)絡(luò)請(qǐng)求獲取數(shù)據(jù),按實(shí)際情況獲取數(shù)據(jù)

  getMouth = () => {
    const {dispatch} = this.props;
    dispatch({
      type: `${NAMESPACE}/getMouth`,
    });
  };

不允許點(diǎn)擊的月份

const disabledMouth = [2,5,8];

按理說(shuō),不允許點(diǎn)擊的月份也應(yīng)該通過(guò)后臺(tái)獲取,此處因?yàn)檫€沒(méi)拿到后臺(tái)接口,暫時(shí)用全局變量充當(dāng)不允許點(diǎn)擊的月份數(shù)組

二、添加組件的state數(shù)據(jù)

this.state = {
      checkMouth: [],//保存已選擇的月份
      allMouth: [],//保存月份標(biāo)簽的屬性數(shù)據(jù)
      temCheckMouth: [],//臨時(shí)保存已選擇的魚(yú)粉
      temAllMouth: [],//臨時(shí)保存月份標(biāo)簽的屬性數(shù)據(jù)
      sign: false//判斷用戶是否點(diǎn)擊確定
}

三、定義含有標(biāo)簽屬性的數(shù)組allMouth

getAllMouth = () => {
	//mouth即為第一步通過(guò)后臺(tái)拿到的model里state的月份值
    const mouth = this.props.mouth.data || '';
    const newMonth = [];
    if (mouth && mouth.length > 0) {
      mouth.map(item => {
        newMonth.push(
          {
            value: item.code,//可理解為每個(gè)月份的id
            label: item.detail,//月份標(biāo)簽需展示的內(nèi)容,如一月、二月等的字樣
            selected: false,//月份標(biāo)簽是否被選擇
            disabled: false//該月份是否不可點(diǎn)擊
          }
        )
      });
    }
    // 修改無(wú)法選擇的月份信息,把無(wú)法選擇的月份disabled置灰掉,不允許用戶點(diǎn)擊選擇
    disabledMouth.map(item => {
      newMonth[item].disabled = true;
    });
    // console.log(newMonth);

	// 把每個(gè)月份的屬性數(shù)據(jù)數(shù)組存入state
    this.setState({
      allMouth: newMonth,
      temAllMouth: newMonth
    })
  };

注:

一般后臺(tái)傳的數(shù)據(jù)只會(huì)有code和detail或其他內(nèi)容,不會(huì)有selected和disabled,所以此處我們要在數(shù)組手動(dòng)添加,給每個(gè)月份自己獨(dú)有的selected值和disabled值。

在最初默認(rèn)都是未選中和允許點(diǎn)擊狀態(tài)。

四、保存月份屬性數(shù)組allMouth

  componentDidMount() {
    let timer;
    new Promise(resolve => {
      this.getMouth();
      timer = setInterval(() => {
        if (this.props.mouth.data) {
          resolve();
        }
      }, 100);
    }).then(() => {
      this.getAllMouth();
      clearInterval(timer);
    });
  }

這部分代碼其實(shí)我考慮了很久,因?yàn)檫@里有一個(gè)前提條件

必須通過(guò)getMouth()后臺(tái)請(qǐng)求到數(shù)據(jù)之后,getAllMouth()才能訪問(wèn)數(shù)據(jù),初始化月份數(shù)組數(shù)據(jù)并放到state

但是在這一步我報(bào)錯(cuò)了很久,因?yàn)樘热羝胀▽?xiě)法(如下)

this.getMouth();×
this.getAllMouth();×

這一步雖然顯示網(wǎng)絡(luò)請(qǐng)求成功了,但是props.mouth并沒(méi)有拿到數(shù)據(jù)!

這一步該如何寫(xiě)思考了很久,直接簡(jiǎn)單實(shí)用promise也不行

  componentDidMount() {    ×
    new Promise(resolve => {    ×
      this.getMouth();    ×
          resolve();    ×
    }).then(() => {    ×
      this.getAllMouth();    ×
    });    ×
  }    ×

此處getMouth()方法的確是執(zhí)行完了,只是還沒(méi)拿到數(shù)據(jù),所以這樣子寫(xiě)是不行的

而且componentDidMount正常來(lái)說(shuō)只會(huì)執(zhí)行一次,所以在componentDidMount執(zhí)行完,而model的state還沒(méi)拿到數(shù)據(jù)的時(shí)候,盡管過(guò)了一段時(shí)間拿到數(shù)據(jù)了this.getAllMouth(); 也不會(huì)再次執(zhí)行了,所以初始化無(wú)法進(jìn)行。

思前想后,能解決這一步的只能多次執(zhí)行,確保拿到數(shù)據(jù)了,再進(jìn)行this.getAllMouth();初始化數(shù)據(jù)。便有了上方代碼的操作。

當(dāng)然,開(kāi)了定時(shí)器記得用完就關(guān)!這一步操作可能性能上不太友好,如果大家有什么更好的方法,請(qǐng)多多指教呀~

五、遍歷顯示月份

上面步驟成功后,可以看到我們初始化的月份數(shù)組allMouth是這樣的,接下來(lái)就可以讓他們展示出來(lái)了

(注:0號(hào)全選是后臺(tái)一同傳過(guò)來(lái)的,大家可忽略)

input框:

<div onClick={this.handleMouth}>
	<InputItem placeholder="請(qǐng)選擇申請(qǐng)?jiān)路? readonly="readonly" clear >
		申請(qǐng)?jiān)路?
	</InputItem>
</div>

點(diǎn)擊后彈出彈窗

主要是使用ActionSheet彈出彈窗顯示內(nèi)容,不多闡述。詳情可見(jiàn)antd-mobile文檔

  handleMouth = () => {
    const {allMouth} = this.state;
    //這一步是為了刪去數(shù)組第一條全選數(shù)據(jù),全選不需要顯示。可忽略
    const newMouthData = allMouth && allMouth.slice(1);

    const modalData = (
      <div className={styles.modalStyle}>
        <div className={styles['tag-body']}>
          <div style={{textAlign: 'left'}}>可選擇月份(可多選)</div>
          <div className={styles['tag-box']}>
            {
              newMouthData && newMouthData.map((item) => {
                return (
                  <Tag
                    data-seed="logId"
                    onChange={(selected) => this.handleOnTagChange(selected, item.value)} // 用戶點(diǎn)擊不同月份時(shí)觸發(fā)的方法(詳情見(jiàn)下方標(biāo)題六)
                    selected={item.selected}// 控制不同月份的選中狀態(tài)
                    disabled={item.disabled}// 控制不同月份是否可點(diǎn)擊
                  >
                    {item.label}
                  </Tag>
                )
              })
            }
          </div>
        </div>
      </div>
    )
    const button1 = (
      <div className={styles.buttonStyle}>
        <span>取消</span>
        <span onClick={this.handleConfirm}>確定</span>//詳情請(qǐng)見(jiàn)標(biāo)題七的內(nèi)容
      </div>
    )
    const BUTTONS = [modalData];
    ActionSheet.showActionSheetWithOptions({
        options: [button1],
        message: BUTTONS,
      },
      // 關(guān)閉頁(yè)面執(zhí)行的方法
      (buttonIndex) => {
		this.closePage();//詳情請(qǐng)見(jiàn)標(biāo)題八的內(nèi)容
      });
  };

六、選擇不同月份觸發(fā)事件

handleOnTagChange = (selected, value) => {
	/**
	*  用戶在彈窗選擇月份時(shí),雖然當(dāng)前處于選中狀態(tài)。
	*  但是倘若用戶選擇完畢時(shí)不點(diǎn)擊確定,而且直接關(guān)閉頁(yè)面
	*  則之前選中的月份都不應(yīng)該保存!所以此處用臨時(shí)數(shù)組進(jìn)行保存
	*  只有用戶點(diǎn)擊確定,才把選擇的所有內(nèi)容保存到正式的數(shù)組中
	*/
    const {temAllMouth, temCheckMouth} = this.state;

    // 修改月份對(duì)應(yīng)的selected屬性
    const newAllMouth = JSON.parse(JSON.stringify(temAllMouth));
    newAllMouth[value].selected = selected;
    // console.log(newAllMouth);

    // 記錄選中的月份
    const newCheckMouth = JSON.parse(JSON.stringify(temCheckMouth));
    if (selected) {//如果選中,把選中的月份添加進(jìn)數(shù)組
      newCheckMouth.push(parseInt(value));
    } else {//如果是取消選中,需要把之前的選中從數(shù)組中刪除
      const deleteMouth = newCheckMouth.findIndex(item => item == value);
      newCheckMouth.splice(deleteMouth, 1);
    }
    // console.log(newCheckMouth);

    this.setState({
      temCheckMouth: newCheckMouth,
      temAllMouth: newAllMouth
    });
  };

關(guān)于const newAllMouth = JSON.parse(JSON.stringify(temAllMouth))的解釋:

這一步其實(shí)我繞了很多彎路,最后一步步排除錯(cuò)誤才發(fā)現(xiàn)我犯了個(gè)超級(jí)低級(jí)的錯(cuò)誤!

因?yàn)檫@個(gè)方法中,我們很明顯需要修改數(shù)組,但是我們不能直接修改state的數(shù)據(jù)

所以必須在方法中深拷貝state的數(shù)組,對(duì)新數(shù)組進(jìn)行修改,最后再通過(guò)setstate把新數(shù)組賦值給state的數(shù)組。

而在寫(xiě)代碼最初,我是直接

const {temAllMouth, temCheckMouth} = this.state;
const newAllMouth = temAllMouth;×××××錯(cuò)誤范例?。?!

很明顯這樣寫(xiě)是錯(cuò)誤的!直接賦值是把temAllMouth的地址賦值給了newAllMouth ,兩者其實(shí)沒(méi)有區(qū)別,修改newAllMouth 也會(huì)修改到state的數(shù)據(jù)temAllMouth,故出現(xiàn)問(wèn)題。

所以最后直接把temAllMouth通過(guò)JSON深拷貝一份,保證newAllMouth與temAllMouth不相同,互不干擾。

七、點(diǎn)擊確定觸發(fā)實(shí)現(xiàn)

handleConfirm = () => {
    const {temCheckMouth, temAllMouth} = this.state;

    /**
    * 對(duì)選中月份進(jìn)行排序
    * 因?yàn)殛P(guān)閉彈窗后需要在input框中顯示用戶選擇的月份
    * 而用戶選擇的順序是不定,所以temCheckMouth保存的選中月份也是亂的
    * 故此處為了美觀,對(duì)選中月份進(jìn)行了排序
    * 使用的是最簡(jiǎn)單的冒泡排序,可以忽略
    */
    const newCheckMouth = JSON.parse(JSON.stringify(temCheckMouth));
    if (newCheckMouth && newCheckMouth.length > 1){
      newCheckMouth.map((item,index) => {
        for (let j = 0; j<newCheckMouth.length-index;j+=1){
          if (newCheckMouth[j] > newCheckMouth[j + 1]){
            const temp = newCheckMouth[j];
            newCheckMouth[j] = newCheckMouth[j + 1];
            newCheckMouth[j + 1] = temp;
          }
        }
      });
    }
    console.log('選中的月份--' + newCheckMouth);

	// 此時(shí)用戶點(diǎn)擊確定按鈕,需要把之前保存的臨時(shí)數(shù)據(jù)賦值給正式的數(shù)組
    this.setState({
      allMouth: temAllMouth,
      checkMouth: newCheckMouth,
      temCheckMouth: newCheckMouth,
      sign: true //確定頁(yè)面
    });

	// 把選中的月份展示在input框,只有用戶有選擇月份的情況才需要展示
    if (temCheckMouth){
      this.props.form.setFieldsValue({ sqzzjtyf: newCheckMouth.toString() });
    }
  }

八、關(guān)閉彈窗觸發(fā)事件

注:這里關(guān)閉彈窗并不是點(diǎn)擊取消或者點(diǎn)擊彈窗外的手機(jī)部分關(guān)閉彈窗時(shí)才會(huì)觸發(fā)!!

點(diǎn)擊確定之后關(guān)閉彈窗同樣會(huì)觸發(fā)!?。。](méi)注意這部分就會(huì)出現(xiàn)錯(cuò)誤!

	closePage = () => {
        setTimeout(()=>{
          const {checkMouth, allMouth, sure} = this.state;
          // sure=false代表用戶沒(méi)有點(diǎn)擊確定,則需要把之前保存的臨時(shí)數(shù)據(jù)重置,保證用戶下次打開(kāi)彈窗時(shí)數(shù)據(jù)的正確性
          if(!sure){
            this.setState({
              temCheckMouth: checkMouth,
              temAllMouth: allMouth
            });
          }else{ // 把點(diǎn)擊確定時(shí)修改的sure=true修改回false,保證下次再次打開(kāi)彈窗的正確性
            this.setState({
              sure: false
            });
          }
        },50)
	}

此處使用settimeout的原因:

上面也說(shuō)了,這里調(diào)用的方法是只要關(guān)閉了彈窗就會(huì)執(zhí)行,而該方法的執(zhí)行順序與用戶點(diǎn)擊確定的執(zhí)行順序應(yīng)該是不相上下的(此處未做深入研究,不確定兩者的執(zhí)行順序)

而這里我們有一個(gè)必須前提,關(guān)閉彈窗的這個(gè)方法必須在點(diǎn)擊確定的方法后面執(zhí)行,原因如下:

在點(diǎn)擊確定方法后,我們會(huì)設(shè)置sure=true,并且把checkMouth和allMouth設(shè)置為新的值

而倘若關(guān)閉彈窗方法沒(méi)有在確定方法后執(zhí)行,則關(guān)閉彈窗方法執(zhí)行的時(shí)候,sure值仍為false!并且checkMouth和allMouth也扔為舊值

這樣,該方法就會(huì)執(zhí)行

      temCheckMouth: checkMouth(舊值),
      temAllMouth: allMouth(舊值)

如此,用戶之前點(diǎn)擊確定應(yīng)該要保存的數(shù)據(jù)就沒(méi)有保存成功了!錯(cuò)誤就出現(xiàn)了!

故此處使用settimeout保證該方法執(zhí)行的延后!

總結(jié)

以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • react native圖片解析流程詳解

    react native圖片解析流程詳解

    這篇文章主要為大家介紹了react native圖片解析流程詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-01-01
  • react native基于FlatList下拉刷新上拉加載實(shí)現(xiàn)代碼示例

    react native基于FlatList下拉刷新上拉加載實(shí)現(xiàn)代碼示例

    這篇文章主要介紹了react native基于FlatList下拉刷新上拉加載實(shí)現(xiàn)代碼示例
    2018-09-09
  • React Native第三方平臺(tái)分享的實(shí)例(Android,IOS雙平臺(tái))

    React Native第三方平臺(tái)分享的實(shí)例(Android,IOS雙平臺(tái))

    本篇文章主要介紹了React Native第三方平臺(tái)分享的實(shí)例(Android,IOS雙平臺(tái)),具有一定的參考價(jià)值,有興趣的可以了解一下
    2017-08-08
  • React高級(jí)概念之Context用法詳解

    React高級(jí)概念之Context用法詳解

    在React應(yīng)用中,為了讓數(shù)據(jù)在組件間共享,常見(jiàn)的方式是讓它們以props的形式自頂向下傳遞,如果數(shù)據(jù)要在組件樹(shù)不同層級(jí)共享,那么這些數(shù)據(jù)必須逐層傳遞直到目的地,Context如同管道,它將數(shù)據(jù)從入口直接傳遞到出口,使用Context能避免“prop-drilling”
    2023-06-06
  • react如何實(shí)現(xiàn)表格多條件搜索

    react如何實(shí)現(xiàn)表格多條件搜索

    這篇文章主要介紹了react如何實(shí)現(xiàn)表格多條件搜索問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2024-03-03
  • React高級(jí)指引之Refs and the DOM使用時(shí)機(jī)詳解

    React高級(jí)指引之Refs and the DOM使用時(shí)機(jī)詳解

    在典型的React數(shù)據(jù)流中,props是父組件與子組件交互的唯一方式。要修改一個(gè)子組件,你需要使用新的props來(lái)重新渲染它。但是,在某些情況下,你需要在典型數(shù)據(jù)流之外強(qiáng)制修改子組件
    2023-02-02
  • React配置子路由的實(shí)現(xiàn)

    React配置子路由的實(shí)現(xiàn)

    本文主要介紹了React配置子路由的實(shí)現(xiàn),我們來(lái)通過(guò)一個(gè)簡(jiǎn)單的例子解釋一下如何配置子路由,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-06-06
  • React利用路由實(shí)現(xiàn)登錄界面的跳轉(zhuǎn)

    React利用路由實(shí)現(xiàn)登錄界面的跳轉(zhuǎn)

    這篇文章主要介紹了React利用路由實(shí)現(xiàn)登錄界面的跳轉(zhuǎn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2021-04-04
  • react實(shí)現(xiàn)同頁(yè)面三級(jí)跳轉(zhuǎn)路由布局

    react實(shí)現(xiàn)同頁(yè)面三級(jí)跳轉(zhuǎn)路由布局

    這篇文章主要為大家詳細(xì)介紹了react實(shí)現(xiàn)同頁(yè)面三級(jí)跳轉(zhuǎn)路由布局,一個(gè)路由小案例,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2019-09-09
  • React中事件綁定this指向三種方法的實(shí)現(xiàn)

    React中事件綁定this指向三種方法的實(shí)現(xiàn)

    這篇文章主要介紹了React中事件綁定this指向三種方法的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2021-05-05

最新評(píng)論