vue或React中数据格式的转换

在开发中最常见的业务就是渲染数据了, 通常情况下接口会返回下面这样的数据类型:

{
  code: 1,
  message: 'success',
  data: {
    list: [
      {
        id: 1,
        name: 'zzz'
      },
      {
        id: 2,
        name: 'ccc'
      }
      ...
    ]
  }
}

这种格式非常好处理, 但有时候我们也会碰到一些特殊的业务功能需要对数据进行转换处理, 比如下面这种业务模式: 需要根据时间来计算某一时间段内有多少笔订单, 订单金额总共多少, 并且渲染出该时间段内的订单.

但是接口数据并不是按照时间进行返回的, 而是类似于上面这种:

{
  data: {
    list: [
      {
        id: 1,
        name: 'zzz',
        time: '2021-02-01'
      },
      {
        id: 2,
        name: 'ccc',
        time: 2021-02-02'
      },
      {
        id: 3,
        name: 'ddd',
        time: '2021-02-01'
      }
      ...
    ]
  }
}

在这种情况下我们前端就要对数据进行转换, 以方便在页面上渲染.

转换方法

const group = () => {
  const obj = {}
  if (Array.isArray(arr)) {
    for (var i = 0; i < arr.length; ++i) {
      var up_time = arr[i].up_time
      if (up_time in obj) obj[up_time].push(arr[i])
      else obj[up_time] = [arr[i]]
    }
  }
  // console.log('obj', obj)
  return obj
}

getDataList().then(res => {
  const {code, message, data} = res

  const arr = []

  const tempList = group(data.list)

  for (let i in tempList) {
    let o = {};
    //即添加了key值也赋了value值 o[i] 相当于o.name 此时i为变量
    o[i] = tempList[i]; 
    arr.push(o)
  }
  // this.dataList即为我们要在页面上渲染的数据
  this.dataList = arr
})

最后返回的dataList格式为

[
  {
    '2020-02-01': [
      {
        id: 1
        name: 'zzz',
        time: '2020-02-01'
      },
      {
        id: 3,
        name: 'ddd',
        time: '2020-02-01'
      }
    ]
  },
  {
    '2020-02-02': [
      {
        id: 2,
        name: 'ccc',
        time: '2020-02-02'
      }
    ]
  }
]

渲染数据(Vue)

<scroll-view scroll-y="true" v-if="TabCur === 0">
  <view class="ready-list" v-if="dataList.length > 0">
    <view class="ready-list-box" v-for="(item, index) in dataList" :key="index">
      <view class="" v-for="(value, key, index) in item" :key="key">
        <!-- {{value}}---{{key}}--{{index}} -->
        <view class="time">
          <text>{{key | timeFormat}}</text>
        </view>
        <view class="statistic_box">
          <view class="statistic_top">
            <view class="statistic_top--left">
              <text>{{value.length || '0'}}</text>
              <text>收款笔数</text>
            </view>
            <view class="statistic_top--right">
              <text v-if="value.length > 0">{{value | filterAmount}}</text>
              <text v-else>0.00</text>
              <text>实收金额(元)</text>
            </view>
          </view>
        </view>
        <view class="" v-for="subItem in value" :key="subItem.id">
          <view class="statistic_box">
            <view class="statistic_bottom">
              <view class="statistic_bottom--bottomLeft">
                <u-icon
                  name="zhifubao-circle-fill"
                  color="#2979ff"
                  size="80"
                  v-if="subItem.pay_type === 'zfb'"
                ></u-icon>
                <u-icon
                  name="weixin-circle-fill"
                  color="#2979ff"
                  size="80"
                  v-else
                ></u-icon>
                <view class="statistic_bottom--bottomLeft-data">
                  <text>{{$u.timeFormat(subItem.up_time, 'hh:MM:ss')}}</text>
                    <text>[收款]{{subItem.shop_name}}</text>
                </view>
              </view>
              <view class="statistic_bottom--bottomRight">
                <text>{{subItem.price}}</text>
                <text>交易成功</text>
              </view>
            </view>
          </view>
        </view>
      </view>
    </view>
  </view>
  <view class="load-more" @click="loadMore">
    <text>{{tips}}</text>
  </view>
</scroll-view>

特殊处理(Vue)

上面的例子中由于我们转换的数据的格式的特殊性, 虽然渲染到页面上了但业务中一些其他要求比如计算2020-02-01时间内所有订单额的总和就有些问题了, 我们无法直接在页面中进行计算, 所以这里通过过滤器进行计算.

filters: {
  filterAmount(value) {
    let num = 0
    value.forEach(i => {
      sum += i.price
    })
    return sum
  }
}

另外我们在页面中对value进行了判断, 因为value初始化渲染时是null或者undefined, 如果要用过滤器计算订单总额这里的value必须是Array, 否则渲染时会报错’value.forEach() is not a function’

在React中转换渲染

funciton filterAmount(value) {
  if (value.length === 0) return 0
  var sum = 0
  value.forEach(i => {
    sum += Number(i.price)
  })
  return sum
}

const getBill = async (params) => {
  const {code, data, message} = await bill(params)
  console.log(params, data)
  var arr = []
  if (code === 1) {
    // 如果当前页返回数据长度大于0则先将上一页数据和当前页数据进行合并然后转换
    // 否则说明当前页没有数据, 返回上一页数据
    var _tempData = []
    // 第二页没有数据, 返回临时数据
    if (data.list.length > 0) {
      // 第一次请求有数据, 临时存数据[]和返回数据合并
        _tempData = group(tempCancelBillData.concat(data.list))
      // 缓存上一次数据
      setTempCancelBillData(data.list)
    } else {
      _tempData = []
    }
    for (let i in _tempData) {
      let o = {};
      o[i] = _tempData[i];
      arr.push(o)
    }
    setBillData(arr)
  } else {
    return
  }
}

<ScrollView
  refreshControl = {
    <RefreshControl
      refreshing={isRefreshing}
      onRefresh = {onRefreshHandle}
    />
  }
>
  {
    billData.length > 0
    ? billData.map((item, index) => {
        return (
          <View key={index} style={styles.itemBox}>
            {
              Object.entries(item).map(([key, value], index) => {
                return (
                  <View key={index}>
                    <View style={styles.time}>
                      <Text>
                        {
                          key ?
                            moment.unix(Number(key)).format('YYYY-MM-DD') :
                            ''
                        }
                      </Text>
                    </View>
                    <View style={styles.mid}>
                      <View style={styles.midLeft}>
                        <Text>{value.length}</Text>
                        <Text>收款笔数</Text>
                      </View>
                      <View style={styles.midRight}>
                        <Text>
                          {
                            filterAmount(value)
                          }
                        </Text>
                        <Text>实收金额(元)</Text>
                      </View>
                    </View>
                    <View style={styles.bottom}>
                      {
                        value.map((subItem, index) => {
                          return (
                            <View key={index} style={styles.bottomBox}>
                              <View style={styles.bottomLeft}>
                                <Image style={styles.img} source={require('../assets/auth.png')} />
                                <View style={styles.bottomLeftData}>
                                  <Text>
                                    {
                                      subItem.up_time ?
                                        moment.unix(Number(subItem.up_time)).format('YYYY-MM-DD HH:mm:ss') :
                                        ''
                                    }
                                  </Text>
                                  <Text>[收款]{subItem.shop_name}</Text>
                                </View>
                              </View>
                              <View style={styles.bottomRight}>
                                <Text>{subItem.price}</Text>
                                <Text>交易成功</Text>
                              </View>
                            </View>
                          )
                        })
                      }
                    </View>
                  </View>
                )
              })
            }
          </View>
        )
    }) : null
  }
</ScrollView>

以上就是在业务中对数据进行特殊转换的例子.