H5快速上手鸿蒙元服务(前端)

一、前言

鸿蒙元服务虽然与h5在很多地方虽然有相似之处,但还是有部分不同的地方,鸿蒙服务开发模式更接近与vue2版本,很多写法与其相似。该篇文章主要用于帮助有h5基础的伙伴能够快速上手鸿蒙元服务,并且对个人在开发过程中遇到的一些坑做个总结。

二、开发相关

项目目录

前端部分主要看js目录下的文件目录即可,除default目录外,其他文件都是与服务卡片相关的。

commom:存放公共配置文件方法等

components:存放公共组件 i18n:i18n相关

media:存放静态文件,图片等

pages:存放页面的目录,包括js,hml,css

utils:存放工具方法,比如网络请求封装等

app.js:全局文件,能够在这个文件中定义全局变量,拥有应用级的生命周期函数

其他关键目录:

supervisual:低代码相关

config.json:项目配置相关,包括路由等

config.json文件

用于给整个项目进行一些关键配置

定义路由

这种定义路由的方式,可能开发过微信小程序的伙伴会比较熟悉,在微信小程序中,一般第一个路径即是项目打开的页面,可惜在鸿蒙元服务中没有这个便捷的功能,designWidth用于定义页面以多宽的设计图来绘制,autoDesginWidth设为true,即是系统根据手机自动设置。

config.json详细配置请看官方文档: developer.harmonyos.com/cn/docs/doc...

HML

HML是一套类HTML的标记语言,通过组件,事件构建出页面的内容。页面具备数据绑定、事件绑定、列表渲染、条件渲染和逻辑控制等高级能力,由鸿蒙内部实现。

js 复制代码
<!-- xxx.hml -->
<div class="container">
    <text class="title">{{count}}</text>
    <div class="box">
        <input type="button" class="btn" value="increase" onclick="increase" />
        <input type="button" class="btn" value="decrease" @click="decrease" />
        <!-- 传递额外参数 -->
        <input type="button" class="btn" value="double" @click="multiply(2)" />
        <input type="button" class="btn" value="decuple" @click="multiply(10)" />
        <input type="button" class="btn" value="square" @click="multiply(count)" />
    </div>
</div>
// xxx.js
export default {
  data: {
    count: 0
  },
  increase() {
    this.count++;
  },
  decrease() {
    this.count--;
  },
  multiply(multiplier) {
    this.count = multiplier * this.count;
  }
};
/* xxx.css */
.container {
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;
    left: 0px;
    top: 0px;
    width: 454px;
    height: 454px;
}
.title {
    font-size: 30px;
    text-align: center;
    width: 200px;
    height: 100px;
}
.box {
    width: 454px;
    height: 200px;
    justify-content: center;
    align-items: center;
    flex-wrap: wrap;
}
.btn {
    width: 200px;
    border-radius: 0;
    margin-top: 10px;
    margin-left: 10px;
}

看这段代码是不是就觉得很亲近了,在hml中通过"{{}}"的形式绑定数据,用@和on的方法来绑定事件,同时支持冒泡、捕获等方式。

列表渲染for

js 复制代码
<!-- xxx.hml -->
<div class="array-container" style="flex-direction: column;margin: 200px;">
  <!-- div列表渲染 -->
  <!-- 默认$item代表数组中的元素, $idx代表数组中的元素索引 -->
  <div for="{{array}}" tid="id" onclick="changeText">
    <text>{{$idx}}.{{$item.name}}</text>
  </div>
  <!-- 自定义元素变量名称 -->
  <div for="{{value in array}}" tid="id" onclick="changeText">    
    <text>{{$idx}}.{{value.name}}</text>
  </div>
  <!-- 自定义元素变量、索引名称 -->
  <div for="{{(index, value) in array}}" tid="id" onclick="changeText">    
    <text>{{index}}.{{value.name}}</text>
  </div>
</div>

tid等于vue中的key,id即为array每一项中的唯一属性,需要注意的是,与vue不同,在鸿蒙元服务中,tid是必须的,如果没有tid可能会引起运行异常的情况。

条件渲染if和show

js 复制代码
<!-- xxx.hml -->
//if
<div class="container">
  <button class="btn" type="capsule" value="toggleShow" onclick="toggleShow"></button>
  <button class="btn" type="capsule" value="toggleDisplay" onclick="toggleDisplay"></button>
  <text if="{{visible}}"> Hello-world1 </text>
  <text elif="{{display}}"> Hello-world2 </text>
  <text else> Hello-World </text>
</div>

//show
<!-- xxx.hml -->
<div class="container">
  <button class="btn" type="capsule" value="toggle" onclick="toggle"></button>
  <text show="{{visible}}" > Hello World </text>
</div>

if和show相当于vue中的v-if和v-show,原理也一样。

自定义组件使用(props和emit传值)

js 复制代码
<!-- template.hml -->
<div class="item"> 
  <text>Name: {{name}}</text>
  <text>Age: {{age}}</text>
  <text class="text-style" onclick="childClicked" id="text" ref="animator">点击这里查看隐藏文本</text>
</div>
<!-- template.js -->
export default {
     props:{
         name,
         age
         contentList
     }
     childClicked () {
     //获取标签对象
        //this.$element("text");
        //this.$element("text").currentOffset().y  获取属性;
        //通过ref的形式来获取
        //this.$refs.animator
        this.$emit('eventType1',{text:'123'});
     },
};
<!-- index.hml -->
//注册
<element name='comp' src='../../common/template.hml'></element>
<div>
//使用
  <comp name="Tony" age="18" content-list="contentList" @event-type1="textClicked"></comp>
</div>
<!-- template.js -->
export default {
     textClicked (e) {
        //e.detail  拿到传过来的数据  e.detail.text
     },
};

注意:组件传递props和emit属性时,强制使用横杆连接的变量名进行传递,接收时,需要使用驼峰名进行接收,通过e.detail拿到emit传过来的参数,通过$element()方法或ref的形式来获取元素对象,其他用法基本和vue2相同。

生命周期和插槽等用法参考官方文档developer.harmonyos.com/cn/docs/doc...

通用事件

developer.harmonyos.com/cn/docs/doc...

内部系统组件

常用的组件包括:

容器组件:dialog、div、滚动组件用于上拉加载(list、list-item、list-item-group)、popup、轮播组件(swiper)

基础组件:image、text、span、input、label

js 复制代码
<div>
    <text>123</text>
</div>

注意:

1.div组件内部不能够直接嵌入文字,需要通过text组件进行包裹

2.list组件在相同方向的滚动不能嵌套使用,否则会造成滚动异常

3.image标签有些图片格式不支持,需要转换为可支持的格式

CSS

华为鸿蒙元服务不支持less,sass等预编译语言,只支持css,相对于h5来说,还做了部分阉割,有些属性在h5能用,在鸿蒙元服务确用不了。

元素标签默认样式

需要注意的是,在元服务中,所有的div标签都是一个flex盒子,所以在我们使用div的时候,如果是纵向布局,那我们需要去手动改变flex-direction: column,更改主轴方向。

js 复制代码
//hml
<div id="tabBarCon">
    <div id="tab1">
    </div>
    <div id="tab2" onclick="handleJumpToCart">
    </div>
    <div id="tab3" onclick="handleJumpToMine">
    </div>
</div>
//css
.tabBarCon{
    flex-direction:column;
}

元素选择器

只支持部分选择器和部分伪类选择器,像h5中的伪元素选择器都是不支持的,也不支持嵌套使用,由于不存在伪元素选择器,所以遇到有时候一些特殊场景时,我们只能在hml中去判断元素索引来添加动态样式。

属性与h5中的差异

属性 鸿蒙元服务 h5
position 只支持absolute、relative、fixed 支持absolute、relative、fixed、sticky
background渐变 linear-gradient(134.27deg, #ff397e 0%, #ff074c 98%),渐变百分比不支持带小数点 支持
长度单位 只支持px、百分比,不支持rem、em、vw、vh px、百分比、rem、em、vw、vh
多行文字省略 text-overflow: ellipsis; max-lines: 1;(只能用于text组件) 单行和多行使用属性不同

JS

特点:

1.支持ES6

2.用法和vue2相似

js 复制代码
// app.js
export default {
  onCreate() {
    console.info('Application onCreate');
  },
  onDestroy() {
    console.info('Application onDestroy');
  },
  globalData: {
    appData: 'appData',
    appVersion: '2.0',
  },
  globalMethod() {
    console.info('This is a global method!');
    this.globalData.appVersion = '3.0';
  }
};
// index.js页面逻辑代码
export default {
  data: {
    appData: 'localData',
    appVersion:'1.0',
  },
  onInit() {
  //获取全局属性
    this.appData = this.$app.$def.globalData.appData;
    this.appVersion = this.$app.$def.globalData.appVersion;
  },
  invokeGlobalMethod() {
    this.$app.$def.globalMethod();
  },
  getAppVersion() {
    this.appVersion = this.$app.$def.globalData.appVersion;
  }
}

data:定义变量

onInit:生命周期函数

getAppVersion:方法,不需要写在methods里面,直接与生命周期函数同级 this. a p p . app. app.def:可以拿到全局对象,

导入导出

支持ESmodule

js 复制代码
//import
import router from '@ohos.router';
//export
export const xxx=123;

应用级生命周期

页面级生命周期

网络请求

使用@ohos.net.http内置模块即可,下面是对网络请求做了一个简单封装,使用的时候直接导入,调用相应请求方法即可,可惜的鸿蒙元服务目前没法进行抓包,所以网络请求调试的时候只能通过打断点的形式进行调试。

js 复制代码
import http from '@ohos.net.http';


import { invokeShowLogin } from '../common/invoke_user';

export default {
    interceptors(response) {
        const result =  JSON.parse(response.result || {});
        const {code,errno} = result
        if (errno === 1024 || code === 1005) {
            return invokeShowLogin();
        }

        return result;
    },

    get(url, data) {
       return http.createHttp().request(
            // 填写http请求的url地址,可以带参数也可以不带参数。URL地址需要开发者自定义。请求的参数可以在extraData中指定
            url,
            {
                method: http.RequestMethod.GET, // 可选,默认为http.RequestMethod.GET
                // 开发者根据自身业务需要添加header字段
                header: {
                    'Content-Type': 'application/json'
                },
                // 当使用POST请求时此字段用于传递内容
                extraData: data,
                connectTimeout: 10*1000,
                readTimeout: 10*1000,
            }
        ).then(res=>{
           return this.interceptors(res);
        });
    },

    post(url, data) {
        return http.createHttp().request(
            // 填写http请求的url地址,可以带参数也可以不带参数。URL地址需要开发者自定义。请求的参数可以在extraData中指定
            url,
            {
                method: http.RequestMethod.POST, // 可选,默认为http.RequestMethod.GET
                // 开发者根据自身业务需要添加header字段
                header: {
                    'Content-Type': ' application/x-www-form-urlencoded'
                },
                // 当使用POST请求时此字段用于传递内容
                extraData: data,
                connectTimeout: 10*1000, // 可选,默认为60s
                readTimeout: 10*1000, // 可选,默认为60s
            }
        ).then(res=>{
            return this.interceptors(res);
        });
    },

    postJson(url, data) {
        return http.createHttp().request(
            // 填写http请求的url地址,可以带参数也可以不带参数。URL地址需要开发者自定义。请求的参数可以在extraData中指定
            url,
            {
                method: http.RequestMethod.POST, // 可选,默认为http.RequestMethod.GET
                // 开发者根据自身业务需要添加header字段
                header: {
                    'Content-Type': 'application/json'
                },
                // 当使用POST请求时此字段用于传递内容
                extraData: data,
                connectTimeout: 10*1000, // 可选,默认为60s
                readTimeout: 10*1000, // 可选,默认为60s
            }
        ).then(res=>{
            return this.interceptors(res);
        })
    }
}

数据存储

只有本地持久化存储这种方式,关闭应用,数据不会丢失。

js 复制代码
storage.set({
    key: 'loginInfo',
    value: JSON.stringify({
        uid, skey
    }),
});
storage.get({
    key: 'userInfo',
    value: JSON.stringify(userInfo),
});

路由跳转

js 复制代码
<!-- index.hml -->
<div class="container">
  <text class="title">This is the index page.</text>
  <button type="capsule" value="Go to the second page" class="button" onclick="launch"></button>
</div>
// index.js
import router from '@ohos.router';
export default {
  launch() {
    router.push ({
      url: 'pages/detail/detail',
      //携带的参数
      params:{a:123}
    });
    //router.back()
    //router.replace()
  },
}.
// detail.js
import router from '@ohos.router';
export default {
  data:{
      a:''
  }
  onInit(){
  //页面携带过来的参数可以直接使用
      //this.a
  }
}

官方文档链接

  1. config.json:developer.harmonyos.com/cn/docs/doc... &developer.harmonyos.com/cn/docs/doc...
  2. http请求:developer.harmonyos.com/cn/docs/doc...
  3. hml:developer.harmonyos.com/cn/docs/doc...
  4. css:developer.harmonyos.com/cn/docs/doc...
  5. js:developer.harmonyos.com/cn/docs/doc...
  6. 生命周期:developer.harmonyos.com/cn/docs/doc...
  7. 目录结构:developer.harmonyos.com/cn/docs/doc...
相关推荐
deli0071 小时前
32K 上下文塞满后,AI 最先忘掉什么?120 轮对话实测
前端
deli0072 小时前
手机拍灯为什么有一条条黑纹?PWM 240Hz 实测
前端
wangruofeng7 小时前
AI Models 1.1.0 发布,查大模型价格、对比模型和找 API 地址
前端·aigc·ai编程
wangruofeng7 小时前
给前端开发者的 100 个设计参考网站
前端·设计
星栈10 小时前
视频即代码,Remotion 能做什么、不能做什么
前端·音视频开发
广州华水科技10 小时前
单北斗GNSS位移监测系统的应用与技术解析
前端
用户479492835691510 小时前
从一句话或代码仓到可交互 HTML:开源 Agent 画图技能 Archify v3.2 实测与选型边界
前端·后端·面试
风骏时光牛马12 小时前
生成一个AI多模态标题,仅输出一条标题,无额外文字、问句、备选、配图、文案等任何附加内容,不需要其他的任务服务 只要标题。
前端
wangruofeng13 小时前
从 GIF 到 AVIF:网页图片格式演进与 2026 年选型指南
前端·架构
Sirius_Ji14 小时前
# 一份鸿蒙原生支持硬解的 ffmpeg 开发基座
harmonyos