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. <math xmlns="http://www.w3.org/1998/Math/MathML"> a p p . app. </math>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...
相关推荐
秦jh_1 分钟前
【Linux】多线程(概念,控制)
linux·运维·前端
蜗牛快跑21314 分钟前
面向对象编程 vs 函数式编程
前端·函数式编程·面向对象编程
Dread_lxy15 分钟前
vue 依赖注入(Provide、Inject )和混入(mixins)
前端·javascript·vue.js
涔溪1 小时前
Ecmascript(ES)标准
前端·elasticsearch·ecmascript
榴莲千丞1 小时前
第8章利用CSS制作导航菜单
前端·css
奔跑草-1 小时前
【前端】深入浅出 - TypeScript 的详细讲解
前端·javascript·react.js·typescript
羡与1 小时前
echarts-gl 3D柱状图配置
前端·javascript·echarts
guokanglun1 小时前
CSS样式实现3D效果
前端·css·3d
Swift社区1 小时前
如何构建安全可靠的 HarmonyOS 应用
harmonyos·arkts·arkui
咔咔库奇2 小时前
ES6进阶知识一
前端·ecmascript·es6