ultimate-harmony-reference/OpenHarmony JS Demo开发讲解.md

14 KiB
Raw Permalink Blame History

以下内容基本来源于书籍《鸿蒙操作系统应用开发实践》,有需要的可购买:京东平台当当平台

完整工程请下载:ISRC_OHOS/OpenHarmony-JS-Demos

项目结构

打开entry→src→main→js工程的开发目录如图所示

输入图片说明

其中,

  • i18n文件夹用于存放配置不同语言场景的资源比如应用文本词条图片路径等资源。en-US.json文件定义了在英文模式下页面显示的变量内容zh-CN.json文件定义了中文模式下的页面内容。
  • pages文件夹用于存放多个页面每个页面由hml、css和js文件组成。
    • index.hml文件定义了index页面的布局index页面中用到的组件以及这些组件的层级关系。
    • index.css文件定义了index页面的样式。
    • index.js文件定义了index页面的业务逻辑比如数据绑定、事件处理等。
  • app.js文件进行全局的逻辑文件和应用生命周期管理。
  • resources文件夹用于存放开发资源文件的目录。包括图片、音视频等资源文件。
  • config.json文件应用配置文件。用于声明应用的Ability信息及应用所需的权限等信息。

JS FA

输入图片说明

可将该FA一共分成三个部分图片区、标题区、描述区。根据此分区根节点的子节点应按列排列。 图片区和描述区分别使用 swiper组件和text组件实现。标题区由两个部分组成以行来排列其中第一部分由两个text组件组成分别为商品名称和商品标语以列排列。第二部分由image组件和text组件组成分别为代表收藏功能的星号和代表收藏次数的数字以行排列如图所示。

输入图片说明

首先构建FA基础布局。其中实现图片区域通常用image组件来实现由于需要左右滑动图片因此在image外层加入swiper滑动容器swiper容器提供了切换子组件显示的能力。 标题区和描述区采用了最常用的基础组件texttext组件用于展示文本文本内容需要写在标签内容区。要将页面的基本元素组装在一起需要使用容器组件如上述swiper容器。在页面布局中常用到三种容器组件分别是div、list和tabs。在页面结构相对简单时可以直接用div作为容器因为div作为单纯的布局容器使用起来更为方便可以支持多种子组件。 在index.hml文件中实现基础布局具体代码如下所示

<div class="container">
    <swiper class="swiper-style">
        <image src="/common/Phone_00.jpg" class="image-mode"></image>
        <image src="/common/Phone_01.jpg" class="image-mode"></image>
        <image src="/common/Phone_02.jpg" class="image-mode"></image>
        <image src="/common/Phone_03.jpg" class="image-mode"></image>
    </swiper>
    <div class="title-section">
        <div class="phone-title">
            <text class="phone-name">
                HUAWEI
            </text>
            <text class="phone-definition">
                Thinking Possibilities
            </text>
        </div>
        <div class="favorite-image">
            <image src="{{unFavoriteImage}}" class="image-size"onclick="favorite"></image>
        </div>
        <div class="favorite-count">
            <text>{{number}}
            </text>
        </div>
    </div>
    <div class="description-first-paragraph">
        <text class="description">{{descriptionFirstParagraph}}
        </text>
    </div>
    <div class="description-second-paragraph">
        <text class="description">{{descriptionSecondParagraph}}
        </text>
    </div>
</div>

在index.hml中为每个组件和容器都定义了一个class=“***”的样式,需要在css文件中依次对样式进行构建。如本例在index.css文件中需要设定的样式主要有flex-direction用于设置子组件容器的排列方式paddind用于设置内边距font-size用于设置字体大小以及swiper组件的一些私有属性如indicator-color用于设置导航点指示器的填充颜色indicator-selected-color用于设置导航点指示器选中的颜色indicator-size用于设置导航点指示器的直径大小等。具体代码如下所示

.container {
    flex-direction: column;
}
.swiper-style {
    height: 700px;
    indicator-color: #4682b4;
    indicator-selected-color: #ffffff;
    indicator-size: 20px;
}
.title-section {
    flex-direction: row;
    height: 150px;
}
.phone-title {
    align-items:flex-start;
    flex-direction: column;
    padding-left: 60px;
    padding-right: 160px;
    padding-top: 50px;
}
.phone-name {
    font-size: 50px;
    color: #000000;
}
.phone-definition {
    font-size: 30px;
    color: #7A787D;
}
.favorite-image {
    padding-left: 70px;
    padding-top: 50px;
}
.favorite-count {
    padding-top: 60px;
    padding-left: 10px;
}
.image-size {
    object-fit: contain;
    height: 60px;
    width: 60px;
}
.description-first-paragraph {
    padding-left: 60px;
    padding-top: 50px;
    padding-right: 60px;
}
.description-second-paragraph {
    padding-left: 60px;
    padding-top: 30px;
    padding-right: 60px;
}
.description {
    color: #7A787D;
}
.image-mode {
    object-fit: contain;
}

在index.js用于构建页面逻辑对图片资源进行赋值并通过添加交互实现收藏功能。收藏按钮通过一个div组件关联click事件实现。click事件作为一个函数定义在index.js文件中可以更改isFavorite的状态从而更新显示的image组件和text组件。index.js中代码如下所示

export default {
    data: {
        unFavoriteImage: "/common/unfavorite.png",
        isFavorite: false,
        number: 20,
        descriptionFirstParagraph:"The breakthrough of visual boundaries, the exploration of photography and videography, the liberation of power and speed, and the innovation of interaction are now ready to be discovered. Embrace the future with new possibilities.",
        descriptionSecondParagraph: "Lighting up infinite possibilities. The quad camera of HUAWEI is embraced by the halo ring. It is a perfect fusion of reflection and refraction. Still Mate, but a new icon.",
    },
    favorite() {
        var tempTotal;
        if (!this.isFavorite) {
            this.unFavoriteImage = "/common/favorite.png";
            tempTotal = this.number + 1;
        } else {
            this.unFavoriteImage = "/common/unfavorite.png";
            tempTotal = this.number -1;
        }
        this.number = tempTotal;
        this.isFavorite = !this.isFavorite;
    }
}

常用组件

根据组件的功能,可以将组件分为以下四大类

组件类型 主要组件
基础组件 text、image、progress、rating、span、marquee、image-animator、divider、search、menu、chart
容器组件 div、list、list-item、stack、swiper、tabs、tab-bar、tab-content、popup、list-item-group、refresh、dialog
媒体组件 video
画布组件 canvas

基础组件-Button

Button是实现用户交互最常用的组件可用于触发JS中的函数。可以使用JS提供的各种按钮包括胶囊按钮、圆形按钮、文本按钮、弧形按钮、下载按钮来实现许多有趣的功能。

<!-- index.hml定义多种按钮 -->
<div class="div-button">
    <button class="button" type="capsule" value="胶囊按钮"></button>
    <button class="button circle" type="circle" icon="common/logo.png"></button>
    <button class="button text" type="text">文本按钮</button>
    <button class="button download" type="download" id="download-btn"
            onClick="setProgress">{{downloadText}}</button>
    <button class="button" type="capsule" waiting="true">载入中...</button>
    <button class="button" type="arc">弧形按钮</button>
</div>

上述下载按钮的onClick属性绑定到了js文件中的setProgress函数中js文件的代码如下所示

export default {
    data: {
        progress: 5,
        downloadText: "下载"
    },
    setProgress(e) {
        this.progress += 10;    //每次点击增加10%的进度
        this.downloadText = this.progress + "%";
        if (this.progress >= 100) {
            this.downloadText = "完成";   //到达100%时显示完成
        }
    }
}

实现效果如下:

输入图片说明

List组件

List组件常用于呈现多行连续同类的数据。List列表组件包含两类子组件分别是list-item列表项和list-item-group列表项组。这里详细讲解一下list-item-group列表项组。 list-item-group是一个具有折叠效果list列表配合list-item使用以list-item-group中的第一个list-item作为分类标准以下都折叠进分类中点击具有折叠和扩展的效果。代码如下所示

<!-- index.hml -->
<div class="container">
    <list>
        <list-item-group>
            <list-item class="item_style"><text class="big_size">水果</text></list-item>
            <list-item><text class="font_size">苹果</text></list-item>
            <list-item><text class="font_size">香蕉</text></list-item>
        </list-item-group>
        <list-item-group>
            <list-item class="item_style"><text class="big_size">饮料</text></list-item>
            <list-item><text class="font_size">可乐</text></list-item>
            <list-item><text class="font_size">咖啡</text></list-item>
        </list-item-group>
        <list-item-group>
            <list-item class="item_style"><text class="big_size">零食</text></list-item>
            <list-item><text class="font_size">薯片</text></list-item>
            <list-item><text class="font_size">锅巴</text></list-item>
        </list-item-group>
    </list>
</div>
.item_style {
    background-color: pink;
}
.big_size {
    font-size: 50px;
}

运行上述代码,结果如图所示,实现了一个具有折叠效果的列表

输入图片说明

自定义组件

自定义组件是用户根据业务需求将已有的组件组合起来封装成新的组件并作为新组件可以在工程中被多次调用从而提高代码的可读性和可扩展性。自定义组件通过element引入到宿主页面使用方法的示例代码如下所示

<element name="comp" src="../comp.hml"></element>
<div>
    <comp prop1='xxxx' @child1="bindParentVmMethod"></comp>
</div>
  • name属性指定自定义组件名称非必填若不填组件名称则为hml文件名。src属性指自定义组件hml文件路径为了准确定位到该组件位置src属性内容必须要填写需要注意的是src路径中"../"代表上一级目录索引。
  • prop属性用于组件之间的通信可以通过方式传递给组件名称必须用小写。
  • 事件绑定:自定义组件中绑定子组件事件使用(on或@)child1语法子组件中通过this.$emit('child1', { params: '传递参数' })触发事件并进行传值父组件执行bindParentVmMe- thod方法并接收子组件传递的参数。 下面创建一个自定义组件并在父组件中引入自定义组件的事件响应。首先在page文件夹中新建自定义组件目录comp同时创建自定义组件的基础htm、css和js文件代码如下所示
<div class="item">
    <text class="title_style">{{title}}</text>
    <text class="text-style" onclick="childClicked">点击这里查看隐藏文本</text>
    <text class="text-style" if="{{showword}}">hello world</text>
</div>
.item {
    width: 700px;
    flex-direction: column;
    height: 300px;
    align-items: center;
    margin-top: 100px;
}
.text-style {
    font-weight: 500;
    font-family: Courier;
    font-size: 40px;
}
export default {
    props: {
        title: {
            default: 'title'
        },
    },
    data: {
        showword: false,
    },
    childClicked () {
        this.$emit('eventType1', {text: "收到子组件参数"});
        this.showword = !this.showword;
    },
}

上述代码新创建了一个comp自定义组件组件中设置了一个具有点击属性的文本内容该点击效果会将自定义组件的数据传递给父组件并将show值从初始化的false转为true即显示hello world文本。 在父组件中通过element引入自定义组件代码如下所示

<element name="comp" src="../comp/comp.hml"></element>
<div class="container">
    <text>父组件:{{text}}</text>
    <comp title="自定义组件" @event-type1="textClicked"></comp>
</div>
.container {
    background-color: #f8f8ff;
    flex: 1;
    flex-direction: column;
    align-content: center;
}
export default {
    data: {
        text: "开始"
    },
    textClicked (clicked) {
        this.text = clicked.detail.text;
    },
}

本示例中父组件通过添加自定义属性向子组件传递了名为title的参数自定义子组件在props中接收自定义组件可以通过props声明属性父组件通过设置的属性向子组件传递参数注意在命名prop时需要使用camelCase即驼峰式命名法在外部父组件传递参数时需要使用kebab-case即用短横线分割命名例如在上面示例代码中属性eventType1在父组件引用时需要转换为event-type1。子组件也通过事件绑定向上传递了参数text父组件接收时通过clicked.detail获取数据。

输入图片说明

父子组件之间的数据传输是单向的,一般的只能从父组件传递给子组件,而子组件如果需要向上传递必须绑定事件,通过事件的$emit来传输。子组件获取来自父组件数据后子组件不能直接修改父组件传递下来的值可以通过将props传入的值用data接收后作为默认值然后在对data的值进行修改。 如果需要观察组件中属性的变化,可以通过$watch方法增加属性变化回调。