往期鸿蒙5.0全套实战文章必看:(文中附带全栈鸿蒙5.0学习资料)
Web组件适配H5中的输入框
场景
将H5中input标签的type属性设置为文本类型时,会在移动端拉起软键盘。由于设备和UI布局的差异,可分为三类软键盘适配场景:
1、当web组件拉起软键盘后的布局问题。
2、input标签的输入框获焦和失焦是否弹出和隐藏问题。
3、input标签的type属性不同拉起不同的软键盘适配。
-
网页拉起的软键盘适配当前页面布局
web组件加载的H5拉起的键盘对H5页面的避让模式可以通过keyboardAvoidMode属性来进行设置,总共分为三种避让模式:
属性 | 值 | 说明 |
RESIZE_VISUAL | 0 | 将整个页面从底部往上抬起软键盘的高度,web的页面高度不变,且可以滑动 |
RESIZE_CONTENT | 1 | 改变页面可视区域的高度,实现避让,页面不可滑动 |
OVERLAYS_CONTENT | 2 | 不顶起页面,不改变高度,将软键盘盖到当前页面上,页面不可滑动 |
1、页面被顶起或未被顶起:
效果展示:分别为三种属性的实际效果
在没有特殊业务的情况下,可自由选择避让模式解决拉起软键盘时页面被顶起或页面未被顶起的问题。参考以下代码实现:
import { webview } from '@kit.ArkWeb';
@Entry
@Component
struct WebTest {
controller: webview.WebviewController = new webview.WebviewController();
aboutToAppear(): void {
webview.WebviewController.setWebDebuggingAccess(true)
}
build() {
Column() {
Web({ src: $rawfile('rich1.html'), controller: this.controller })
.defaultFontSize(20)
.defaultFixedFontSize(20)
.domStorageAccess(true)
.width('100%')
.height('100%')
.keyboardAvoidMode(2)
}.width('100%').height('100%')
}
}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
<style>
.container {
max-width: 100%;
overflow-x: hidden;
margin: 0 auto;
}
body {
background-color: #FCEDDF;
}
p {
color: #F77B7D;
}
</style>
</head>
<body>
<input type="text"/>
<div class="container">
<p>软键盘避让模式示例</p>
</div>
</body>
</html>
2、需要页面在软键盘上面避让一段距离:
方案实现:通过监听软键盘是否弹出,来动态设置一个放置在web组件下面的blank组件的高度,将web页面顶上去一段距离,达到以下效果
示例代码如下:
import { webview } from '@kit.ArkWeb';
import { BusinessError } from '@kit.BasicServicesKit';
import { window } from '@kit.ArkUI';
@Entry
@Component
struct WebComponent {
controller: webview.WebviewController = new webview.WebviewController();
@State toolOff: number = 0;
aboutToAppear(): void {
webview.WebviewController.setWebDebuggingAccess(true);
this.listenKeyboard();
}
private listenKeyboard() {
window.getLastWindow(getContext(this)).then(currentWindow => {
currentWindow.on('keyboardHeightChange', (data) => {
let keyboardHeight = Math.floor(px2vp(data));
if (keyboardHeight > 0) {
this.toolOff = keyboardHeight + 20
} else {
this.toolOff = 0
}
})
})
}
build() {
Stack() {
Column() {
Web({ src: $rawfile('rich1.html'), controller: this.controller })
.layoutWeight(1)
.domStorageAccess(true)
.height('100%')
.keyboardAvoidMode(1)
Blank()
.backgroundColor("#ffffff")
.width('100%')
.height(this.toolOff)
}
}
}
}
3、自定义弹窗中的web页面拉起软键盘的避让情况:
在此场景下,H5页面拉起的软键盘会将整个弹窗都顶起来,但是当弹窗内的web组件使用了web的自适应高度能力,即加上了.layoutMode(WebLayoutMode.FIT_CONTENT)属性后,会导致弹窗显示异常,这是因为目前这个属性并未做避让弹窗的处理。目前使用的规避方案就是通过获取当前页面的高度来给web页面动态设置,来替代原来的自适应高度的方法。
import web_webview from '@ohos.web.webview'
import { BusinessError } from '@kit.BasicServicesKit';
@Entry
@Component
struct Page122603 {
editDialogController: CustomDialogController = new CustomDialogController({
builder: CommentsEditDialog({}),
alignment: DialogAlignment.Bottom,
customStyle: true,
})
build() {
Column() {
Button('点击打开弹窗')
.backgroundColor('#f7797d')
.onClick(() => {
this.editDialogController.open()
})
}.width('100%').height('100%')
}
}
@CustomDialog
export struct CommentsEditDialog {
controller: CustomDialogController
@State wController: web_webview.WebviewController = new web_webview.WebviewController()
@State webResult: string = ''
private jsStr: string =
'function watchWindowSize() { var rect = document.documentElement.getBoundingClientRect(); var docHeight = rect.height; return docHeight; } document.addEventListener(\'DOMContentLoaded\', (event) => { let height = watchWindowSize(); console.log("整个HTML文档的实际高度:", height, "像素"); });'
@State scripts: Array<ScriptItem> = [
{ script: this.jsStr, scriptRules: ["*"] }
];
build() {
Stack() {
Column() {
Web({
src: $rawfile('rich.html'),
controller: this.wController,
})
.javaScriptOnDocumentStart(this.scripts)
.onPageEnd(event => {
this.wController.runJavaScript(
`watchWindowSize()`,
(error, result) => {
if (error) {
console.error(`run JavaScript error, ErrorCode: ${(error as BusinessError).code}, Message: ${(error as BusinessError).message}`);
return;
}
if (result) {
this.webResult = result;
console.info(`The test() return value is: ${result}`);
}
});
})
.height(this.webResult)
.domStorageAccess(true)
.overScrollMode(OverScrollMode.NEVER)
.keyboardAvoidMode(1)
}.height('100%')
}
.expandSafeArea([SafeAreaType.SYSTEM])
.width('100%')
.height('60%')
}
closeDialog() {
if (this.controller != null) {
this.controller.close()
}
}
}
-
网页上输入框失焦获焦问题
1、获焦后未自动弹出软键盘:
目前web的规格是输入框自动获焦后不会拉起软键盘,可使用输入法框架的showTextInput方法拉起软键盘,代码如下:
import web_webview from '@ohos.web.webview'
import inputMethod from '@ohos.inputMethod';
import { BusinessError } from '@ohos.base';
let inputMethodController = inputMethod.getController();
@Entry
@Component
struct WebComponent {
controller: web_webview.WebviewController = new web_webview.WebviewController()
aboutToAppear(): void {
try {
let textConfig: inputMethod.TextConfig = {
inputAttribute: {
textInputType: 0,
enterKeyType: 1
}
};
inputMethodController.attach(true, textConfig, (err: BusinessError) => {
if (err) {
console.error(`Failed to attach: ${JSON.stringify(err)}`);
return;
}
console.log('Succeeded in attaching the inputMethod.');
});
} catch (err) {
console.error(`Failed to attach: ${JSON.stringify(err)}`);
}
}
build() {
Column() {
Web({ src: $rawfile('rich1.html'), controller: this.controller })
.domStorageAccess(true)
.onPageVisible(() => {
inputMethodController.showTextInput((err: BusinessError) => {
if (err) {
console.error(`Failed to showTextInput: ${JSON.stringify(err)}`);
return;
}
console.log('Succeeded in showing the inputMethod.');
});
})
}
}
}
2、点击软键盘右下角“完成”键后输入框未失焦,键盘未收起:
目前可以通过runJavascript方法加载一段js使输入框失焦,示例代码如下:
import web_webview from '@ohos.web.webview';
@Entry
@Component
struct SecondPage {
webviewController: web_webview.WebviewController = new web_webview.WebviewController();
aboutToAppear(): void {
web_webview.WebviewController.setWebDebuggingAccess(true)
}
build() {
Column() {
Web({
src: $rawfile('inputArea.html'), controller: this.webviewController
})
.domStorageAccess(true)
.keyboardAvoidMode(2)
.fileAccess(true)
.onPageEnd(() => {
this.webviewController.runJavaScript('function hideKeyboard() {\n' +
' document.getElementById(\'inputField\').blur();\n' +
' }\n' +
'\n' +
' document.getElementById(\'inputField\').addEventListener(\'keydown\', function(event) {\n' +
' if (event.key === \'Enter\') {\n' +
' hideKeyboard();\n' +
' }\n' +
' });')
})
}
.padding({ top: 28 })
.height('100%')
.width('100%')
}
}
这段js的作用就是监听软键盘右下角的回车键,即显示为“完成”或者“开始”的那个按键,当js监听到它按下后调用失焦方法收起软键盘。
-
H5上input标签的不同type属性与拉起不同类型键盘的适配
网页输入框拉起不同类型的软键盘与input标签的两个属性有关系,分别是type属性和inputmode属性,这两个属性单独使用以及一起使用拉起什么类型软键盘的关系如下:
属性 | type="text"; type="url"; type="email" | type="number"; type="tel" | type="password" | type="text"和inputmode="numeric" | type="number"和inputmode="text" |
拉起键盘的类型 | 文本键盘 | 数字键盘 | 华为安全键盘 | 数字键盘 | 数字键盘 |
可以根据以上表格两个属性的作用情况来根据业务需求拉起不同的软键盘,如果有特殊的业务场景,例如输入座机号,它需要输入一个“-”符。这种情况可以通过在应用侧执行一段js脚本到H5上,就可以实现“-”的提交以及限制其他字符的输入,H5示例代码如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>获取输入框值示例</title>
<style>
body {
font-family: Arial, sans-serif;
background-color: #f7797d;
margin: 20px;
}
label, input {
font-size: 18px;
margin: 10px 0;
display: block;
}
button {
margin-top: 10px;
padding: 10px 20px;
font-size: 18px;
background-color: #ffc3a0;
color: white;
border: none;
cursor: pointer;
}
button:hover {
background-color: #C6FFDD;
}
</style>
</head>
<body>
<h1>获取输入框值示例</h1>
<form id="numericForm">
<label for="phoneInput">请输入:</label>
<input type="number" id="phoneInput" placeholder="请填写公司电话Number"/>
<button type="submit">提交</button>
</form>
<h3>提交结果:</h3>
<p id="submitOutput">-</p>
<script>
const numericForm = document.getElementById('numericForm');
numericForm.addEventListener('submit', (event) => {
event.preventDefault();
const ttttt = document.getElementById("phoneInput").value
submitOutput.textContent = `您提交的数字是:${ttttt}`;
});
</script>
</body>
</html>
以上代码中input标签拉起软键盘是数字键盘,不能限制其它字符的输入,并且在提交输入内容的时候由于type属性的限制导致提交失败。
目前的解决方案就是通过js方法把input的标签的type改为text类型,然后继续添加inputmode="numeric"属性,拉起数字键盘,最后使用一段正则限制其他字符输入只允许输入“-”字符,示例代码如下:
import web_webview from '@ohos.web.webview';
@Entry
@Component
struct SecondPage {
webviewController: web_webview.WebviewController = new web_webview.WebviewController();
build() {
Column() {
Web({
src: $rawfile('Input3.html'), controller: this.webviewController
})
.domStorageAccess(true)
.keyboardAvoidMode(2)
.fileAccess(true)
.onPageEnd(() => {
this.webviewController.runJavaScript(
'const input = document.getElementById(\'phoneInput\');' +
'input.type = \'text\'; ' +
'input.inputMode = \'numeric\';' +
'input.addEventListener(\'input\', function(event) { ' +
'const nonNumericRegex = /[^0-9\\-]/g; ' +
'input.value = input.value.replace(nonNumericRegex, \'\'); ' +
'});'
)
})
}
.padding({ top: 28 })
.height('100%')
.width('100%')
}
}