自定义键盘覆盖表单的坑

838 阅读2分钟

自定义键盘覆盖表单的坑

最近在开发Cordova+vue项目时,引用了vant-ui的数字自定义键盘,因为不是原生键盘,所以出现了键盘覆盖了表单的现象,导致使用数字自定义键盘的时候看不到自己输入了啥。

思路非常简单,既然覆盖上了,那就让表单在自定义键盘弹出的时候滚上去就OK了。

1 第一次尝试 -- scrollBy

采用了scrollBy方法。

// 键盘组件代码
 methods: {
      // 打开键盘的时候
      handleNumberClick () {
          // 弹起数字键盘
          this.showNumberKeyBoard = true
          // 比较下被点的输入框高度和整个页面滚动高度的高度差
          // 也就是算一下输入框距离顶部的距离,如果超过360,就认为会被遮盖到
          // 就向上滚一些
          if (this.$refs.keyBoard.offsetTop - this.$parent.$refs.section.scrollTop > 360) {
              this.scrolled = true
              this.$parent.$refs.section.scrollBy({
                  top: 300,
                  behavior: 'smooth'
              })
          }
      },
      handleBlur () {
          this.$emit('input',this.number)
          this.showNumberKeyBoard = false
          if (this.scrolled) {
              // 键盘失焦,滚回来
              this.$parent.$refs.section.scrollBy({
                  top: 0,
                  behavior: 'smooth'
              })
              this.scrolled = false
          }
      }
  }

万万没想到,在h5和iOS上跑得很好的代码,在Android上不起作用。

然后就打了桩,发现Android竟然在报错。说不认识scrollBy.

是的,对我来讲这是个谜,我现在也不知道为什么他不认识scrollBy

2 第二次尝试 -- jquery

网上有解决方案jquery可以解决这个问题,就使用了jquery。

// 键盘组件代码
methods: {
    handleNumberClick () {
        this.showNumberKeyBoard = true
        if (this.$refs.keyBoard.offsetTop - this.$parent.$refs.section.scrollTop > 360) {
             this.scrolled = true
             // 使用这种方式
             $('#startInspectSection').animate({
                 scrollTop: 300
             }, 1000);
             // 或者使用这种方式
             // $('#startInspectSection').scrollTop(300)
             
        }
    },
    handleBlur () {
        this.$emit('input',this.number)
        this.showNumberKeyBoard = false
        if (this.scrolled) {
            // 使用这种方式
            $('#startInspectSection').animate({
               scrollTop: 0
            }, 1000);
            // 或者使用这种方式
            // $('#startInspectSection').scrollTop(0)
            this.scrolled = false
        }
    }
}

jquery解决了我的问题。随之有两个疑问:

  • jquery是怎么做到的
  • 怎么才能不再vue里用jquery

翻阅jquery源码,找到了这段代码。

// Create scrollLeft and scrollTop methods
jQuery.each( { scrollLeft: "pageXOffset", scrollTop: "pageYOffset" }, function( method, prop ) {
 var top = "pageYOffset" === prop;

 jQuery.fn[ method ] = function( val ) {
  return access( this, function( elem, method, val ) {

   // Coalesce documents and windows
   var win;
   if ( isWindow( elem ) ) {
    win = elem;
   } else if ( elem.nodeType === 9 ) {
    win = elem.defaultView;
   }

   if ( val === undefined ) {
    return win ? win[ prop ] : elem[ method ];
   }

   if ( win ) {
        // 如果是window的话
    win.scrollTo(
     !top ? val : win.pageXOffset,
     top ? val : win.pageYOffset
    );

   } else {
        // 如果不是window的话,就直接使用了scrollTop或scrollLeft属性
    elem[ method ] = val;
   }
  }, method, val, arguments.length );
 };
});

是的,为什么要纠结于方法呢,可以使用属性啊。

3 第三次尝试 -- scrollTop属性

基于jquery的实现,使用vue来实现,就是使用scrollTop属性。

methods: {
    handleNumberClick () {
        this.showNumberKeyBoard = true
        if (this.$refs.keyBoard.offsetTop - this.$parent.$refs.section.scrollTop > 360) {
            this.originOffset = this.$parent.$refs.section.scrollTop
            this.$parent.$refs.section.scrollTop = this.scrolled = this.$parent.$refs.section.scrollTop  + 300
        }
    },
    handleBlur () {
        this.$emit('input',this.number)
        this.showNumberKeyBoard = false
        if (this.scrolled) {
            this.$parent.$refs.section.scrollTop = this.originOffset
            this.scrolled = 0
        }
    }
},

总结

要抽时间好好看看基础知识了,都是基础不牢的锅。

本文使用 mdnice 排版