微信小程序原生JS智能粘贴功能 编辑与删除

566 阅读8分钟

微信小程序原生JS智能粘贴功能 编辑与删除

功能要求:智能识别,并且所有识别的内容都可单独修改,智能识别框可收起和展开,列表可单条右滑删除(图未展示),识别框与列表页都可一键清除

效果:

·

WXML代码

<view class="page">
  <view class='shouqi' wx:if="{{showsmall||showClear}}">
    <view class='text' bindtap="showbig">请输入或者粘贴信息,可自动识别</view>
    <image src="https://file.baimipay.cn/biaodan2x.png" bindtap="addressList"></image>
  </view>
  <view class='address-wrap' wx:if="{{showbig&&!showClear}}">
    <view class='smart-address'>
      <view class='smart-top'>
        <view class='flex-3'>
          <view class="paste">
            <view class="paste-title">智能粘贴</view>
            <image src="https://file.baimipay.cn/icon_zhankai.png" bindtap="showbig" class='zhankai'></image>
          </view>

          <view class='c9 ft12 mt10'>不同信息用空格隔开,不同订单请换行添加</view>
        </view>
        <view class='flex-1 tar' bindtap='addressList'>
          <image src="https://file.baimipay.cn/biaodan2x.png"></image>
        </view>
      </view>
      <view class='smart-bottom' hidden='{{imageSrc}}'>
        <textarea class='textarea-css' placeholder-class="input-placeholder" placeholder="楼栋-单元-门牌号  货物信息  手机号(选填) 例如:6-2-103 十斤车厘子 15711111111" bindinput='handleInputList' value='{{copyText}}' focus maxlength="1000"/>
        <view class='clearknow'>
          <view wx:if='{{copyText}}' data-name='copyText' bindtap='handleClearInput'>清除</view>
          <view wx:if='{{copyText}}'  bindtap='pasteAvailableText'>识别</view>
        </view>
      </view>
    </view>
  </view>
  <view class='addressInfo-title'>
    <text style='width:220rpx;'>地址</text>
    <text style='width:310rpx;'>货物信息</text>
    <text>手机号</text>
  </view>
  <view wx:if='{{!listData.length}}' class='kong'>
    空
  </view>
  <view class='wrap' wx:if='{{!showClear}}'>
    <view wx:for='{{listData}}' wx:key='index' class='addressInfo {{index== isTouchMove? "touch-move-active" : ""}}' auto-height bindtouchstart='TouS' bindtouchmove='TouM' catchtouchend='TouE' data-index="{{index}}">
      <view class='content'>
        <textarea bindinput="handleInputAddress" class='flex-1 site-input' placeholder-class='cc' value='{{item.unitAddress}}' placeholder='请填写楼栋号' maxlength="12" data-index="{{index}}" auto-height></textarea>
        <textarea bindinput="handleInputInfo" style="max-width:300rpx;" class='flex-1 site-input' placeholder-class='cc' value='{{item.deliverInfo}}' placeholder='请填写货物信息' maxlength="150" data-index="{{index}}" auto-height></textarea>
        <textarea bindinput="handleInputPhone" class='flex-1 site-input' placeholder-class='cc' value='{{item.phone}}' placeholder='请填写手机号' maxlength="13" data-index="{{index}}" auto-height></textarea>
      </view>
      <view class='del' catchtap='delAddress' data-index='{{index}}'>
        删除
      </view>
    </view>
  </view>
  <view wx:else>
  <view wx:for='{{listData}}' wx:key='index' class='addressInfo {{index== isTouchMove? "touch-move-active" : ""}}' auto-height bindtouchstart='TouS' bindtouchmove='TouM' catchtouchend='TouE' data-index="{{index}}">
      <view class='content'>
        <view class='flex-1 site-input' auto-height>{{item.unitAddress}}</view>
        <view style="max-width:310rpx;" class='flex-1 site-input' auto-height>{{item.deliverInfo}}</view>
        <view class='flex-1 site-input' auto-height>{{item.phone}}</view>
      </view>
    </view>
  </view>
  <view class="submit">
    <button class="submit-btn clear" catchtap='{{showClear?"":"showClear"}}' style='color:#333;'>
      清除
    </button>
    <button class="submit-btn {{listData.length?'':'disable'}}" catchtap='{{showClear?"":"submit"}}'>
      下一步({{listData.length}})
    </button>
  </view>
</view>

<!-- 弹出层 -->
<view class='popup-view' wx:if="{{showClear}}">
  <view class='popup'>
    <view class='popup-title'>确定全部清除?</view>
    <view class='dialogbtn'>
      <view bindtap="onCloseFlag" class='headbtn'>取消</view>
      <view bindtap="subClear" class='headbtn sub'>确定</view>
    </view>
  </view>
</view>

JS代码

const app = getApp();
import Common from '../../../api/common.js'
import Address from "../../../api/address.js"
import Head from "../../../api/header.js"

Page({
  /**
   * 页面的初始数据
   */
    data: {
    syncName: app.globalData.syncName, //缓存标识
    listData:[],
    copyText: '',
    addressId: '',
    userNameFocus: false,
    mobileFocus: false,
    addressFocus: false,
    isShow: true,
    iosPhone: false, //手机机型
    showsmall:false,
    showbig:true,
    isTouchMove: -1,
    showClear:false
  },
  /**
   * 生命周期函数--监听页面加载
   */
  onLoad: function (options) {
    wx.setNavigationBarTitle({
      title: '填写送货信息'
    })
    if (wx.getStorageSync(`${this.data.syncName}headAddress`)){
      const listData = wx.getStorageSync(`${this.data.syncName}headAddress`)
      this.setData({
        listData
      })
    }
    
  },
  /**
   * 生命周期函数--监听页面显示
   */
  onShow: function () {
    console.log(this.data.listData)
  },
  
  onUnload: function () {
    // wx.removeStorageSync(`${this.data.syncName}headAddress`)
  },

  submit() {
    const msg = this.checkMsg();
    if (msg) {
      app.commonTip(msg);
      return false;
    }
    let listData = this.data.listData
    let num = 0
    for (let i in listData){
      num++
      listData[i].numMark=num
    }
    wx.setStorageSync(`${this.data.syncName}headAddress`, listData)
    wx.navigateTo({
      url: '../../../packageA/head/index',
    })
  },

  // 识别文字
  postTest(text) {
    console.log('识别文字')
    Head.filterAddress(text).then(res => {
      let listData = this.data.listData
      if (listData.length==0){
        this.setData({
          listData: res.arrayMsg
        })
      }else{
        console.log(listData)
        // listData=listData.concat(res.arrayMsg)
        //listData = listData.unshift(res.arrayMsg)
        for (let i = res.arrayMsg.length-1;i>=0; i--){
          listData = [res.arrayMsg[i], ...listData];
        }
        
        this.setData({
          listData,
        })
        console.log(listData)
      }
    }).catch(msg => {
      console.error(msg);
    })
    wx.hideLoading();
  },
  handleInputList(e) {
    this.setData({
      copyText: e.detail.value
    })
  },
  //处理粘贴文本
  pasteAvailableText() {
    wx.showLoading({
      title: '智能识别中...',
      mask: true
    })
    this.postTest(this.data.copyText)
  },
  handleClearInput(e) {
    // debugger
    const attrName = e.currentTarget.dataset.name;
    this.setData({
      [`${attrName}`]: ''
    })
    app.commonTip('已清除')
  },
  hadnleCancel() {
    this.handleIsShowCropper();
    this.clearImageSrc();
  },
  addressList(){
    wx.navigateTo({
      url: '../../../packageA/head/address_list/index',
    })
  },
  showbig(){
    this.setData({
      showsmall: !this.data.showsmall,
      showbig: !this.data.showbig
    })
  },
  handleInputInfo(e){
    const index = e.currentTarget.dataset.index
    let listData = this.data.listData
    listData[index].deliverInfo = e.detail.value
    this.setData({
      listData: listData
    })
  },
  handleInputAddress(e) {
    // debugger
    const index = e.currentTarget.dataset.index
    let listData = this.data.listData
    listData[index].unitAddress = e.detail.value
    this.setData({
      listData: listData
    })
  },
  handleInputPhone(e) {
    const index = e.currentTarget.dataset.index
    let listData = this.data.listData
    listData[index].phone = e.detail.value
    this.setData({
      listData: listData
    })
  },
  TouS(e) { //用户手指触摸
    var index = e.currentTarget.dataset.index
    if (e.touches.length == 1) {
      this.setData({
        startX: e.touches[0].clientX,
        startY: e.touches[0].clientY,
      })
    }

  },
  TouM(e) { //用户拖动
    var index = e.currentTarget.dataset.index
    // console.log(index)
    if (e.touches.length == 1) {
      let moveX = e.touches[0].clientX;
      let moveY = e.touches[0].clientY;
      let disX = this.data.startX - moveX;
      let disY = this.data.startY - moveY;
      const isScrolling = Math.abs(disX) < Math.abs(disY) ? 1 : 0;
      //isScrolling为1时,表示纵向滑动,0为横向滑动
      if (disX > 30 && isScrolling == 0) {
        this.setData({
          isTouchMove: index
        })
      } else if (disX < 0 && index == this.data.isTouchMove) {
        if (isScrolling == 0) {
          this.setData({
            isTouchMove: -1
          })
        }
      }
    }
  },
  TouE(e) {
    var index = e.currentTarget.dataset.index;
    if (this.data.disX < 120) {
      this.setData({
        isTouchMove: -1
      })
    }
  },
  delAddress(e) { //删除地址 
    const index = e.currentTarget.dataset.index
    const that = this
    this.setData({
      isTouchMove: -1
    })
    wx.showModal({
      title: '提示',
      content: '是否删除',
      success: function (res) {
        if (res.confirm) {
          let listData = that.data.listData
          listData.splice(index, 1);
          that.setData({
            listData
          })
          console.log(that.data.listData)
        } else if (res.cancel) {
          console.log('用户点击取消')
        }
      }
    })
  },
  checkMsg() {
    let msg = '';
    let listData=this.data.listData
    var regPos1 = /(^(\d{3,4}-)\d{7,8}$)/; //电话号码
    var regPos2 = /^1[3|4|5|7|8][0-9]{9}$/; //手机号码
    for (let i in listData){
      if (listData[i].unitAddress==''){
        msg = '请填写地址';
      }
      if (listData[i].deliverInfo == '' || listData[i].deliverInfo == null) {
        msg = '请填写货物信息';
      }
      if (listData[i].phone != '' && listData[i].phone != null) {
        if (!(regPos1.test(listData[i].phone)) && !(regPos2.test(listData[i].phone))) {
          msg = '手机号格式错误,请重新填写';
          listData[i].phone = ''
        }
      }
      this.setData({
        listData
      })
    }
    if (this.data.listData.length > 50) msg = '最多50条';
    if (this.data.listData.length == 0) msg = '请填写货物信息';
    return msg;
  },
  //清除弹框
  showClear(){
    this.setData({
      showClear: true
    })
  },
  //关闭弹窗
  onCloseFlag() {
    this.setData({
      showClear: false
    })
  },
  //确定清除
  subClear(){
    this.setData({
      listData: [],
      showClear: false
    })
    app.commonTip('已清除')
  }
})

WXSS代码

page{
  padding-bottom:200rpx;
  box-sizing: border-box;
  background-color: #f6f6f6;
}

.wrap {
}


.input-wrap {
  width: 100vw;
  display: flex;
  position: relative;
  padding: 0 30rpx;
  font-size: 32rpx;
  height: 96rpx;
  background-color: #fff;
  border-bottom: 1px solid #eee;
  box-sizing: border-box;
}

.input-wrap>view:first-child {
  width: 60%;
}

.input-wrap>view:last-child {
  width: 40%;
}

.input-v {
  width: 100%;
  display: flex;
  flex-direction: row;
  padding-left: 10rpx;
  margin-top: 10rpx;
  height: 76rpx;
  font-size: 30rpx;
  justify-content: space-between;
  align-items: center;
  box-sizing: border-box;
}

.input-v:first-child{
  padding-right: 10rpx;
}

.input-v input {
  width: 80%;
}

.input-v.flex-2 input {
  display: inline-block;
  overflow: hidden;
  width: 220rpx;
  height: 74rpx;
  margin-top: 1rpx;
}

.input-v.flex-3 input {
  display: inline-block;
  overflow: hidden;
  width: 320rpx;
  height: 74rpx;
  margin-top: 1rpx;
}

.input-v + .input-v {
  border-left: 1rpx solid #eee;
}

.name-phone-icon {
  margin-right: 6rpx;
}

.picker-click-dom {
  padding: 10rpx 30rpx;
  position: relative;
  height: 76rpx;
  line-height: 76rpx;
  display: block;
  background-color: #fff;
  border-bottom: 1rpx solid #eee;
  font-size: 30rpx;
}

.picker {
  width: 100%;
  height: 76rpx;
  line-height: 76rpx;
}

.picker-more {
  width: 14rpx;
  height: 24rpx;
  position: absolute;
  right: 30rpx;
  top: 42rpx;
}

.textarea {
  height: 100%;
  width: 92%;
  font-size: 30rpx;
}

.textarea-view {
  position: relative;
  background-color: #fff;
  padding: 24rpx 20rpx 0 30rpx;
  display: flex;
  font-size: 30rpx;
  height: 220rpx;
  box-sizing: border-box;
}

.text-icon {
  position: absolute;
  right: 20rpx;
  top: 20rpx;
  z-index: 100;
  background-color: #fff;
}

.textarea-length-tip {
  position: absolute;
  right: 28rpx;
  bottom: 20rpx;
  z-index: 100;
  color: #999;
}

.address-wrap {
  padding: 20rpx;
}

.smart-address {
  margin: 0 auto;
  /* height: 420rpx; */
  background-color: #fff;
}

.smart-top {
  display: flex;
  flex-direction: row;
  align-items: center;
  height: 90rpx;
  padding: 28rpx 38rpx 10rpx 20rpx;
  border-bottom: 1rpx solid #E8E9EA;
}

.smart-left {
  float: left;
  overflow: hidden;
}

.smartleft-address {
  color: #f40;
  font-size: 28rpx;
}

.smartleft-auto {
  color: #999;
  font-size: 24rpx;
  margin-top: 5rpx;
}

.icon-voice {
  width: 24rpx;
  height: 36rpx;
}

.smart-bottom {
  overflow: hidden;
  height: 300rpx;
  padding: 28rpx 10rpx 14rpx 20rpx;
  line-height: 28rpx;
  position: relative;
}

.smart-bottom .clear-icon {
  position: absolute;
  right: 10rpx;
  bottom: 10rpx;
}

.textarea-css {
  width: 100%;
  display: block;
  height: 250rpx;
  line-height: 42rpx;
  color: #333;
  font-size: 30rpx;
}

.input-placeholder {
  color: #ccc;
}

.textarea-pcss {
  color: #d7d7d7ff;
  font-size: 28rpx;
  line-height: 60rpx;
}

button {
  width: 620rpx;
  margin: 30rpx 0rpx;
  background-color: #ccc;
  color: #fff;
  margin-left: auto;
  margin-right: auto;
  font-size: 36rpx;
  height: 90rpx;
  line-height: 90rpx;
}

.upload-icon {
  width: 44rpx;
  height: 44rpx;
}

.cropper {
  position: absolute;
  top: 0;
  left: 0;
}

.cropper-buttons {
  background-color: rgba(0, 0, 0, 0.4);
}

.btn {
  height: 30px;
  line-height: 30px;
  padding: 0 24rpx;
  border-radius: 2px;
  color: #fff;
}

.cropper-result image {
  width: 100%;
  height: 100px;
}

.col-f40 {
  color: #56c776 !important;
}

button {
  border-radius: 48rpx;
  font-size: 32rpx;
}

.iostextarea textarea {
  margin-left:-10rpx;
}
.input-v .iostextarea{
  margin-left:-10rpx;
}
.input-v .androidtextarea{
  margin-left:-8rpx;
}
.shouqi{
  margin: 20rpx;
  height: 100rpx;
  display: flex;
  background-color: #fff;
  justify-content:space-between;
  align-items:center;
  padding-left:20rpx;
  padding-right: 32rpx;
}

.shouqi .text{
  font-size: 30rpx;
  color:#ccc;
}

.shouqi image{
  width: 44rpx;
  height: 44rpx;
}

.tar image{
  width: 44rpx;
  height: 44rpx;
}

.clearknow{
  display:flex;
  justify-content:flex-end;
  align-items:center;
  color:#333;
  font-size:24rpx;
}

.clearknow view{
  padding:10rpx 34rpx;
  background-color:#E8E9EA;
  border-radius: 27rpx;
}
.clearknow view:last-child{
  background-color:#FFD643;
  margin-left:40rpx;
}

.paste{
  display:flex;
  align-items:center;
}

.paste-title{
  color:#56C776;
  font-weight:600;
  font-size:30rpx;
}

.zhankai{
width:84rpx;
height:44rpx;
display:inline-block;
margin-left:10rpx;
}

.addressInfo-title{
  height:80rpx;
  padding:22rpx 20rpx;
  font-size:28rpx;
  color:#333;
  display:flex;
  justify-content:flex-start;
  font-weight:550;
  background-color:#fafafa;
  box-sizing:border-box;
}

.addressInfo{
  display: flex;
  background-color: #fff;
  position: relative;
  color: #666;
  font-size: 28rpx;
  box-sizing: border-box;
  width: 100%;
  overflow: hidden;
}

.addressInfo textarea{
  max-width:220rpx;
  padding-right:10rpx;
  box-sizing:border-box;
}

.addressInfo textarea:last-child{
  min-width: 190rpx;
  padding-right:0rpx;
  box-sizing:border-box;
}

.touch-move-active .content, .touch-move-active .del {
  -webkit-transform: translateX(0);
  transform: translateX(0);
}

.content{
  padding: 32rpx 20rpx;
  width: 100%;
  position: relative;
  margin-left: -120rpx;
  transform: translateX(120rpx);
  -webkit-transform: translateX(120rpx);
  transition: all 0.4s;
  -webkit-transition: all 0.4s;
  border-bottom: 1rpx solid #E8E9EA;
  display: flex;
}

.content:last-child{
  border:none;
}

.del {
  background-color: orangered;
  position: absolute;
  top: 0;
  right: 0;
  height: 100%;
  width: 120rpx;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  color: #fff;
  -webkit-transform: translateX(120rpx);
  transform: translateX(120rpx);
  -webkit-transition: all 0.4s;
  transition: all 0.4s;
}

.submit {
  width: 100vw;
  position: fixed;
  left: 0;
  bottom: 0;
  display: flex;
  height: 160rpx;
  padding: 0 32rpx;
  margin-top: 30rpx;
  justify-content: space-between;
  align-items: center;
  box-sizing: border-box;
  box-shadow: 2px 2px 10px rgba(0, 0, 0, 0.1);
  z-index: 1000;
  background: #fff;
}


.submit .submit-btn {
  color:#333;
  width: 398rpx;
  height: 96rpx;
  border-radius: 48rpx;
  font-size: 32rpx;
  text-align: center;
  line-height: 96rpx;
  background-color: rgba(243, 203, 60);
}

.submit .submit-btn.clear{
  width: 218rpx;
  background-color: #fff;
  border: 2rpx solid #E8E9EA;
}


.submit-btn text {
  margin-left: 10rpx;
}

.submit .submit-btn.disable {
  background-color: rgba(243, 203, 60, 0.5);
  color:#666;
}

.kong{
  width: 100%-120rpx;
  background-color: #fff;
  padding: 35rpx;
  font-size: 28rpx;
  color:#666;
  text-align: center;
}
.popup {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translateY(-50%) translateX(-50%);
  width: 584rpx;
  height: 220rpx;
  background: #fff;
  z-index: 99;
}

.popup-view {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  background: rgba(0, 0, 0, 0.7);
  z-index: 2;
}

.dialogbtn{
  display: flex;
  border-top: 1rpx solid #E8E9EA;
  justify-content: space-between;
  width: 100%;
  height: 96rpx;
  bottom: 0;
  position: absolute;


}

.dialogbtn .headbtn{
  color: #333;
  font-size: 32rpx;
  padding: 25rpx 0;
  width: 50%;
  text-align: center;

}

.sub{
  color:#F3CB3C !important;
  border-left:1rpx solid #E8E9EA;
  font-weight: 550;
}
.popup-dflex{
  display: flex;
  border: 1rpx solid #E8E9EA;
  border-radius: 8rpx;
  padding:18rpx 32rpx;
  margin:0 20rpx;
  margin-top: 20rpx;
}

.popup-title{
  color:#2E3038;
  font-size: 30rpx;
  font-weight: 550;
  text-align: center;
  margin: 30rpx 0;
}