微信小程序开发

微信小程序中“原生组件”的坑。

2019-05-18  本文已影响0人  firechun

想做一个简单的效果,如图示:


效果图

用户选择第一二项时,文本框是禁止状态,并显示预定义的文本;选择第三项时,清空文本并取消禁止状态,用户可以输入文本。如果用户输入文本之后又选择了第一二项,则仍然在文本框中显示预定义文本。最后提交时,获得的是文本框中的内容。
代码超级简单,定义两个变量分别代表文本框是否禁止输入和文本框的内容,在radia-group的change事件中使用setData方法改变这两个变量的值,微信就会重新渲染页面:

/**
   * 退款原因改变
   */
reasonChange: function(e){
    this.setData({
      disableInput: e.detail.value != '',
      drawbackReason: e.detail.value
    })
  }
  /**
   * 输入退款原因
   */
  inputReason: function(e){
    this.setData({
      words: e.detail.value.length,
      drawbackReason: e.detail.value,
    })
},

WXML:

  <view>
    <view>退款原因</view>
    <radio-group class='align-right' bindchange="reasonChange">
      <label class="radio">
        <radio value="不想投放了" color='{{styleInfo.color}}' checked="true" />
        不想投放了
      </label>
      <label class="radio" >
        <radio value="多次审核未通过" color='{{styleInfo.color}}'/>
        多次审核未通过
      </label>
      <label class="radio" >
        <radio value='' color='{{styleInfo.color}}'/>
        其它({{words}}/50字)
      </label>
    </radio-group>
    <textarea disabled='{{disableInput}}' focus='{{!disableInput}}' bindinput='inputReason' maxlength='50' value='{{drawbackReason}}'></textarea>
  </view>

在微信开发工具中调试没有任何问题,在真机上调试时发现,当用户输入文本后又重新选择第一二项时,文本框中的内容不会改变,必须再选择一次第一二项,才会出现预期的效果。具体来说,就是选择第三项,输入文本“test”,然后再选择第一或第二项,文本框变成禁止状态,但文本内容仍然是“test“,这时再选择一下第一项或第二项,又恢复正常了。

反复查看代码和业务逻辑,都找不到任何问题,关键是在微信开发工具中调试是没有任何问题的。

无奈之下,查阅微信的开发文档,发现textarea的文档中有这么一句话:该组件是原生组件,使用时请注意相关限制。
什么限制呢?点链接进去继续看:

在工具上,原生组件是用web组件模拟的,因此很多情况并不能很好的还原真机的表现,建议开发者在使用到原生组件时尽量在真机上进行调试。

也就是原生组件在开发工具中的表现和真机中不尽相同,因此才会出现上面的奇怪现象。
在reasonChange和inputReason两个方法中用console.log()观察执行情况,会发现改变选项时,先触发reasonChange方法,然后又触发了inputReason方法。
经过分析就明白,在reasonChange中,使用setData方法改变了drawbackReason变量的值,此时drawbackReason的值的确变成了空字符串,而setData方法会同步更改wxml,因此同时更改了textarea的value,而更改textarea的value又会触发inputReason,这个方法中会用textarea的value去更新drawbackReason,此时textarea的value还是原来的值,这一轮代码运行下来,就造成了drawbackReason的值没有任何改变。

对微信小程序的组件没有深入研究过,我猜测对原生组件textarea,任何方式产生的文本改变都会引发bindinput事件,而在开发工具中是用web组件模拟的textarea,只有输入文本才会触发bindinput事件,用代码改变文本则不会触发。

找到原因后,解决就很简单了,添加一个变量,在reasonChange中根据用户选项设定变量的值,在inputReason中根据该变量的值决定是否反向更新drawbackReason的值。

  /**
   * 退款原因改变
   */
  reasonChange: function(e){
    //和wxml无关,无需使用setData方法
    this.data.inputting = e.detail.value == ''
    this.setData({
      disableInput: e.detail.value != '',
      drawbackReason: e.detail.value
    })
  },

  /**
   * 输入退款原因
   */
  inputReason: function(e){
    this.setData({
      words: e.detail.value.length,
    })
    if(this.data.inputting){
      this.setData({
        drawbackReason: e.detail.value,
      })
    }
  },

上一篇 下一篇

猜你喜欢

热点阅读