美文网首页APP & program
微信小程序组件: 点击列表项弹出输入框

微信小程序组件: 点击列表项弹出输入框

作者: 牛会骑自行车 | 来源:发表于2023-01-30 13:30 被阅读0次

    注意事项

    使用页面设置
    1. 每个元素需要设置id, 便于后面进行取值(单项底边界)
    2. 如果是有tabBar的主页面, 需要传参告诉组件, 进行tabBar的隐藏设置(不隐藏的话textarea的fixed定位会将tabBar的距离顶出来.....说不清楚了, 请看图片😂)
    组件
    1. 页面滚动容器的paddingBottom需要通过triggerEvent带着数值传出来
    2. textarea中webkit-scrollbar的消失, 需要将样式写在app.wxss中(组件的wxss中只能使用类名) 报错
    3. wx.pageScroll可以在组件中使用

    代码

    组件wxml ⬇️

    <view class="comment-view" id="njxCommentTextarea" style="bottom: {{textBottom}}px;">
      <textarea class="textarea" style="margin-right: {{isIos ? 0 : 10}}px;padding: {{isIos ? '0 10px' : '4px 10px'}};" value="{{inputValue}}" placeholder="{{placeholder}}" placeholder-class="textarea-placeholder" focus="{{focus}}" auto-height fixed adjust-position="{{false}}" cursor-spacing="140" show-confirm-bar="{{false}}" confirm-type="send" bindkeyboardheightchange="getKeyBoardHeight" bindblur="onBlur" bindinput="onInput" bindconfirm="onSend"></textarea>
      <view class="njx_button" wx:if="{{!isIos}}" catchtap="onSend">发送</view>
    </view>
    

    组件wxss ⬇️

    @import "/components/common.wxss";
    
    .comment-view {
      width: 100vw;
      padding: 6px 12px;
      display: flex;
      justify-content: space-between;
      align-items: center;
    
      font-size: 14px;
    
      background: #ededf4;
      position: fixed;
    }
    
    .textarea {
      width: 100%;
      background: #fff;
      border-radius: 4px;
    }
    
    .textarea-placeholder {
      color: #666666;
    }
    .njx_button {
      min-width: 54px!important;
    }
    

    组件js ⬇️

    Component({
      properties: {
        inputValue: String,
        // 滚动容器id(必传参): 用来获取当前scrollTop
        scrollContainerId: {
          required: true,
          type: String,
          value: "",
        },
        // 当前点击元素的id(必传参)
        currentElId: {
          required: true,
          type: String,
          value: "",
        },
        placeholder: String,
        // 是否是有tabBar的页面: 如果有, 需要在输入框弹出且定位的过程中将tabBar隐藏
        hasTabBar: {
          type: Boolean,
          value: false,
        },
      },
      data: {
        isIos: false,
        focus: false,
    
        initPageHeight: false,
        pageHeight: 0,
        initKeyBoardHeight: false,
        keyBoardHeight: 0,
        initTextHeight: false,
        textHeight: 0,
    
        textBottom: -1000,
        elBottom: 0,
    
        beforeScrollTop: 0,
      },
      methods: {
        async getSystem() {
          const {
            system,
          } = wx.getSystemInfoSync();
    
          this.setData({
            isIos: system.includes('iOS'),
          })
        },
        getDomInfo({
          elId,
          isComponent
        }) {
          // createSelectorQuery用在组件中的元素时用this, 页面中的元素时使用wx
          let _this = isComponent ? this : wx;
          return new Promise((resolve) => {
            _this.createSelectorQuery().select('#' + elId).boundingClientRect().exec(function (res) {
              resolve(res[0])
            })
          })
        },
        getKeyBoardHeight(e) {
          const {
            height: keyBoardHeight,
          } = e.detail;
    
          if (!this.data.initKeyBoardHeight && keyBoardHeight !== 0) {
            this.setData({
              keyBoardHeight,
              initKeyBoardHeight: true,
            })
    
            this.fixTextarea();
          }
        },
        onPageScroll({
          scrollTop,
          paddingBottom
        }) {
          this.triggerEvent('padpage', {
            paddingBottom,
          })
          
          wx.pageScrollTo({
            scrollTop,
          })
        },
    
        async setEl(elId) {
          wx.hideTabBar();
          // 获取页面高度
          if(!this.data.initPageHeight) {
            const {screenHeight, windowHeight} = wx.getSystemInfoSync();
    
            this.setData({
              pageHeight: this.data.hasTabBar ? screenHeight : windowHeight
            })
          }
          // 获取元素底边距
          const {
            bottom: elBottom
          } = await this.getDomInfo({
            elId
          });
    
          if (!this.data.initTextHeight) {
            const {
              height: textHeight
            } = await this.getDomInfo({
              elId: 'njxCommentTextarea',
              isComponent: true
            });
    
            this.setData({
              textHeight,
              initTextHeight: true,
            })
          }
          // 聚焦
          this.setData({
            focus: true,
            elBottom,
          })
          this.data.keyBoardHeight && this.fixTextarea();
        },
        fixTextarea() {
          let textBottom = this.data.pageHeight - this.data.elBottom - this.data.textHeight;
    
          let fixPosition = ({
            value,
            beforeScrollTop
          }) => {
            this.setData({
              textBottom: this.data.isIos ? value : value - 1,
              beforeScrollTop
            })
          }
    
          if (textBottom > this.data.keyBoardHeight) {
            fixPosition({
              value: this.data.isIos ? this.data.keyBoardHeight : this.data.keyBoardHeight - 1,
              beforeScrollTop: 0
            });
          } else {
            wx.createSelectorQuery().select('#' + this.data.scrollContainerId).boundingClientRect().selectViewport().scrollOffset().exec(res => {
              const beforeScrollTop = res[1].scrollTop;
              fixPosition({
                value: this.data.keyBoardHeight,
                beforeScrollTop
              });
    
              const scrollTop = beforeScrollTop + this.data.keyBoardHeight - textBottom;
    
              this.onPageScroll({
                paddingBottom: this.data.textHeight + this.data.keyBoardHeight,
                scrollTop,
              });
            })
          }
        },
        onBlur() {
          this.onPageScroll({
            scrollTop: this.data.beforeScrollTop,
            paddingBottom: 0
          })
          this.data.hasTabBar && wx.showTabBar();
          this.setData({
            textBottom: -this.data.textHeight,
            inputValue: "",
          })
        },
        onInput(e) {
          const inputValue = e.detail.value;
          this.setData({
            inputValue,
          })
        },
        onSend(e) {
          const {
            value
          } = e.detail;
    
          this.triggerEvent('sendvalue', {
            value: value || this.data.inputValue,
          })
        },
      },
      observers: {
        currentElId(id) {
          id && this.data.textBottom < 0 && this.setEl(id);
        },
      },
      lifetimes: {
        attached() {
          this.getSystem();
        }
      }
    })
    
    使用页面代码

    wxml ⬇️

    <view class="njx_container h_100">
      <view id="scrollNjx" style="padding-bottom: {{paddingBottom}}px;">
        <view class="njx_card" wx:for="{{list}}" wx:key="id" id="id-{{item.id}}" bindtap="toCommentComponent" data-item="{{item}}">
          {{item.id}}
        </view>
      </view>
    </view>
    
    <njx-comment-input scrollContainerId="scrollNjx" currentElId="{{currentElId}}" placeholder="{{placeholder}}" hasTabBar bindsendvalue="onSend" bindpadpage="onPadPage"></njx-comment-input>
    

    js ⬇️

    let list = [];
    for (let i = 0; i <= 20; i++) {
      list.push({
        id: i
      });
    }
    
    Page({
      data: {
        list,
        placeholder: "",
        paddingBottom: 20,
        currentElId: "",
      },
    
      toCommentComponent(e) {
        const {item} = e.currentTarget.dataset;
        this.setData({
          currentElId: 'id-' + item.id,
          placeholder: '我的评论ID是 ---- ' + item.id,
        })
      },
      onSend(e) {
        const {value} = e.detail;
        console.log(value, 'VALUE ~~~~~~~~~~~~~~~');
      },
      onPadPage(e) {
        const {paddingBottom} = e.detail;
        this.setData({
          paddingBottom,
        })
      },
      onLoad(options) {
      },
    })
    
    最后记得在json中那啥usingComponents呀~~

    这篇注释有点少, 都在之前那篇里, 有变化的才写了新的嘿嘿

    tada~~~一个评论区的输入框组件就完成啦💃

    实际使用时发现了新的问题, 这里的代码懒得改了😂
    最好将输入框容器的id也设置为动态, 从使用页面传进来.

    相关文章

      网友评论

        本文标题:微信小程序组件: 点击列表项弹出输入框

        本文链接:https://www.haomeiwen.com/subject/wbayhdtx.html