zoukankan      html  css  js  c++  java
  • Ant Design Pro中Transfer穿梭框的实际用法(与后端交互)

    Ant Design Pro中Transfer穿梭框的实际用法(与后端交互)


    该控件的属性以及属性的作用在ADP的官方文档中都有介绍,但没有讲如何与后端交互,本文旨在讲解该控件与后端的交互。
    Ant Design官方文档


    先来看需求是怎样的,以及实现的效果

    此处输入图片的描述

    需求:管理某个场馆中的活动,可以对这个场馆进行加入活动和移出活动。
    如图,初始进入到这个页面后,韵苑体育馆中有两个活动:活动1、活动5,其余活动在右边的框中(不属于该场馆)。选中右边框中的活动,可以进行移入操作。选中左边的活动,可以进行移出活动。

    第一步:从后端取数据

    (1)首先,我在该model(namesapce为themeList)的state中定义了两个数据

        activitys: {
          list: [],
        },
        emptyActivitys: {
          list: [],
        }
    

    activitys是上图中属于左边框的活动,即场馆中的活动。emptyActivitys是上图中右边框的活动,即不属于该场馆中的活动。这两个集合没有交集。

    (2)接下来就是该页面在加载的时候从后端取数据并放到这两个属性中,这里需要熟悉Ant Design Pro框架的用法以及React交互原理,就不再这里进行赘述了。

    第二步:引进该控件

    方便起见,我在使用这个控件时没有做代码规范,直接在该页面的代码上添加了该控件代码。

    @connect(({ themeList, loading }) => ({
      themeList,
      submitting: loading.effects['themeList/'],
    }))
    class App extends React.Component {
      handleChange = targetKeys => {
        const {
          themeList: { emptyActivitys },
        } = this.props;    //从model中取出emptyActivitys
        const { dispatch, themeList } = this.props;
    
        var addList = []; // 需要添加到当前场馆的活动
        var removeList = []; // 需要移出当前场馆的活动
    
        //每次点击按钮,都会判断是否有移出的活动或者移入的活动
        
        // 移出
        for (var i = 0; i < targetKeys.length; i++) { 
          var key = targetKeys[i];
          var has = false;
          for (var j = 0; j < emptyActivitys.list.length; j++) {
            if (emptyActivitys.list[j].key == key) {
              has = true;
              break;
            }
          }
          if (has) continue;
          removeList.push(key);
        }
        //targetKeys是右框中活动的Key,不是选中的Key,是在点击“移入”后(即用户已经看到了活动移过去)才调用handleChange
        
        // 移入
        for (var i = 0; i < emptyActivitys.list.length; i++) {
          var key = emptyActivitys.list[i].key;
          var has = false; 
          for (var j = 0; j < targetKeys.length; j++) {
            if (targetKeys[j] == key) {
              has = true;
              break;
            }
          }
          if (has) continue;
          addList.push(key);
        }
    
        //再利用两个for循环,实现接口调用
        for (var i = 0; i < addList.length; i++) {
          dispatch({
            type: 'themeList/api_addActivityToTheme',
            payload: {
              themeId: themeList.detailId,
              activityId: addList[i],
            },
          });
        }
    
        for (var i = 0; i < removeList.length; i++) {
          dispatch({
            type: 'themeList/api_deleteActivityFromTheme',
            payload: {
              themeId: themeList.detailId,
              activityId: removeList[i],
            },
          });
        }
      };
    
      render() {
        const {
          themeList,
          themeList: { activitys, emptyActivitys },
        } = this.props;
        var list = [];
        var keys = [];
    
        for (var i = 0; i < activitys.list.length; i++) {
          // 把场馆中的活动的id赋值给key属性
          activitys.list[i].key = activitys.list[i].activityId;
          // 把场馆中的活动加入到集合list中
          list.push(activitys.list[i]);
        }
    
        for (var i = 0; i < emptyActivitys.list.length; i++) {
          emptyActivitys.list[i].key = emptyActivitys.list[i].activityId;
          list.push(emptyActivitys.list[i]);
          keys.push(emptyActivitys.list[i].key);
        } //keys保留着不属于当前场馆的活动ID
    
        return (
          <Transfer
            dataSource={list}
            showSearch
            listStyle={{
               250,
              height: 300,
            }}
            operations={['移出', '移入']}
            targetKeys={keys} //targetKeys是页面右边的框:即不属于当前场馆的活动
            onChange={this.handleChange}
            titles={[themeList.detailName, '所有活动']}
            render={item => `${item.title}-${item.label}`}
          />
        );
      }
    }
    

    1、@connect不用介绍,用于将该控件与指定的medel绑定。
    2、该控件中只含有一个方法:handleChange
    3、在transer控件的属性中,targetKeys指的是右边框中的集合的Keys,所以我首先自定义了一个空的keys,然后把empyActivitys的key放到keys中。dataSource指的是所有的集合,即左边和右边的合集。所以在render中会有两个for循环,一个是将所有活动放在list中,另一个是将非场馆活动放在keys中。
    4、选中活动,点击按钮,会触发handleChange函数(点击按钮才触发,不是选中活动)。在该函数中,我定义了addList和removeList,用于指定哪些活动被添加或者被移除。
    5、用两个for循环,对addList和removeList进行填充。
    6、再用两个for循环,对addList和removeList中的每个元素进行相应接口的调用。

    第三步:修改当前的activitys和emptyActivitys

    在完成上述的加入和移出活动后,此时的activitys和emptyActivitys应该被改变,但在实际的model中他们是不会变的,所以只能自己手动的进行更改。

    先看看model中的effects的方法:

          *api_deleteActivityFromTheme({ payload }, { call, put }) {
          var activityId = payload.activityId;
          const response = yield call(api_deleteActivityFromTheme, payload);
          if (isResponseSuccess(response)) {
            // success
            yield put({
              type: 'save_deleteActivityFromStadium',
              payload: activityId,
            });
          } else {
          }
        },
        *api_addActivityToTheme({ payload }, { call, put }) {
          var activityId = payload.activityId;
          const response = yield call(api_addActivityToTheme, payload);
          if (isResponseSuccess(response)) {
            // success
            yield put({
              type: 'save_api_addActivityToStadium',
              payload: activityId,
            });
          } else {
          }
        },
    

    上述代码正是那最后两个for循环调用的接口

    然后该改变是在model中的reducer中进行改变的:

        save_api_addActivityToStadium(state, action) {
          var l = null;
          var list = [];
          for (var i = 0; i < state.emptyActivitys.list.length; i++) {
            if (state.emptyActivitys.list[i].activityId == action.payload) {
              l = state.emptyActivitys.list[i];
            } else {
              list.push(state.emptyActivitys.list[i]);
            }
          }
          state.emptyActivitys.list = list;
          state.activitys.list.push(l);
          return {
            ...state,
          };
        },
            save_deleteActivityFromStadium(state, action) {
          var l = null;
          var list = [];
          for (var i = 0; i < state.activitys.list.length; i++) {
            if (state.activitys.list[i].activityId == action.payload) {
              l = state.activitys.list[i];
            } else {
              list.push(state.activitys.list[i]);
            }
          }
          state.activitys.list = list;
          state.emptyActivitys.list.push(l);
          return {
            ...state,
          };
        },
    

    简单来说,就是在加入和移出后,我要更新activitys和emptyActivitys这两个数据,否则会造成逻辑的错误。

    注意:该控件的限制在于需要后端提供相应的接口,且算法不简单,但由于产品经理的硬性要求,不得已这么写了,有许多不规范的地方还请大佬们指教。

  • 相关阅读:
    sourceTree和eclipse 的使用
    oracle习题练习
    oracle详解
    单例模式
    反射详解
    Oracle 存储过程判断语句正确写法和时间查询方法
    MVC4 Jqgrid设计与实现
    遇到不支持的 Oracle 数据类型 USERDEFINED
    ArcGIS Server10.1 动态图层服务
    VS2010连接Oracle配置
  • 原文地址:https://www.cnblogs.com/tian874540961/p/10219021.html
Copyright © 2011-2022 走看看