鸿蒙页面如何与H5页面交互?
- 先看效果
- 前言
- 通信功能介绍
- Web组件使用问题
- Harmony OS NEXT版本(接口及解决方案兼容API12版本或以上版本)
先看效果
功能介绍
- 点击Click Me按钮可以接收展示鸿蒙传递给html的内容
- 点击霓虹灯按钮可以同步更新底部鸿蒙页面的按钮内容“打开”或“关闭”
- 点击底部鸿蒙页面的按钮,可以同步修改html的霓虹灯按钮状态
前言
在开发App时,我们经常会遇到使用webView加载H5页面的场景,这样做的好处就不多加赘述了,那么鸿蒙App如何加载H5页面呢?又怎么与H5页面进行通信呢?,废话少说,直接上代码。
通信功能介绍
App可以通过runJavaScript()方法调用html页面的JavaScript相关函数。 在下面的示例中,点击App的“runJavaScript”按钮时,来触发html页面的change()方法更新霓虹灯按钮状态。
html通过鸿蒙的test方法,获取鸿蒙传递过来的数据。通过出发changeBtnText同步更新鸿蒙按钮的内容。
html文件目录:harmonyApp\entry\src\main\resources\rawfile
html代码如下:
<!-- index.html -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>霓虹灯按钮拨动特效</title>
<style>
* {
border: 0;
box-sizing: border-box;
margin: 0;
padding: 0;
}
:root {
--hue: 223;
--off-hue: 3;
--on-hue1: 123;
--on-hue2: 168;
--fg: hsl(var(--hue), 10%, 90%);
--primary: hsl(var(--hue), 90%, 50%);
--trans-dur: 0.6s;
--trans-timing: cubic-bezier(0.65, 0, 0.35, 1);
font-size: calc(40px + (60 - 40) * (100vw - 320px) / (2560 - 320));
}
body,
input {
font: 1em/1.5 sans-serif;
}
body {
background-image: linear-gradient(45deg, hsl(var(--hue), 10%, 20%), hsl(var(--hue), 10%, 10%));
color: var(--fg);
display: flex;
height: 100vh;
transition: background-color var(--trans-dur), color var(--trans-dur);
}
.common{
height: 6em;
width: 5em;
}
.switch,
.switch__input {
-webkit-tap-highlight-color: #0000;
}
.switch {
display: block;
margin: auto;
position: relative;
width: 5em;
height: 3em;
}
.switch__base-outer,
.switch__base-inner {
display: block;
position: absolute;
}
.switch__base-outer {
border-radius: 1.25em;
box-shadow: -0.125em -0.125em 0.25em hsl(var(--hue), 10%, 30%), 0.125em 0.125em 0.125em hsl(var(--hue), 10%, 30%) inset, 0.125em 0.125em 0.25em hsl(0, 0%, 0%), -0.125em -0.125em 0.125em hsl(var(--hue), 10%, 5%) inset;
top: 0.125em;
left: 0.125em;
width: 4.75em;
height: 2.75em;
}
.switch__base-inner {
border-radius: 1.125em;
box-shadow: -0.25em -0.25em 0.25em hsl(var(--hue), 10%, 30%) inset, 0.0625em 0.0625em 0.125em hsla(var(--hue), 10%, 30%), 0.125em 0.25em 0.25em hsl(var(--hue), 10%, 5%) inset, -0.0625em -0.0625em 0.125em hsla(var(--hue), 10%, 5%);
top: 0.375em;
left: 0.375em;
width: 4.25em;
height: 2.25em;
}
.switch__base-neon {
display: block;
overflow: visible;
position: absolute;
top: 0;
left: 0;
width: 100%;
height: auto;
}
.switch__base-neon path {
stroke-dasharray: 0 104.26 0;
transition: stroke-dasharray var(--trans-dur) var(--trans-timing);
}
.switch__input {
outline: transparent;
position: relative;
width: 100%;
height: 100%;
-webkit-appearance: none;
appearance: none;
}
.switch__input:before {
border-radius: 0.125em;
box-shadow: 0 0 0 0.125em hsla(var(--hue), 90%, 50%, 0);
content: "";
display: block;
position: absolute;
inset: -0.125em;
transition: box-shadow 0.15s linear;
}
.switch__input:focus-visible:before {
box-shadow: 0 0 0 0.125em var(--primary);
}
.switch__knob,
.switch__knob-container {
border-radius: 1em;
display: block;
position: absolute;
}
.switch__knob {
background-color: hsl(var(--hue), 10%, 15%);
background-image: radial-gradient(88% 88% at 50% 50%, hsl(var(--hue), 10%, 20%) 47%, hsla(var(--hue), 10%, 20%, 0) 50%), radial-gradient(88% 88% at 47% 47%, hsl(var(--hue), 10%, 85%) 45%, hsla(var(--hue), 10%, 85%, 0) 50%), radial-gradient(65% 70% at 40% 60%, hsl(var(--hue), 10%, 20%) 46%, hsla(var(--hue), 10%, 20%, 0) 50%);
box-shadow: -0.0625em -0.0625em 0.0625em hsl(var(--hue), 10%, 15%) inset, -0.125em -0.125em 0.0625em hsl(var(--hue), 10%, 5%) inset, 0.75em 0.25em 0.125em hsla(0, 0%, 0%, 0.8);
width: 2em;
height: 2em;
transition: transform var(--trans-dur) var(--trans-timing);
}
.switch__knob-container {
overflow: hidden;
top: 0.5em;
left: 0.5em;
width: 4em;
height: 2em;
}
.switch__knob-neon {
display: block;
width: 2em;
height: auto;
}
.switch__knob-neon circle {
opacity: 0;
stroke-dasharray: 0 90.32 0 54.19;
transition: opacity var(--trans-dur) steps(1, end), stroke-dasharray var(--trans-dur) var(--trans-timing);
}
.switch__knob-shadow {
border-radius: 50%;
box-shadow: 0.125em 0.125em 0.125em hsla(0, 0%, 0%, 0.9);
display: block;
position: absolute;
top: 0.5em;
left: 0.5em;
width: 2em;
height: 2em;
transition: transform var(--trans-dur) var(--trans-timing);
}
.switch__led {
background-color: hsl(var(--off-hue), 90%, 70%);
border-radius: 50%;
box-shadow: 0 -0.0625em 0.0625em hsl(var(--off-hue), 90%, 40%) inset, 0 0 0.125em hsla(var(--off-hue), 90%, 70%, 0.3), 0 0 0.125em hsla(var(--off-hue), 90%, 70%, 0.3), 0.125em 0.125em 0.125em hsla(0, 0%, 0%, 0.5);
display: block;
position: absolute;
top: 0;
left: 0;
width: 0.25em;
height: 0.25em;
transition: background-color var(--trans-dur) var(--trans-timing), box-shadow var(--trans-dur) var(--trans-timing);
}
.switch__text {
overflow: hidden;
position: absolute;
width: 1px;
height: 1px;
}
.switch__input:checked~.switch__led {
background-color: hsl(var(--on-hue1), 90%, 70%);
box-shadow: 0 -0.0625em 0.0625em hsl(var(--on-hue1), 90%, 40%) inset, 0 -0.125em 0.125em hsla(var(--on-hue1), 90%, 70%, 0.3), 0 0.125em 0.125em hsla(var(--on-hue1), 90%, 70%, 0.3), 0.125em 0.125em 0.125em hsla(0, 0%, 0%, 0.5);
}
.switch__input:checked~.switch__base-neon path {
stroke-dasharray: 52.13 0 52.13;
}
.switch__input:checked~.switch__knob-shadow,
.switch__input:checked~.switch__knob-container .switch__knob {
transform: translateX(100%);
}
.switch__input:checked~.switch__knob-container .switch__knob-neon circle {
opacity: 1;
stroke-dasharray: 45.16 0 45.16 54.19;
transition-timing-function: steps(1, start), var(--trans-timing);
}
.btn-box{
/* width: 2.5em; */
position: absolute;
top: 0.1em;
left: 50%;
transform: translateX(-50%);
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
.btn-box .btn {
width: 10em;
background-color: rgb(32, 93, 224);
border: none;
color: white;
padding: 15px 32px;
text-align: center;
text-decoration: none;
display: inline-block;
font-size: 0.3em;
margin: 4px 2px;
cursor: pointer;
}
.btn-box #demo {
font-size: 0.3em;
}
</style>
</head>
<body>
<div class="btn-box">
<button class="btn" type="button" onclick="callArkTS()">Click Me!</button>
<p id="demo"></p>
</div>
<label class="switch">
<input id="switch" class="switch__input" type="checkbox" role="switch">
<span class="switch__base-outer"></span>
<span class="switch__base-inner"></span>
<svg class="switch__base-neon" viewBox="0 0 40 24" width="40px" height="24px">
<defs>
<filter id="switch-glow">
<feGaussianBlur result="coloredBlur" stddeviation="1"></feGaussianBlur>
<feMerge>
<feMergeNode in="coloredBlur"></feMergeNode>
<feMergeNode in="SourceGraphic"></feMergeNode>
</feMerge>
</filter>
<linearGradient id="switch-gradient1" x1="0" y1="0" x2="1" y2="0">
<stop offset="0%" stop-color="hsl(var(--on-hue1),90%,70%)" />
<stop offset="100%" stop-color="hsl(var(--on-hue2),90%,70%)" />
</linearGradient>
<linearGradient id="switch-gradient2" x1="0.7" y1="0" x2="0.3" y2="1">
<stop offset="25%" stop-color="hsla(var(--on-hue1),90%,70%,0)" />
<stop offset="50%" stop-color="hsla(var(--on-hue1),90%,70%,0.3)" />
<stop offset="100%" stop-color="hsla(var(--on-hue2),90%,70%,0.3)" />
</linearGradient>
</defs>
<path fill="none" filter="url(#switch-glow)" stroke="url(#switch-gradient1)" stroke-width="1"
stroke-dasharray="0 104.26 0" stroke-dashoffset="0.01" stroke-linecap="round"
d="m.5,12C.5,5.649,5.649.5,12,.5h16c6.351,0,11.5,5.149,11.5,11.5s-5.149,11.5-11.5,11.5H12C5.649,23.5.5,18.351.5,12Z" />
</svg>
<span class="switch__knob-shadow"></span>
<span class="switch__knob-container">
<span class="switch__knob">
<svg class="switch__knob-neon" viewBox="0 0 48 48" width="48px" height="48px">
<circle fill="none" stroke="url(#switch-gradient2)" stroke-dasharray="0 90.32 0 54.19"
stroke-linecap="round" stroke-width="1" r="23" cx="24" cy="24"
transform="rotate(-112.5,24,24)" />
</svg>
</span>
</span>
<span class="switch__led"></span>
<span class="switch__text">Power</span>
</label>
</body>
<script>
let switchDom = document.getElementById("switch");
function callArkTS() {
let str = window.harmony.test();
document.getElementById("demo").innerHTML = '鸿蒙传递过来的参数: '+str;
}
switchDom.addEventListener("change", function (e) {
if(e.target.checked){
window.harmony.changeBtnText('关闭');
}else{
window.harmony.changeBtnText('打开');
}
});
function change() {
switchDom.checked = !switchDom.checked;
}
</script>
</html>
鸿蒙App代码如下:
// xxx.ets
import web_webview from '@ohos.web.webview';
class WebViewModel {
btnText: string = '打开';
constructor() {
}
test(): string {
return 'ArkTS Hello World!';
}
// 修改按钮文本
changeBtnText(value:string){
this.btnText = value;
}
}
@Entry
@Component
struct WebComponent {
webviewController: web_webview.WebviewController = new web_webview.WebviewController();
// 声明需要注册的对象
@State vm: WebViewModel = new WebViewModel();
build() {
Stack() {
Column() {
// 页面内容
Scroll(){
Column(){
// web组件加载本地index.html页面
Web({ src: $rawfile('index.html'), controller: this.webviewController})
.domStorageAccess(true)
.javaScriptAccess(true)
.onProgressChange((event)=>{
// 自行编写加载状态
})
// 将对象注入到web端
.javaScriptProxy({
object: this.vm,
name: "harmony",
methodList: ["test",'changeBtnText'],
controller: this.webviewController
})
}.padding(16)
}
.edgeEffect(EdgeEffect.Fade)
.width('100%')
.layoutWeight(1)
.align(Alignment.TopStart)
Button(this.vm.btnText)
.width('80%')
.borderRadius(10)
.margin({bottom:px2vp(Number(AppStorage.get('safeAreaTopHeight'))) + ''})
.onClick(() => {
if(this.vm.btnText === '打开'){
this.vm.btnText = '关闭';
}else if(this.vm.btnText === '关闭'){
this.vm.btnText = '打开';
}
this.webviewController.runJavaScript('change()');
})
}
.height('100%')
.backgroundColor('#F5F5F5')
}
}
}
Web组件使用问题
鸿蒙的Web组件加载H5页面会出现很多意外的问题,我这里建议把Web组件的以下两个选项开启,避免问题的产生。
- domStorageAccess(true)开启文档对象模型存储接口(DOM Storage API)权限
- javaScriptAccess(true)允许执行JavaScript脚本
具体代码如下:
// xxx.ets
import web_webview from '@ohos.web.webview';
class WebViewModel {
constructor() {
}
test(): string {
return 'ArkTS Hello World!';
}
}
@Entry
@Component
struct WebComponent {
webviewController: web_webview.WebviewController = new web_webview.WebviewController();
// 声明需要注册的对象
@State vm: WebViewModel = new WebViewModel();
build() {
Column() {
// web组件加载本地index.html页面
Web({ src: $rawfile('index.html'), controller: this.webviewController})
.domStorageAccess(true)
.javaScriptAccess(true)
// 将对象注入到web端
.javaScriptProxy({
object: this.vm,
name: "harmony",
methodList: ["test"],
controller: this.webviewController
})
}
}
}
其他选项可参考 鸿蒙Web官网