Tencent / wepy

小程序组件化开发框架
https://wepyjs.gitee.io/wepy-docs/
Other
22.52k stars 3.05k forks source link

IOS 数据渲染问题 #2019

Open LYlanfeng opened 5 years ago

LYlanfeng commented 5 years ago

提交ISSUE前请确保已认真阅读以下内容

Please read the following information carefully before you open an issue.

在提交issue之前必须确认以下问题:

Please make sure you understand the following points:

阅读完后请在提交的issue中删除以上内容,包括分割线

DELETE THE INFORMATION ABOVE(INCLUDE THE SEPARATION LINE) BEFORE YOU OPEN AN ISSUE


Description

[问题描述:站在其它人的角度尽可能清晰地、简洁地把问题描述清楚] IOS上修改数据,调用$apply()更新,数据未渲染问题。

  1. 该问题主要存在在IOS上面,安卓和模拟器调试都没此问题
  2. 出现情况: 2.1 data格式定义如下:
    data: {
    targetImages: [],
    choose: {
    list: []
    }
    }

    js方法如下:

    
    // 初始化方法
    async init () {
    try {
      wepy.showLoading({
        title: '初始化图片'
      })
      const goods = await this.getGood()
      if (goods.code === 200) {
        this.array = goods.data.list || ''
      }
      let img = null
      for (let i = 0; i < this.imgs.length; i++) {
        img = {}
        const r = await this.getImage(this.imgs[i].image_url_url)
        img.url = this.imgs[i].image_url_url
        img.id = this.imgs[i].id
        let w = r.width
        let h = r.height
        let ch = (this.width / w) * h
        if (ch > this.height) { // 如果大于最大高度
          img.width = Math.floor((this.height / h) * w)
          img.height = this.height
        } else {
          img.width = this.width
          img.height = Math.floor(ch)
        }
        img.list = []
        const gl = this.imgs[i].goods_list
        if (gl && gl.length > 0) {
          gl.forEach(v => {
            if (v.image_info) {
              const xy = v.image_info.split('-')
              img.list.push({
                goods_id: v.goods_id,
                goods_title: v.goods_title,
                value: v.goods_title,
                x: xy[0],
                y: xy[1]
              })
            }
          })
        }
        this.targetImages.push(img)
      }
      this.imgIndex = 0
      this.choose = this.targetImages[this.imgIndex]
      wx.setNavigationBarTitle({
        title: `编辑(${this.imgIndex + 1}/${this.imgs.length})`
      })
      this.$apply()
    } catch (e) {
      console.error(e)
      wepy.showToast({
        title: '初始化图片失败',
        icon: 'none'
      })
    } finally {
      wepy.hideLoading()
    }
    }

// 选择一个产品,就给choose对象下面的list数组push一个对象 bindPickerChange (e) { let index = e.currentTarget.dataset.index const name = this.array[index].goods_title this.addTag(name, this.array[index]) this.show = false this.$apply() }, addTag (name, data) { tid++ const tag = { id: tid, x: 10, y: 10, value: name, data: data } this.choose.list.push(tag) this.$apply() }

发现类似情况在IOS上面比较多。
就是从一个数组中将一个对象赋值给data下面的对象,是引入方式的传递,所以数组中的对象和choose对象实际是同一个对象,当更改choose下面的对象,list下面的对象同时也同步更改,在调试器上基本上不会出问题。但是这种方式的实现逻辑在IOS上经常就是数据渲染不会更新视图,调用this.$apply()也是无效的。

  [Description of the issue]

## Environment

  * Platform: [开发者工具/iOS/Andriod/Web] IOS
  * Platform version: [对应工具或者iOS或者Andriod的版本号] 2.4.3
  * Wechat version: [微信版本号]
  * wepy-cli version: [wepy-cli -v] 1.7.3
  * wepy version: [在package.json里] 1.7.2
  * other version: [如果是插件问题,请列出问题插件的版本号]

## Reproduce

  [如何重现问题]
代码:
  ```javascript
<template>
  <view class="customers-container {{isPx ? 'xmjconfirm-container' : ''}}">
    <scroll-view scroll-y="true" class="scrollView">
      <view class="orderList">
        <view wx:for="{{detailData.order_item_list}}" wx:for-item="item" wx:key="item.id">
          <van-swipe-cell right-width="{{ 65 }}">
            <van-cell-group>
              <view class="wrapper">
                <view class="img-box">
                  <image src="{{item.goods_cover_url}}" alt=""></image>
                </view>
                <view class="detail">
                  <view class="title ellipsis-2">{{item.goods_title}}</view>
                  <view class="label clearfix">
                    <text class="num">数量x{{item.number}}</text>
                    <text class="price">¥{{item.factory_amount}}</text>
                  </view>
                </view>
              </view>
            </van-cell-group>
            <view class="djdj" slot="right" @tap="tzdj({{index}})">调整订金</view>
          </van-swipe-cell>
          <view class="box clearfix">
            <view class="wrapper-box">
              <view class="title">类型</view>
              <view class="detail" style="font-weight: 600">{{item.goods_cate}}</view>
            </view>
            <view class="wrapper-box center">
              <view class="title">定金</view>
              <view class="detail">¥{{item.deposit_amount}}</view>
            </view>
            <view class="wrapper-box">
              <view class="title">总价</view>
              <view class="detail price">{{item.factory_all_amount}}</view>
            </view>
          </view>
        </view>
      </view>
    </scroll-view>
    <view class="mjconfirm-btn">
      <view class="inline">
        <view class="label">
          <view class="label-item clearfix">
            订单总额
            <text class="price">¥{{totalAmount}}</text>
          </view>
          <view class="label-item sec-label clearfix">
            定金总额
            <text class="price price_border">¥{{totalDJ}}</text>
          </view>
          <view class="label-item last-label clearfix" @tap="xgjy">
            交付周期
            <text class="date">{{detailData.interaction_cycle}}天</text>
          </view>
        </view>
        <button @tap="comfie">确定</button>
      </view>
    </view>
    <van-popup show="{{ show }}" custom-style="Tjauto" z-index="9999" catch:close="onClose">
      <view class="tz-view">
        <view class="title">
          调价
          <image @tap="close" class="close" src="../../images/customer/close.png"></image>
        </view>
        <view class="wrapper">
          <view class="img-box">
            <image src="{{choose.goods_cover_url}}" alt=""></image>
          </view>
          <view class="detail">
            <view class="title ellipsis-2">{{choose.goods_title}}</view>
            <text class="price">¥{{choose.amount}}</text>
          </view>
          <text class="num">x{{choose.number}}</text>
        </view>
        <view class="input-view">
          <text class="tip">将订金调整为:</text>
          <view class="iv">
            <input type="number" value="{{choose.deposit_amount}}" bindinput="aBlur">
          </view>
          <text class="dw">元</text>
        </view>
        <button class="save" @tap="changeDJ">确认修改</button>
      </view>
    </van-popup>
    <van-popup show="{{ show2 }}" custom-style="Tjauto" z-index="9999" catch:close="onClose">
      <view class="tz-view">
        <view class="title">
          调整周期
          <image @tap="close2" class="close" src="../../images/customer/close.png"></image>
        </view>
        <view class="input-view">
          <text class="tip">将交付周期为:</text>
          <view class="iv">
            <input type="number" value="{{detailData.interaction_cycle}}" bindinput="zBlur">
          </view>
          <text class="dw">天</text>
        </view>
        <button class="save" @tap="saveZ">确认修改</button>
      </view>
    </van-popup>
  </view>
</template>

<script>
import wepy from 'wepy'
import lf from 'lf'
import testMixin from '../../mixins/test'

export default class confirmOrder extends wepy.page {
  config = {
    navigationBarTitleText: '确认订单',
    navigationBarTextStyle: '#fff',
    backgroundTextStyle: 'light',
    backgroundColor: '#2ebc88',
    navigationBarBackgroundColor: '#2ebc88',
    usingComponents: {
      'van-popup': '/components/vant/popup/index',
      'van-cell-group': '/components/vant/cell-group/index',
      'van-swipe-cell': '/components/vant/swipe-cell/index'
    }
  }
  mixins = [testMixin]
  data = {
    show: false,
    show2: false,
    detailData: [],
    choose: {},
    detailId: '',
    sum: '',
    oldAmount: '',
    oldZQ: '',
    sum: 0
  }

  computed = {
    totalAmount () {
      const list = this.detailData.order_item_list || []
      let sum = 0
      list.forEach(v => {
        sum = sum + Number(v.amount)
      })
      return sum
    },
    totalDJ () {
      const list = this.detailData.order_item_list || []
      let sum = 0
      list.forEach(v => {
        sum = sum + Number(v.deposit_amount)
      })
      return sum
    }
  }

  methods = {
    close2 () {
      this.show2 = false
      this.detailData.interaction_cycle  = this.oldZQ
      this.$apply()
    },
    xgjy () {
      this.show2 = true
      this.oldZQ = this.detailData.interaction_cycle
      this.$apply()
    },
    zBlur (e) {
      this.detailData.interaction_cycle  = e.detail.value
      this.$apply()
    },
    async saveZ () {
      var reg = /^\+?[1-9][0-9]*$/
      if (!reg.test(this.detailData.interaction_cycle)) {
        this.detailData.interaction_cycle = this.oldZQ
        this.$apply()
        wepy.showToast({
          title: '请输入整数',
          icon: 'none'
        })
        return
      }
      try {
        const res = await lf.net.post('/Api/Factory/set_interaction_cycle', {
          order_id: this.detailData.id,
          interaction_cycle: this.detailData.interaction_cycle
        })
        if (res.code === 200) {
          this.show2 = false
          this.$apply()
          this.init()
          wepy.showToast({
            title: '操作成功',
            icon: 'none'
          })
        } else {
          wepy.showToast({
            title: res.info,
            icon: 'none'
          })
        }
      } catch (e) {
        console.error(e)
        wepy.showToast({
          title: '操作错误',
          icon: ''
        })
      }
    },
    toTel (number) {
      wepy.makePhoneCall({
        phoneNumber: String(number)
      })
    },
    tzdj (index) {
      this.show = true
      this.choose = this.detailData.order_item_list[index]
      this.oldAmount = this.choose.deposit_amount
      this.$apply()
    },
    close () {
      this.show = false
      this.choose.deposit_amount = this.oldAmount
      this.choose = {}
    },
    async changeDJ () {
      const reg = /(^[1-9]([0-9]+)?(\.[0-9]{1,2})?$)|(^(0){1}$)|(^[0-9]\.[0-9]([0-9])?$)/;
      let value = this.choose.deposit_amount
      if (!reg.test(value)) {
        this.choose.deposit_amount = this.oldAmount
        this.$apply()
        wepy.showToast({
          title: '请输入正确金额',
          icon: 'none'
        })
        return
      }
      if (Number(value) > Number(this.choose.amount)) {
        this.choose.deposit_amount = this.oldAmount
        this.$apply()
        wepy.showToast({
          title: '不能大于总价',
          icon: 'none'
        })
        return
      }
      try {
        const res = await lf.net.post('/Api/Factory/order_item_update', {
          order_item_id: this.choose.id,
          deposit_amount: this.choose.deposit_amount
        })
        if (res.code === 200) {
          this.show = false
          this.choose = {}
          this.$apply()
         //  this.init() 发现IOS上有问题后,无奈就干脆调用一次初始化,才能渲染
          wepy.showToast({
            title: '操作成功',
            icon: 'none'
          })
        } else {
          wepy.showToast({
            title: res.info,
            icon: 'none'
          })
        }
      } catch (e) {
        console.error(e)
        wepy.showToast({
          title: '操作错误',
          icon: ''
        })
      }
    },
    aBlur (e) {
      const value = e.detail.value
      this.choose.deposit_amount = value
      this.$apply()
    },
    async comfie () {
      wepy.showLoading({
        title: '提交中...'
      })
      try {
        const res = await lf.net.post('/Api/Factory/order_check_commit', {
          id: this.detailData.id
        })
        wepy.hideLoading()
        if (res.code === 200) {
          this.show = false
          this.choose = {}
          this.$apply()
          wepy.showToast({
            title: '操作成功'
          })
          setTimeout(() => {
            wepy.navigateBack()
          }, 800)
        } else {
          wepy.showToast({
            title: res.info,
            icon: 'none'
          })
        }
      } catch (e) {
        console.error(e)
        wepy.hideLoading()
        wepy.showToast({
          title: '操作错误',
          icon: ''
        })
      }
    }
  }
  events = {}

  async init () {
    this.getDetail()
  }

  async getDetail () {
    let result = await lf.net.post('/Api/Factory/order_detail', {
      order_id: this.detailId
    })
    if (result.code === 200) {
      this.detailData = result.data
      this.getSum(this.detailData.order_item_list)
      this.$apply()
    } else {
      wepy.showToast({
        title: result.info,
        icon: 'none'
      })
    }
  }

  getSum (list) {
    this.sum = 0
    for (let i = 0; i < list.length; i++) {
      this.sum += parseInt(list[i].number)
    }
  }

  onLoad (options) {
    this.detailId = options.id
    this.init()
  }
}
</script>

[How to reproduce the issue]

Observed Results

[实际表现] 上面代码,choose的对象就是来源于detailData.order_item_list,在模拟器中表现都正常,但是在IOS上面修改之后就会不渲染,必须重新调用init初始化数据才会正常渲染。 [Observed Results]

Expected Results

[期望表现]

[Expected Results]

Relevant Code / Logs


  // TODO(you): code or logs here to reproduce the problem
  // 可以使用小程序代码片段功能,方便其它人帮助你定位代码问题
  // 详情可参考这里:https://developers.weixin.qq.com/miniprogram/dev/devtools/minicode.html
  ```
LYlanfeng commented 5 years ago

刚自己测试了下,发现choose.list下面数据更改,IOS不渲染,但是我同时将这个choose.list的对象引用复制给data跟下面的定义一个新的对象,然后渲染的时候用新的对象去渲染就没任何问题。所以问题出在这个数组的渲染,必须在跟节点下面的才能在IOS下面渲染。 我上面所发的重现问题代码,估计是也同样的问题,因为数组是在detailData对象下面。所以导致数组中的对象修改无法渲染。