Skip to content

0x00d-Web知识之VisualViewport

Visual Viewport API 提供了当前页面的视觉视口接口,即 VisualViewport 。对于每个页面容器来说(如 iframe),都存在有一个独立的 window 对象。每个页面容器的 window 对象都有一个独立的 VisualViewport 属性。

你可以使用 Window.visualViewport 获得对应 window 的视觉视口 API。

可以间接获取iOS端键盘的高度,解决一些键盘弹出造成的布局问题(iOS13支持)。

实际问题

|230

h5页面布局中,顶部为‘注意事项’,底部固定为输入框。在iOS设备预览时,当键盘弹起的时候,看不到顶部的注意事项。

直观来说,问题导致的原因是键盘弹起的时候,iOS端的webview不会改变尺寸。因此导致顶部的注意事项被顶上去了。

解决方案:

方案1:
配合移动原生端处理(如果是自己的app),当键盘弹出或者收起的时候,调用原生端调整webview的高度。

swift
/// 键盘缩放的时候是需要调整大小
var resizeWindowOnKeyboardAppear = false {
	didSet {
		if resizeWindowOnKeyboardAppear == false {
			webView.snp.remakeConstraints { [weak self] make in													make.top.left.right.bottom.equalToSuperview()											    
			}
		}
	}
}
    
@objc func keyboardWillShow(_ notification: Notification) {
        // 获取键盘的高度:(notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue.height
        if resizeWindowOnKeyboardAppear {
            if let keyboardHeight = (notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue.height {
                webView.snp.remakeConstraints { make in                                            make.left.right.top.equalToSuperview()
                    make.bottom.equalToSuperview().offset(-keyboardHeight)
                }
            }
        }
    }
/// 键盘缩放的时候是需要调整大小
var resizeWindowOnKeyboardAppear = false {
	didSet {
		if resizeWindowOnKeyboardAppear == false {
			webView.snp.remakeConstraints { [weak self] make in													make.top.left.right.bottom.equalToSuperview()											    
			}
		}
	}
}
    
@objc func keyboardWillShow(_ notification: Notification) {
        // 获取键盘的高度:(notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue.height
        if resizeWindowOnKeyboardAppear {
            if let keyboardHeight = (notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue.height {
                webView.snp.remakeConstraints { make in                                            make.left.right.top.equalToSuperview()
                    make.bottom.equalToSuperview().offset(-keyboardHeight)
                }
            }
        }
    }

方案2: 使用 visualViewport, 示例代码:

js
// 页面顶部增加一个元素,用于弹出键盘时,将注意事项撑下去
<div
  id="con-container"
  :style="{'height': keyboardHeightHandle.keyboardHeight + 'px'}"
>
</div>

// 页面加载完成时
this.keyboardHeightHandle.originHeight = window.visualViewport.height;
window.addEventListener('scroll', this.handleOnScroll);
window.visualViewport.addEventListener('resize', this.handleResizeEvent);

/* 弹出键盘时,防止用户滚动最外层看到空白*/
function handleOnScroll () {
  if (this.keyboardHeightHandle.keyboardHeight > 0) {
	this.$refs.inputRef.blur();
  }
},
 /* 处理键盘问题*/
function handleResizeEvent () {
  const kbHeight = this.keyboardHeightHandle.originHeight - window.visualViewport.height;
  // 可能存在用户拖拽固定,导致键盘不准,这里额外判断
  if (kbHeight != 0 && kbHeight < this.keyboardHeightHandle.keyboardHeight) {
	return;
  }
  if (kbHeight == 0) {
	this.keyboardHeightHandle.keyboardHeight = kbHeight;
  } else {
	setTimeout(() => {
	  this.keyboardHeightHandle.keyboardHeight = kbHeight;
	  // 滚动到最底部
	  if (this.$refs.contentRef) {
		this.$refs.contentRef.scrollTop =
			this.$refs.contentRef.scrollHeight;
	  }
	}, 200);
  }
}
// 页面顶部增加一个元素,用于弹出键盘时,将注意事项撑下去
<div
  id="con-container"
  :style="{'height': keyboardHeightHandle.keyboardHeight + 'px'}"
>
</div>

// 页面加载完成时
this.keyboardHeightHandle.originHeight = window.visualViewport.height;
window.addEventListener('scroll', this.handleOnScroll);
window.visualViewport.addEventListener('resize', this.handleResizeEvent);

/* 弹出键盘时,防止用户滚动最外层看到空白*/
function handleOnScroll () {
  if (this.keyboardHeightHandle.keyboardHeight > 0) {
	this.$refs.inputRef.blur();
  }
},
 /* 处理键盘问题*/
function handleResizeEvent () {
  const kbHeight = this.keyboardHeightHandle.originHeight - window.visualViewport.height;
  // 可能存在用户拖拽固定,导致键盘不准,这里额外判断
  if (kbHeight != 0 && kbHeight < this.keyboardHeightHandle.keyboardHeight) {
	return;
  }
  if (kbHeight == 0) {
	this.keyboardHeightHandle.keyboardHeight = kbHeight;
  } else {
	setTimeout(() => {
	  this.keyboardHeightHandle.keyboardHeight = kbHeight;
	  // 滚动到最底部
	  if (this.$refs.contentRef) {
		this.$refs.contentRef.scrollTop =
			this.$refs.contentRef.scrollHeight;
	  }
	}, 200);
  }
}

其他参考示例: css - How to make fixed-content go above iOS keyboard? - Stack Overflow