微信小程序 — 自定義picker選擇器彈窗內容+textarea穿透bug

微信小程序中定義好的幾種picker選擇器,無論是日期選擇器仍是地區選擇器,或是其餘的都只有定死的樣式和內容。node

可是大多數開發程序的狀況下仍是須要本身寫樣式的,或是內容的。ios

例如:小程序

代碼以下:微信小程序

<view class="free-btns" style="margin-top: 10vh;background:none;">
    <button class="free-btn" bindtap="toggleDialog"> 選定國家:{{value}} </button>
  </view>

  <view class="free-dialog {{ showDialog ? 'free-dialog--show' : '' }}">
    <view class="free-dialog__mask" bindtap="toggleDialog" />
    <view class="free-dialog__container">
      <view style="padding: 5% 5% 15%;">
        <form bindsubmit='submit' bindreset="reset">
          <view bindtap='freetoBack' class="free-button free-dialog-reset">取消</view>
          <view bindtap='freeBack' class="free-button free-dialog-submit">肯定</view>

          <radio-group class='free-radios' bindchange="radioChange">
            <label class="free-radio" bindtap="click" wx:for="{{items}}" wx:key="{{items}}" data-id="{{index}}" style="{{index==id?'background:#48c23d;color:#fff;':'background:#fff;color:#000;'}}">
              <radio value="{{item.name}}" name="{{item.value}}"></radio>
              <label class="free-text">{{item.value}}</label>
            </label>
          </radio-group>
        </form>

      </view>
    </view>
  </view>

樣式:緩存

.free-dialog__mask { position: fixed; top: 0; left: 0; right: 0; bottom: 0; z-index: 10; background: rgba(0, 0, 0, 0.7); display: none;
} .free-dialog__container { position: fixed; left: 0; bottom: 0; width: 750rpx; background: white; transform: translateY(150%); transition: all 0.4s ease; z-index: 11;
} .free-dialog--show .free-dialog__container { transform: translateY(0);
} .free-dialog--show .free-dialog__mask { display: block;
}
/*模態框中的內容*/ .free-button{ display: inline-block; width:50px; text-align: center; font-size:20px; color:#707070; margin-bottom:20px;
} .free-dialog-submit{ float: right; color:#48c23d;
} radio-group{ margin:10rpx 0rpx;
} radio-group>label{ width:22.5%; display: inline-block; border:1px solid #ddd; padding:10px 0px; margin:0px 2px 2px;
} radio-group label radio{ width:100%; z-index: 3; display: none;
} .checked{ background:#48c23d; color:#fff;
} radio-group label .free-text{ width:100%; text-align: center; display: inline-block;
}

js:微信

Page({ data: { showDialog: false, items: [ { name: '中國', value: '中國' }, { name: '美國', value: '美國' }, { name: '巴西', value: '巴西' }, { name: '日本', value: '日本' }, { name: '英國', value: '英國' }, { name: '法國', value: '法國' }, { name: '韓國', value: '韓國' }, { name: '俄羅斯', value: '俄羅斯' },] }, /*點擊變色*/ click:function(e){ var id = e.currentTarget.dataset.id var that = this that.setData({ id:id }) }, onLoad: function (options) { var that = this that.setData({ value:'show' }) }, radioChange: function (e) { console.log('radio發生change事件,攜帶value值爲:', e.detail.value) var that = this that.setData({ value: e.detail.value }) console.log(this.data.value) }, toggleDialog() { this.setData({ showDialog: !this.data.showDialog }); }, freeBack:function(){ var that = this if(this.data.value=='show'){ wx.showModal({ title: '提示', content: '你沒有選擇任何內容', }) } that.setData({ showDialog: !this.data.showDialog }) }, freetoBack: function () { var that = this wx.showModal({ title: '提示', content: '你沒有選擇任何內容', }) that.setData({ showDialog: !this.data.showDialog, value:'show', checked: false, }) }, })

遇到個BUG,就是表單中有textarea組件的時候,彈出層設置z-index,在模擬器上運行沒問題,可是真機就無效了,textarea的內容就會穿透出來。ide

查了資料發現是官方的坑,textarea組件爲原生組件層級最高,不能經過 z-index 控制層級。flex

解決辦法:

一、隱藏 textarea:this

設置一個值,用wx:if 去控制textarea的顯示和隱藏。就是說當彈窗彈出的時候,在textarea作wx:if判斷那個值爲false,把textarea隱藏,而後關閉彈窗或點擊其餘的時候,把那個值再設爲true,顯示textarea。固然hidden原理同樣。spa

代碼以下:

<view class='itemArea'>
          <view class="form_item">留言類型:</view>
          <view class="form_item flex_row jc_between underLine"> 
            <button class="free-btn" bindtap="toggleType"> {{typename}} </button>
            <view class="red" bindtap="toggleType">選擇</view>
          </view>

          <view bindtap="hideView">
          <view class="free-dialog {{ showType ? 'free-dialog-show' : 'free-dialog_mask' }}">
            <view class="free-dialog_mask" bindtap="toggleType" />
            <view class="free-dialog_container1">
              <view class='p25'>
                <form bindsubmit='submit' bindreset="reset">
                  <radio-group class='free-radios' bindchange="radioChange2">
                    <label class="free-radio" bindtap="clickType" wx:for="{{msgtype}}" wx:key="{{msgtype}}" data-idn="{{index}}" data-name='{{item.typename}}' data-id='{{item.typeid}}' style="{{index==idn?'background:#FBDBDB;':'background:#F5F5F5;'}}">
                      <radio value="{{item.typename}}" name="{{item.typename}}"></radio>
                      <label class="free-text">{{item.typename}}</label>
                    </label>
                  </radio-group>
                </form>
              </view>
            </view>
            </view>

          </view>
      </view>
      <view class='pb20'>
          <view class="form_item">留言內容:</view>
          <view class="form_item">
            <textarea class='form_textarea' hidden="{{noTextarea}}" placeholder='請填寫留言內容' bindinput='msgcontent' value="{{msgcontent}}" name="msgcontent"></textarea>
          </view>
       </view>

js:

data: { noTextarea: false, //textarea彈出層的時候隱藏
}, //點擊其餘位置隱藏遮罩層
  hideView:function(){ var that = this; that.setData({ noTextarea: false, }) }, //選擇留言類型
  toggleType: function () { this.setData({ showType: !this.data.showType, noTextarea: true, }); }, radioChange2: function (e) { var that = this; that.setData({ typename: e.detail.value, showType: !this.data.showType, noTextarea: false, }) console.log(this.data.typename); }, clickType:function(e){ var that = this; var idn = e.currentTarget.dataset.idn; var id = e.currentTarget.dataset.id; that.setData({ idn: idn, typeid: id, noTextarea: false, }) console.log(that.data.typeid); },

 二、還有一種解決方法是使用替代元素

有時候, textarea穿透的不是遮罩層,或者遮罩層以一種半透明而非徹底遮住頁面內容的形式呈現,擔憂用戶可以看到由於 textarea的消失而致使頁面跳動,產生很差的用戶體驗,那麼就能夠使用替代元素來替代 textarea而非將之直接隱藏掉。

基本的 textarea組件只接受文本的輸入,拋開可輸入性的話,外觀上看就是一個含有文本節點的簡單元素,只須要獲取當前狀態下的 textarea中輸入的文字,將之賦予給一個樣式與 textarea相同的普通元素,就達到了臨時替代的效果。

<!-- 這是真正的 textarea組件 -->
<textarea id="text-area" value="{{txtRealContent}}" bindinput='txtInput' wx:if="{{!showMask}}" />
<!-- 這是用於模擬 textarea的替代元素 -->
<view class='rich-text' style="{{('height:' + txtHeight + 'px')}}" wx:else>
  <rich-text nodes="{{txtRealContent}}"></rich-text>
</view>
  • 因爲須要實時獲取 textarea中已經輸入的內容,因此給 textarea元素加了個 bindinput的監聽器
  • showMask用於標識是否顯示遮罩層(或者其餘可能會被 textarea穿透的浮動元素),若是顯示遮罩層,則隱藏 textarea元素,並顯示替代原宿
  • 這裏 textarea的隱藏使用了 wx:if,會使其完全地從頁面中消失,而從新顯示出來的時候,textarea元素會從新建立,丟失原先輸入,因此給其加了個 value屬性,其值 txtRealContent就是緩存的 textarea已經輸入的文本內容;若是你不用這種方法,不讓 textarea徹底顯示,而僅僅是隱藏,例如使用 hidden="{{ showMask ? true :false }}",由於不涉及到 textarea的刪除與重建,因此就無需添加 value屬性來控制文本內容了。
  • textarea是能夠輸入可換行的文本內容的,因此這裏使用了 rich-text組件,在使用的時候,我發現 rich-text好像不支持溢出隱藏,因此又額外在其外面包了一層 view組件,並將其高度設置爲和 textarea相同。

上面四個步驟,都比較簡單,稍微須要注意的是,若是 textarea的內容包含了換行文本,則須要對換行符進行處理:

textareaContent.replace(/\n/g, '<br/>')
若是你想讓 textarea自動增長高度而不是固定高度,給 textarea加了個 auto-height,那麼就須要「實時」獲取其高度 說是 「實時」,其實也並非那麼實時,不考慮其餘樣式的變化, textarea的高度與行數有關,每增減一行,其高度纔會變化,因此只須要監控其內容行數的變化便可,剛好 textarea組件也已經提供了這個監控器: bindlinechange
實例代碼以下:
<view class="page-body">
  <button bindtap="changeMaskVisible">切換mask</button>
  <view class="textarea-wrp">
    <textarea id="text-area" value="{{txtContent}}" bindinput='txtInput' bindlinechange="textAreaLineChange" wx:if="{{!showMask}}" auto-height />
    <view class='rich-text' style="{{('height:' + txtHeight + 'px')}}" wx:else>
      <rich-text nodes="{{txtRealContent}}"></rich-text>
    </view>
  </view>
  <button>Footer</button>
  <view wx:if="{{showMask}}" bindtap="changeMaskVisible" class="mask">
    <view class="mask-content"></view>    
  </view>
</view>

樣式:

.rich-text { overflow: hidden;
} .mask { position: fixed; top: 0; right: 0; bottom: 0; left: 0; background-color: rgba(0, 0, 0, .6); z-index: 10;
} .mask-content { position: fixed; top: 44%; left: 50%; height: 60%; width: 60%; transform: translate(-50%, -50%); background-color: yellowgreen; z-index: 12;
}

js:

Page({ data: { txtRealContent: '', txtContent: '', showMask: false, txtHeight: 0 }, textAreaLineChange(e) { this.setData({ txtHeight: e.detail.height }) }, txtInput(e) { this.setData({ txtContent: e.detail.value }) }, changeMaskVisible(e) { if (!this.data.showMask) { // 將換行符轉換爲wxml可識別的換行元素 <br/>
      const txtRealContent = this.data.txtContent.replace(/\n/g, '<br/>') this.setData({ txtRealContent }) } this.setData({ showMask: !this.data.showMask }) } })
相關文章
相關標籤/搜索