微信小程序之表单页面优化

1、前言

长表单录入信息在业务系统中是非常常见的一个场景,然而长表单加业务系统,那流畅度,简直不忍直视。所以趁着现在空闲,想了一些关于长表单页面的优化方案。

2、优化方案一: 减少绑定方法

我们平时写小程序页面的时候,可能会不太注意,会有这样的写法。

<!-- html页面 -->
<view class='content2'>
    <view class='item'>
      <text class='item_title'>姓名</text>
      <input  type='text' value ='{{name}}' bindinput ="getName"></input>
    </view>
    <view class='item'>
      <text class='item_title'>手机号</text>
      <input type='text' value ='{{phone}}' bindinput ="getPhone"></input>
    </view>
</view>


// js页面如下
 getName(e){
    this.setData({
      name : e.detail.value
    })
  },

  getPhone(e){
    this.setData({
      name: e.detail.value
    })
  }
  // 其他 ....

表单少的时候还好,如果你想一下业务系统中,有些页面有2/3十个字段呢?难道每个input都给一个相应方法吗?

不仅代码重复多,而且js页面中定义的方法过多占用内存、占用体积、而且还导致代码多阅读困难等,而且哪一天如果要对输入的内容做检查处理,就算可以把检查的代码抽象出来,难道还要调用二三十次?

当然,上一种方法也不是没有优点,优点就是:职责单一,哪天不小心把某个方法改bug也不影响其他的使用。

但从性能方面考虑,我们就可以对某一类相似的输入方法就行优化,绑定同一个方法,像下面这样:

<!-- html页面 -->
<view class='content2'>
    <view class='item'>
      <text class='item_title'>姓名</text>
      <input  type='text' value ='{{name}}' data-type="name" bindinput ="getValue"></input>
    </view>
    <view class='item'>
      <text class='item_title'>手机号</text>
      <input type='text' value ='{{phone}}' data-type="phone" bindinput ="getValue"></input>
    </view>
</view>


// js页面如下
  getValue(res){
    let type = res.currentTarget.dataset.type;
    switch(type)
    {
      case 'name':
        this.setData({
          name : res.detail.value
        })
      break;

      case 'phone':
        this.setData({
          phone : res.detail.value
        })
      break;

      // 其他...

      default:
      break;
    }
  },
  // 其他 ....

3、优化方案二: 不使用this.setData

在方案一中,我们主要针对长表单页面进行了简单的优化,而事实上你优化后运行,也感觉不出性能有什么提升,但从逻辑上来说,性能确实提升了一些,只是效果不明显而已。

而方案二,才是优化的重点。

想想,我们在vue中一般都是使用双向数据绑定,vue帮我们处理了许多逻辑。而在小程序中,页面并不是双向数据绑定的,而且由于小程序中获取不到dom节点,我们无法在点提交的时候才去获取各个input里的值,所以我们一般都会习惯性地把各个input的值存入data中,每次存数据到data中都要调用this.setData这个方法,并且由于小程序双线程的构架,this.setData调用后,js逻辑线程就会通知渲染线程去渲染数据更新页面,而2个线程之间的通信及渲染层渲染才是造成性能下降的罪魁祸首。

比如,输入名字中,我输入一个: 任 字。

由于使用拼音的缘故,我要输入 ren,然后选择 任 字。你在getValue()方法中打印一下,看getValue()被调用了多少次?

4次!!!

不仅是getValue()被调用了4次,this.setData()也被调用了4次!!

如果我要输入的内容超多,打字速度超快(20多年的手速...),然后你就会看到,页面卡顿...

然后分析我们的wxml代码,发现有一行 value = '{{name}}' 。

嗯??? 我们为什么要设置这一行代码?为了使页面所渲染的数据和data中保持同步!但本身input数据是刚从渲染层(Input是原生组件,实际是native层,不过这不重要)传递到逻辑层,数据本身就是同步的了!!!

所以,对于input这种输入性标签,我们只需要保存数据就好了!而不用多此一举再次通知渲染层渲染!!!

如果我们不需要通知渲染层渲染,那就不需要用data来存储数据,那么代码将会变成下面这样:

<!-- html页面 -->
<view class='content2'>
    <view class='item'>
      <text class='item_title'>姓名</text>
      <input  type='text' data-type='name' bindinput ="getValue"></input>
    </view>
    <view class='item'>
      <text class='item_title'>手机号</text>
      <input type='text'  data-type='phone' bindinput ="getValue"></input>
    </view>
    <view class='item'>
      <text class='item_title'>身份证</text>
      <input  type='text' bindinput ="getBankName"></input>
    </view>
</view>


//js页面如下
data:{

},

// 这里才是核心!!!
// 本质上Page()是一个方法,传进来的是一个对象,
// 那么既然能存在data,肯定也可以使用自定义mydata来存数据啦。
mydata:{
  phone:'',
  name:'',
  cardId:'',
  barnchName:'',
  bankCardNo:'',
  linkName:'',
  linkShip:'',
  linkPhone:''
},
getValue(res){
    let type = res.currentTarget.dataset.type;
  // 如果你不需要对输入的内容各自处理的话,甚至还可以这样做,
   // 这样就可以去掉裹脚布一样的switch了
   // this.mydata[type] = res.detail.value;
    switch(type)
    {
      case 'name':
        this.mydata.name = res.detail.value
      break;

      case 'phone':
        this.mydata.phone = res.detail.value
      break;

      default:
      break;
    }
  },

在这份代码中,主要使用了mydata来存储数据,页面显示的就是用户输入的数据,不过我们把数据备份了一份,同时切断了他们之间的“同步”。就这样,没有了“同步”,没有了this.setData(),也没有了卡顿。

然后在下一步的方法中,打印一下数据,发现数据也能完整取到,如下图:

image.png

4、完整代码

<!-- html -->
<!--pages/task/information/information.wxml-->
<!-- <view class='showTips' animation="{{animation}}">{{message}}</view> -->
<view class='container2'>
  <view class='pageItem'>
      <!-- <text>1/3</text> -->
      <view class='content2'>
        <view class='item'>
          <text class='item_title'>姓名</text>
          <input  type='text' data-type='name' bindinput ="getValue"></input>
        </view>
        <view class='item'>
          <text class='item_title'>手机号</text>
          <input type='text'  data-type='phone' bindinput ="getValue"></input>
        </view>
        <view class='item'>
          <text class='item_title'>身份证</text>
          <input  type='text' data-type='cardId' bindinput ="getValue"></input>
        </view>
        <!-- <view class='item'>
          <text class='item_title'>开户行</text>
           <select prop-array='{{myBankArr}}' bind:myget='getBank'></select> 
        </view> -->
        <view class='item'>
          <text class='item_title'>支行名称</text>
          <input  type='text' data-type='branchName' bindinput ="getValue" ></input>
          
        </view>
        <view class='item'>
          <text class='item_title'>银行卡号</text>
          <input  type='text' data-type='cardNo' bindinput ="getValue"></input>
          
        </view>
        <view class='item'>
          <text class='item_title'>紧急联系人</text>
          <input  type='text' data-type='linkName' bindinput ="getValue"></input>
          <!-- <text class='tips_1'>*</text> -->
        </view>
        <view class='item'>
          <text class='item_title'>联系人关系</text>
          <input  type='text' data-type='linkShip' bindinput ="getValue"></input>
          <!-- <text class='tips_1'>*</text> -->
        </view>
        <view class='item'>
          <text class='item_title'>联系人电话</text>
          <input  type='text' data-type='linkPhone' bindinput ="getValue" ></input>
          <!-- <text class='tips_1'>*</text> -->
        </view>
      </view>

      <button bindtap='next'>下一步</button>
  </view>
  <view class='pageItem'>
  </view>
  <view class='pageItem'>
  </view>
  <button bindtap='nextStep'>下一步</button>
</view>
// js
// pages/t
Page({

  mydata:{
    phone:'',
    name:'',
    cardId:'',
    barnchName:'',
    bankCardNo:'',
    linkName:'',
    linkShip:'',
    linkPhone:''
  },
  data: {
    isChecked: false,
    animation: {},
    message: '银行卡必须是本人的,用作发佣金',
    myBankArr:[
      {
        "id": 0,
        "text": '中国招商银行'
      },
      {
        "id": 1,
        "text": '中国工商银行'
      },
      {
        "id": 2,
        "text": '中国农业银行'
      },
      {
        "id": 3,
        "text": '中国银行'
      },
      {
        "id": 4,
        "text": '中国建设银行'
      },
      {
        "id": 5,
        "text": '中国邮政储蓄银行'
      }
    ]
  },

  onLoad: function (options) {
  },
  onShow: function () {
  },

  getValue(res){
    let type = res.currentTarget.dataset.type;
    switch(type)
    {
      case 'name':
        this.mydata.name = res.detail.value
      break;

      case 'phone':
        this.mydata.phone = res.detail.value
      break;

      case 'cardId':
      break;

      case 'barnchName':
      break;

      case 'bankCardNo':
      break;

      case 'linkName':
      break;

      case 'linkShip':
      break;

      case 'linkPhone':
      break;
      
      default:
      break;
    }
  },
  next(){
    console.log(this.mydata)
  }
})
/* css 部分 */
/* pages/task/information/information.wxss */
page,view{
  margin: 0;
  padding: 0;
}
.showTips{
  position: absolute;
  left: 0;
  top: -70rpx;
  width: 750rpx;
  height: 70rpx;
  line-height: 70rpx;
  text-align: center;
  background-color: #c6d0e3;
  color: #00276f;
}
.container2{
  display: flex;
  flex-direction: row;
  justify-content: flex-start;
  align-items: center;
  padding: 0;
  overflow: hidden;
}

.pageItem{
  width: 750rpx;
  display: flex;
  flex-direction: column;
  justify-content: flex-start;
  align-items: center;
  flex-shrink: 0;
}

.content2{
  width: 100%;
  /* border-top: solid 2rpx #333;
  border-bottom: solid 2rpx #333; */
  padding-left: 20rpx;
}

.item{
  margin-top: 10rpx;
  padding: 10rpx 10rpx;
  width: 100%;
  /* margin: 25rpx 0; */
  display: flex;
  flex-direction: row;
  justify-content: flex-start;
  align-items: center;
  border-bottom: solid 2rpx #EDEDED;
}
.item_title{
  width: 150rpx;
  flex-shrink: 0;
  text-align: right;
  font-size: 28rpx;
}

.item > input{
  text-align: left;
  font-size: 34rpx;
  height: 60rpx;
  line-height: 60rpx;
  padding: 0 20rpx;
  width: 490rpx;
  /* border-radius: 10rpx; */
  
}

.item > select{
  text-align: left;
  font-size: 34rpx;
  height: 60rpx;
  line-height: 60rpx;
  padding: 0 20rpx;
  width: 490rpx;
  /* border-radius: 10rpx; */
  /* border-bottom: solid 2rpx #EDEDED; */
}

.inputPlace{
  font-size: 30rpx;
}

.tips_1{
  color: red;
  margin-left: 10rpx;
  width: 10rpx;
}

.tips{
  height: 33rpx;
  line-height: 33rpx;
  margin-top: 180rpx;
}
.tips .img image{
  width: 27rpx;
  height: 33rpx;
  margin: 0 10rpx 0 150rpx;
}
.tips text{
  color: #1D4692;
  font-size: 25rpx;
}
button{
  margin-top: 50rpx;
}
.checkbox{
  text-align: center;
  color: #1D4692;
  margin: 50rpx 0;
}
.checkbox view,.checkbox navigator{
  font-size: 26rpx;
}
.checkbox navigator{
  display: inline;
  text-decoration: underline;
}
checkbox .wx-checkbox-input {
  width: 20rpx;
  height: 20rpx;
  margin-right: 30rpx;
}

5、目前我个人就想到这2个优化方案,肯定也还存在其他的方案的,欢迎交流。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 220,137评论 6 511
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,824评论 3 396
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 166,465评论 0 357
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,131评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,140评论 6 397
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,895评论 1 308
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,535评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,435评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,952评论 1 319
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,081评论 3 340
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,210评论 1 352
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,896评论 5 347
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,552评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,089评论 0 23
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,198评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,531评论 3 375
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,209评论 2 357