MultiList 3.0.4

多级选择列表组件,该组件基于list组件封装,支持列表展示,支持自定义模板展示,内容异步加载等功能。

使用说明

引用方式

import { MultiList } from '$yo-component';

// 如果你的项目中未使用最新的 ykit-config-yo 插件,可能无法使用上面这个语法糖
// 你仍然可以通过下面这种方式来引用
import MultiList from 'yo3/component/multilist';

使用场景

这里展示的是 multiList 主要使用场景,用于多级列表选择。常见于去哪儿客户端、美团客户端、大众点评客户端,位置筛选功能。

class MultiListDemo extends Component {
  constructor(props) {
    super(props);
    this.state = {
      multiValue: [],
      dataSource: originalData
    };
  }
  handleValueChange({newValue}) {
    let value;
    // 最后一项选中项value值为0,则清空value,0通常是不限。
    if (newValue[newValue.length - 1] === DEFAULT) {
      value = [];
    } else {
      value = newValue;
    }
    this.setState({
      multiValue: value
    });
  }
  async handleUpdateData(item){
    switch (item.asyncType){
      case 'SUBWAY-2':
        originalData.subList[5].subList[1].subList = await fetchDataOfSubway();
        this.setState({
          dataSource: Object.assign({}, originalData)
        });
      break;
    }
  }
  render() {
    return (
      <Page title="multiList Demo" extraClass="demo-content">
        <MultiList
          dataSource={this.state.dataSource}
          value={this.state.multiValue}
          onChange={this.handleValueChange.bind(this)}
          onUpdateData={this.handleUpdateData.bind(this)}
        />
      </Page>
    );
  }
}

异步加载数据

该方法用于减少首次渲染数据的大小,不适用于替代首次数据的获取。下面是传入组件中用于渲染的 dataSource

const dataSource = {
  defaultValue: 1,
  subItemType: 'MENU',
  subList: [{
    name: '同步',
    value: 1,
    defaultValue: '1-1',
    subItemType: 'RADIO',
    subList: [{
      name: '1-1  默认选项',
      value: '1-1'
    }, {
      name: '1-2',
      value: '1-2'
    }, {
      name: '1-3',
      value: '1-3'
    }, {
      name: '1-4',
      value: '1-4'
    }]
  }, {
    name: '异步',
    value: 2,
    subItemType: 'RADIO',
    defaultValue: '2-2',
    subList: 'ASYNC',
    asyncType: '2-2'
  }]
};

组件按照 Value 和 defaultValue 来计算展开路径,并渲染组件。当渲染到 subListASYNC 的节点时会触发 onUpdateData 事件,并传入该层级数据内容作为参数,用户可以通过判断 Value 或自定义 key 值标记,获取数据更新 dataSource

class SimpleMultiList extends Component {
  // ...
  async handleUpdateData(item){
    /**
    * item 内容为
    * {
    *   name: '异步',
    *   value: 2,
    *   subItemType: 'RADIO',
    *   defaultValue: '2-2',
    *   subList: 'ASYNC',
    *   asyncType: '2-2'
    * }
    */
    switch (item.asyncType){
      case '2-2':
        testData[1].subList = await fetchData();
        this.setState({
          dataSource: {
            defaultValue: 1,
            subList: testData,
            subItemType: 'MENU'
          }
        });
      break;
    }
  }
  render() {
    return (
      <Page
        title="multiList Demo"
        extraClass="demo-content"
      >
        <MultiList
          dataSource={ this.state.dataSource}
          value={this.state.value}
          onUpdateData={this.handleUpdateData.bind(this)}
          onChange={({newValue}) => {
            this.updateValue(newValue);
            Toast.show(`您的选择是${newValue.join('>')}`)
          }}
        />
      </Page>
    )
  }
}

自定义内容

multiList 主要适用于多级选择列表,但是也支持自定义二级及二级以下内容的自定义。使用时传入 subList 传入自定义内容,触发 renderContent,该方法需返回一个 element。

const multiData = {
  subItemType: 'ProductMenu',
  subList: [{
    name: '产品1',
    value: 1,
    subList: 'product1'
  },{
    name: '产品2',
    value: 2,
    subList: 'product2',
  }]
};

class SimplaMultiList extends Component {
  constructor(props) {
    super(props);
    this.state = {
      dataSource: multiData,
      value: [1]
    }
  }
  updateValue(value) {
    this.setState({
      value,
    })
  }
  render() {
    return (
      <Page
        title="multiList Demo"
        extraClass="demo-content"
      >
        <MultiList
          dataSource={ this.state.dataSource}
          value={this.state.value}
          onChange={({newValue}) => {
            this.updateValue(newValue);
          }}
          onItemTap={({item})=>{
            return [item.value];
          }}
          renderItem={({itemType, data, isSpread, index})=>{
            switch (itemType){
              case 'ProductMenu':
                return <ProductMenu data={data} isSpread={isSpread} index={index}/>
            }
          }}
          renderContent={({type}) => {
            switch (type) {
              case 'product1':
                return <Product tit="product1" />;
              case 'product2':
                return <Product tit="product2" />;
            }
          }}
        />
      </Page>
    )
  }
}

ReactDOM.render(<SimplaMultiList /> , document.querySelector('#container'));
属性

dataSource { Array } #

dataSource 是一个树形的结构,每一个层级会有defaultValue,表示默认展开该哪个item或者默认选中项(非必填),subList为下级层级的内容,subList的每个字项设置内容如下。

  • name 为文字描述
  • value 该项value
  • subItemType 用于设置下一层级的list item使用的组件,内置 MENU,RADIO,CHECKBOX。如果传入的字符不在默认序列中会触发组件的renderItem方法,由用户自行渲染。
  • itemType 用于定义当前item 使用的组件,优先级高于父层级的 subItemType
  • subList支持数组和String类型,当传入array类型渲染为列表, 内置String为FAULTASYNCEMPTY对应内置模板分别用于展示加载错误,加载中,加载内容为空三种情况, 其中加载ASYNC会触发onUpdateData事件,通知用户更新数据。用户可以通过自定义字符串,触发renderContent方法, 返回ReactElement作为内容并进行其他操作。
  • defaultValue 表示该层级的默认值,若下一级为最后一层级表示,默认值[注意:默认值不会作为value]。
const dataSource = {
  defaultValue: 1,
  subItemType: 'MENU',
  subList: [{
      name: '同步',
     value: 1,
     defaultValue: '1-1',
     subItemType: 'RADIO',
     subList: [{
        name: '1-1  默认选项',
         value: '1-1'
     }, {
         name: '1-2',
         value: '1-2'
     }, {
         name: '1-3',
         value: '1-3'
     }, {
         name: '1-4',
         value: '1-4'
      }]
 }, {
     name: '异步',
     value: 2,
     subItemType: 'RADIO',
     defaultValue: '2-2',
     subList: 'ASYNC',
     asyncType: '2-2'
   }]
  };

value { Array } #

mutliList的值,该值为点选的value

onChange { Function } #

用于更新结果的回调函数

function({level, listValue, newValue, newItems}){
 	level 表示当前菜单层级
 	oldValue 表示当前multiList的value
 	newValue 表示更新后的multiList的value
     newItems 表示更新后的value对应的item
 	}

extraClass { String } #

给组件根节点附加的额外样式类

默认值: null

onItemTap { Function } #

当Item的类型不是'MENU'、'CHECKBOX'、'RADIO',该事件将会被触发。事件处理函数需要有返回值,该值将会作为newValue触发组件的onChange事件。

方法参数:

参数名 类型 描述 支持版本
父层数据,层级,改节点数据,该节点索引, data, level, item, index, target

renderItem { Function } #

当Item的类型不是'MENU'、'CHECKBOX'、'RADIO',该事件将会被触发。事件处理函数需要有返回值,返回值是PropsTypes.element类型作为Listitem

 renderItem={(item)=>{
const {itemType, data, isSpread, index} = item;
      JSON.stringify(item);
   // {  "itemType":"ProductMenu", 节点的Type类型(此时的`itemType`是组件根据父节点`subItemType`和该节点`itemType`按照优先级处理过的值。)
    //    "level":0, item所在层级
    //    "index":"2", item所在父节点subList
   //    "route": "1>2>1", item在dataSource中的索引值
    //    "isLeaf":false, 该节点是否为叶子节点
    //    "isSpread":false, 如果该节点为父节点时该值表示该节点是否是展开的
    //    "isChecked":false, 该节点是否是有效值
    //    "data":{"name":"产品2","value":2,"subList":"product2","key":1,"_index":1} 原数据内容`key`值为组建计算由于优化List性能,如原数据中有设置则使用原数据,单请调用者保证key值在该层级中的唯一性。
     // }
     switch (itemType){
         case 'ProductMenu':
          return <ProductMenu data={data} isSpread={isSpread} index={index}/>
      }
 }}

方法参数:

参数名 类型 描述 支持版本
父层数据,节点所在层级,节点数据,该节点在父节点`subList`中的索引, itemType, data, level, item, index, target

renderContent { Function } #

当subList的类型不是array,该事件将会被触发,事件处理函数需要有返回值,返回值是PropsTypes.element类型作为Listitem

renderContent={(item) => {
   const {type} = item;
      console.log(JSON.stringify(item));
     // {"type":"product1","data":{"name":"产品1","value":1,"subList":"product1","key":"1"},"level":1}
     switch (type){
         case 'product1':
           return <Product tit="product1" />;
         case 'product2':
           return <Product tit="product2" />;
      }
  }}

方法参数:

参数名 类型 描述 支持版本
节点的Type类型, itemType, data, level 父层数据,层级,改节点数据,该节点索引,

onUpdateData { Function } #

当加载的层级为ASYNC时触发,用于用户更新dataSource,用户通过获取数据中的内容判断如何更新dataSource。

方法参数:

参数名 类型 描述 支持版本
data 父节点的数据