CH6- JS UI前端开发

2023-11-02

前言

  • 随着移动端开发技术的不断发展,传统的复杂代码开发(Java、C)方式已经无法满足现今的快速代码开发和迭代的需求,而JavaScript做为一种轻量级解释型即时编译型的编程语言在移动应用开发中得到了开发者的青睐,其在微信小程序开发uni-App开发中得到了较多使用。不同与小程序,HarmonyOs Js框架拥有独特的代码优化模式,JS代码可以在HarmonyOs系统中快速运行。

目标

  • 掌握利用JS UI开发HarmonyOS前端界面的方法,包括开发复杂页面布局,掌握常用组件容器组件自定义组件的用法,学会使用JS FA访问PA的方法

1.JS前端开发基础

  • JS UI框架是一种跨设备的高性能UI开发框架,支持声明式编程跨设备多态UI。需要掌握以下基础知识:
    • HTML5
    • CSS
    • JavaScript

基础能力

  • 声明式编程JS UI框架采用类HTML和CSS声明式编程语言作为页面布局页面样式的开发语言,页面业务逻辑则支持ECMAScript规范的JavaScript语言。JS UI框架提供的声明式编程,可以让开发者避免编写UI状态切换的代码,视图配置信息更加直观。
  • 跨设备开发框架架构上支持UI跨设备显示能力,运行时自动映射到不同设备类型,开发者无感知,降低开发者多设备适配成本
  • 高性能开发框架包含了许多核心的控件,如列表图片各类容器组件等,针对声明式语法进行了渲染流程的优化。

整体架构

20220118120123

  • JS uI框架包括应用层(Application )前端框架层(Framework )引擎层(Engine )平台适配层(Porting Layer) 。
  • Application应用层表示开发者使用JS UI框架开发的FA应用,这里的FA应用特指JS FA应用
  • Framework前端框架层主要完成前端页面解析,以及提供MVVM ( Model-View-ViewModel)开发模式页面路由机制自定义组件等能力。

引擎层&适配层

  • Engine引擎层主要提供动画解析DOM ( Documen Object Model)树构建布局计算、渲染命令构建与绘制、事件管理等能力。
  • Porting Layer适配层主要完成对平台层进行抽象,提供抽象接口,可以对接到系统平台。比如:事件对接、渲染管线对接和系统生命周期对接等。

JS FA的使用

AceAbility

AceAbility类是JS FA在HarmonyOS上运行环境的基类,继承自Ability。开发者的应用运行入口类应该从该类派生。

public class MainAbility extends AceAbility {
    @Override
    public void onStart(Intent intent){
    	super.onStart(intent);
    }
    @Override
    public void onStop() {
    	super.onStop();
    }
}

如何加载JS FA

  • JS FA生命周期事件分为应用生命周期页面生命周期,应用通过AceAbility类中setInstanceName()接口设置该Ability的实例资源,并通过AceAbility窗口进行显示以及全局应用生命周期管理。
  • setIlnstanceName(String name)的参数"name"指实例名称实例名称与config.json文件中module.js.name的值对应。
  • 若开发者未修改实例名,而使用了缺省值default,则无需调用此接口。若开发者修改了实例名,则需在应用Ability实例的onStart()中调用此接口,并将参数"name"设置为修改后的实例名称。

生命周期

20220118120742

加载主页面

  • setInstanceName()接口使用方法:在MainAbility的onStart()中的super.onStart()前调用此接口.
public class MainAbility extends AceAbility {
    @Override
    public void onStart(Intent intent){
        setInstanceName("ISComponentName"); // config.json配置文件中module.js.name的标签值。
        super.onStart(intent);
}

JS FA开发目录

  • 在工程目录中: common文件夹主要存放公共资源,如图片、视频等
  • i18n下存放多语言的json文件
  • pages文件夹下存放多个页面,每个页面由.hml、.css和.js文件组成。

20220118120910

限定词文件

  • main > js > default > i18n > en-US.json:
  • 此文件定义了在英文模式页面显示的变量内容。同理,zh-CN.json中定义了中文模式下的页面内容。
{
    "strings": {
        "hello": "Hello",
        "world": "World"
    },
    "files": {}
}

页面结构.hml文件

  • main > is > default > pages > index > index.hml:
  • 此文件定义了index页面的结构、index页面中用到的组件,以及这些组件的层级关系。例如: index.hml文件中包含了一个text组件,内容为“Hello World”文本。
<div class ="container">
    <text class ="title">
		{{ $t('strings.hello') }{ftitle}}
    </text>
</div>

页面样式.css文件

  • main > js > default > pages > index > index.css:
  • 此文件定义了index页面的样式。例如:index.css文件定义了“container”和“title”的样式
.container {
    flex-direction: column;
    justify-content: center;
    align-items: center;
}
.title {
    font-size: 100px;
}

页面交互.js文件

  • main > js > default > pages > index > index.js:
  • 此文件定义了index页面的业务逻辑,比如数据绑定、事件处理等。例如:变量“title”赋值为字符串“world”
export default {
    data: {
        title: ",
    },
    onlnit() {
    	this.title = this.$t('strings.world');
    },
}

2.—个典型JS FA应用开发

构建页面结构

20220118121405

  • 首先在index.hml文件中构建页面结构。在进行代码开发之前,首先要对页面结构进行分析,将页面分解为不同的部分,用容器组件来承载
  • 根据JSFA应用效果图,此页面一共分成三个部分:标题区展示区详情区根据此分区,可以确定根节点的子节点应按列排

20220118121500

结构分析

  • 标题区是由两个按列排列的text组件实现。
  • 展示区和详情区由按行排列的swiper组件和div组件组成,如下图所示:
    • 第一部分是展示区:由一个容器组件swiper,包含了四个image组件构成;
      • 其中四个image组件通过for指令来循环创建
    • 第二部分是详情区∶由一个容器组件div,包含了一个text组件四个画布组件canvas绘制的圆形构成。
      • swiper组件里展示的图片需要放在与pages目录同级的common目录
<!-- index.hml -->
<div class="container">
	<!-- title area 标题区-->
    <div class="title">
        <text class="name"> Food </text>
        <text class="sub-title"> Choose What You Like </text>
    </div>
    
    
    <div class="dispaly-style">
        <!--display area 展示区-->
        <swiper id="swiperImage" class="swiper-style">
            <image src="{i$item}}" class="image-mode" focusable="true" for="{{imageList}}"></image>
        </swiper>
    </div>   

    
    <!-- product details area 详情区-->
    <div class="container">
        <div class="selection-bar-container">
            
            <div class="selection-bar">
                <image src="{{$item}}" class="option-mode" onfocus="swipeTolndex({{$idx}})" onclick="swipeTolndex([{$idx]})" for="{fimageListl}"></image>
            </div>
            
            <div class="description-first-paragraph">
    			<text class="description">{{descriptionFirstParagraph}}</text>
			</div>
            
            <div class="cart">
    			<text class="{{cartStyle}}" onclick="addCart" onfocus="getFocus" onblur="lostFocus" focusable="true">{{cartText}}</text>
            </div> 
            
        </div>
    </div>
</div>

构建页面样式

  • index.css文件中通过media query管控手机TV不同页面样式,页面样式还采用了css伪类的写法当点击时或者焦点移动到image组件上,image组件由半透明变成不透明
.container {
    flex-direction: column;
}
/*tv */
@media screen and (device-type: tv) {
    .title {
        align-items:flex-start;
        flex-direction: column;
        padding-left: 60px;padding-right: 160px;
        margin-top:15px;
    }
	.swiper-style {
        height: 300px;
        width: 350px;
        indicator-color: #4682b4;
        indicator-selected-color:#fOe68c;
        indicator-size: 10px;
        margin-left: 50px;
    }

/* phone */
@media screen and(device-type: phone){
    .title {
        align-items:flex-start;
        flex-direction: column;
        padding-left: 60px;padding-right: 160px;
        padding-top: 20px;
    }
    .option-mode {
        height: 40px;
        width: 40px;
		margin-left: 50px;
        opacity: 0.5;
		border-radius: 20px;
    }
    .cart-text {
		font-size: 20px;
        text-align: center;
        width: 300px;height: 50px;
        background-color: #6495ed;
        color: white; 
    }
	.cart-text-focus {
        font-size: 20px;
        text-align: center;
        width: 300px;
        height: 50px;
        background-color: #4169e1;
        color: white;
    }
    .add-cart-text {
        font-size: 20px;
        text-align: center;
        width: 300px;
        height: 50px;
        background-color: #ffd700;
        color: white;
    }
	.option-mode:focus {	/*伪类,聚焦时透明度变化*/
        opacity: 1;
    }
}

构建页面逻辑

  • 在index.js文件中构建页面逻辑,主要实现的是两个逻辑功能:
    • 当点击时或者焦点移动到不同的缩略图swiper滑动到相应的图片;
    • 焦点移动到购物车区时,“Add To Cart”背景颜色从浅蓝变成深蓝,点击后文字变化为“Cart + 1”,背景颜色由深蓝色变成黄色。添加购物车不可重复操作
export default {
    data: {
        cartText: 'Add To Cart',
        cartStyle: 'cart-text',
        isCartEmpty: true,
        descriptionFirstParagraph:'This is the food page including fresh fruit, meat,snack and etc. You can pickwhatever you like and addit to your Cart. Your orderwill arrive within 48 hours. ',
		imageList:['/common/food_000.JPG',
                   '/common/food_001.JPG',
                   '/common/food_002.JPG',
                   '/common/food_003.JPG'],
    },
    
    swipeTolndex(index){
        this.$element('swiperImage').swipeTo({index: index});
    },
    
    addCart() {
        if (this.isCartEmpty){
            this.cartText = 'Cart + 1';
            this.cartStyle = 'add-cart-text';
        	this.isCartEmpty = false;
        }
    },

    getFocus() {
        if (this.isCartEmpty){
        	this.cartStyle = 'cart-text-focus';
        }
    },
    
    lostFocus(){
        if (this.isCartEmpty){
        	this.cartStyle = 'cart-text';
        }
    },
}

适配设备类型

  • config.json的“deciceType”字段中添加手机TV的设备类型:
{
    "module": {
   		"deviceType": ["phone","tv"],
    }
}

3.构建用户界面

组件介绍

  • 组件(Component)是构建页面的核心,每个组件通过对数据和方法的简单封装,实现独立的可视、可交互功能单元。组件之间相互独立,随取随用,也可以在需求相同的地方重复使用。开发者还可以通过组件间合理的搭配定义满足业务需求的新组件。

组件分类

20220118130246

组件通用特性

组件通用属性

通用属性包含常规属性渲染属性

  • 常规属性指的是组件普遍支持的用来设置组件基本标识外观显示特征的属性

20220118130544

组件通用样式

  • 在前端设计中组件最关键的问题是如何将组件在屏幕中显示出来,就是要定义它的大小位置关系

20220118130733

组件通用事件

  • ``事件绑定在组件上,当组件达到事件触发条件时,会执行JS中对应的事件回调函数,实现页面uI视图和页面JS逻辑层的交互。对HarmonyOS系统来说,事件主要为手势事件按键事件`。
    • 手势事件主要用于智能穿戴等具有触摸屏的设备
    • 按键事件主要用于智慧屏设备

20220118151734

布局说明

  • JS UI框架中手机和智慧屏以720px ( px指逻辑像素,非物理像素)为基准宽度,根据实际屏幕宽度进行缩放,例如当width设为100px时,在宽度为1440物理像素的屏幕上,实际显示的宽度为200物理像素。智能穿戴的基准宽度为454px,换算逻辑同理。

页面元素

  • 一个页面的基本元素包含标题区域文本区域图片区域等,每个基本元素内还可以包含多个子元素,开发者根据需求还可以添加按钮开关进度条等组件。在构建页面布局时,需要对每个基本元素思考以下几个问题:
    • 该元素的尺寸和排列位置;
    • 是否有重叠的元素;
    • 是否需要设置对齐、内间距或者边界;
    • 是否包含子元素及其排列位置;
    • 是否需要容器组件及其类型。

页面分解

  • 页面中的元素分解之后再对每个基本元素按顺序实现,可以减少多层嵌套造成的视觉混乱逻辑混乱,提高代码的可读性,方便对页面做后续的调整。以下图为例进行分解:

20220118151931

定义文档结构

  • 实现标题文本区域最常用的是基础组件text。text组件用于展示文本,可以设置不同的属性和样式,文本内容需要写在标签内容区,在页面中插入标题和文本区域的示例如下:
<!-- xxx.hml -->
<div class="container">
    <text class="title-text">{{headTitle}}</text>
    <text class="paragraph-text">{{paragraphFirst}}</text>
    <text class="paragraph-text">{{paragraphSecond}}</text>
</div>

定义文档样式

/*xxx.cSS*/
.container {
	flex-direction: column;
    margin-top: 20px;
    margin-left: 30px;
}
.title-text {
	color: #1a1a1a;
    font-size: 50px;
    margin-top: 40px;
    margin-bottom: 20px;
}
.paragraph-text {
    color: #000000;
    font-size: 35px;
    line-height: 60px;
}

动态内容和交互

// xxx.js
export default {
    data: {
        headTitle: 'Capture the Beauty in This Moment',
        paragraphFirst: 'Capture the beauty of light during the transition and fusion ofice and water. At the instant of movement and stillness, softness and rigidity,force and beauty, condensing moving moments.',
        paragraphSecond: 'Reflecting the purity of nature, the innovative designupgrades your visual entertainment and ergonomic comfort. Effortlessly capturewhat you see and let it speak for what you feel.',
    },
}

添加图片区域

  • 实现图片区域通常用image组件来实现,使用的方法和text组件类似。
  • 图片资源放在与pages目录同级的common目录下
<!-- xxx.hml -->
<image class="img" src="{{middlelmage}}"></image>
/*xxx.cSS*/
.img {
	margin-top: 30px;
    margin-bottom: 30px;
    height: 385px;
}
// xxx.js
export default {
    data: {
		middlelmage: '/common/ice.png',
    },
}

添加留言区域

  • 留言框的功能为∶用户输入留言后点击完成,留言区域即显示留言内容;用户点击右侧的删除按钮可删除当前留言内容重新输入。
  • 留言区域由div、text、input关联click事件实现。开发者可以使用
    • input组件实现输入留言的部分
    • 使用text组件实现留言显示部分
    • 使用commentText的状态标记此时显示的组件(通过if属性控制)。
    • 包含文本“完成”和“删除”的text组件中关联click事件
    • 更新commentText状态和inputValue的内容。

留言区实现

  • 页面结构
<!-- xxx.hml -->
<div class="container">
    <text class="comment-title">Comment</text>
    <div if="{{commentText}}">
        <input class="comment" value="{{finputValuel}]" onchange="updateValue()"></input>
        <text class="comment-key" onclick="update" focusable="true">Done</text>
    </div>
    <div if="{{commentText}}">
    	<text class="comment-text" focusable="true">{{inputValue}}</text>
        <text class="comment-key" onclick="update" focusable="true">Delete</text>
	</div>
</div>
  • 样式
/*xxx.csS */
.container {
	margin-top: 24px;
	background-color: #ffffff;
}
.comment-title {
    font-size: 40px;
    color: #1a1a1a;
    font-weight: bold;
    margin-top: 40px;
    margin-bottom: 10px;
}
.comment {
    width: 550px;
    height: 100px;
    background-color: lightgrey;
}
.comment-key {
    width: 150px;
    height: 100px;
    margin-left: 20px;
    font-size: 32px;
    color: #1a1a1a;
    font-weight: bold;
}
.comment-key:focus {
    color: #007dff;
}
.comment-text {
    width: 550px;
    height: 100px;
    text-align: left;
    line-height: 35px;
    font-size: 30px;
    color: #O00000;
    border-bottom-color: #bcbcbc;
    border-bottom-width: 0.5px;
}
  • 交互
//xxx.js
export default {
    data: {
        inputValue:"",
        commentText: false,
    },
    update(){
        this.commentText = !this.commentText;
    },	
    updateValue(e){
        this.inputValue = e.text;
    },
}

添加容器

  • 要将页面的基本元素组装在一起,需要使用容器组件。在页面布局中常用到三种容器组件,分别是div、list、tabs、dialog和form。在页面结构相对简单时,可以直接用div作为容器,因为div作为单纯的布局容器,使用起来更为方便,可以支持多种子组件。
list组件
  • 当页面结构较为复杂时,如果使用div循环渲染,容易出现卡顿,因此推荐使用list组件代替div组件实现长列表布局,从而实现更加流畅的列表滚动体验。但是,list组件仅支持list-item作为子组件,因此使用list时需要留意list-item的注意事项。示例如下:
<!-- xxx.hml -->
<list class="list">
    <list-item type="listltem" for="{{textList}}">
        <text class="desc-text">{{$item.value}}</text>
    </list-item>
</list>
/*xxx.cSS*/
.desc-text {
	width: 683.3px;
    font-size: 35.4px;
}
// xxx.js
export default {
    data: {
		textList: [[value: 'JS FA']],
    },
}

实现效果

  • 以上示例的list中只包含一个list-item,list-item中只有一个text组件。在实际应用中可以在list中加入多个list-item,同时list-item下可以包含多个其他子组件

20220118152845

tabs组件
  • 页面经常需要动态加载时,推荐使用tabs组件。tabs组件支持change事件在页签切换后触发。tabs组件仅支持一个tab-bar一个tab-content。具体的使用示例如下:
<!-- xxx.hml -->
<tabs>
    <tab-bar>
    	<text>Home</text>
        <text>Index</text>
        <text>Detail</text>
    </tab-bar>
    
    <tab-content>
    	<image src="{{homeImage}"></image>
        <image src="{{indexImagel}"></image>
        <image src="{{detailImage}}"></image>
    </tab-content>
</tabs>
// xxx.js
export default {
    data: {
		homelmage: '/common/home.png',
        indexlmage: '/common/index.png',
        detaillmage: '/common/detail.png',
    },
}

20220118153101

dialog组件
  • dialog组件是容器组件支持用户自定义弹窗的格式和内容,该容器组件仅支持单子件。也就是说如果需要在dialog中定义复杂元素,则这能将这些负责子组件放在其他容 器如div中。
    • 当弹窗组件显示时,用户点击非dialog区域取消弹窗时会触发cancel事件;
    • 此外dialog组件有两个特定方法,show和close,分别为显示对话框和删除对话框。
<dialog id="simpledialog" class="dialog-main" oncancel="cancelDialog">
    <div class="dialog-div">
        <div class="inner-txt">
            <text class="txt">是否切换到玫瑰介绍?</text>
        </div>
        <div class="inner-btn">
            <button
                type="capsule"
                value="确认"
                onclick="setSchedule"
                class="btn-txt"
            ></button>
            <button
                type="capsule"
                value="取消"
                onclick="cancelSchedule"
                class="btn-txt"
            ></button>
        </div>
    </div>
</dialog>

dialog组件运行效果

change(e) {
    if (e.index == 1)
    this.$element('simpledialog').show()
},
cancelDialog(e) {
    prompt.showToast({message: '离开'})
},
cancelSchedule(e) {
    this.$element('simpledialog').close()
    prompt.showToast({message: '确认取消'})
},

20220123121325

form组件
  • form组件容器提供了一种方便地方式来提交输入信息支持容器内input元素的内容提交 和重置
<form onsubmit="onSubmit" onreset="onReset">
    <label>菊花</label>
    <input type="radio" name="radioGroup" value="ju"></input>
    <label>玫瑰</label>
    <input type="radio" name="radioGroup" value="rose"></input>
    <text>你的评价</text>
    <input type="text" name="user"></input>
    <input type="submit">提交</input>
    <input type="reset">重置</input>
</form>
export default {
    onSubmit(result) {
        console.log(result.value.radioGroup);
        console.log(result.value.user);
    },
    onReset() {
        console.log("reset all value");
    },
};

20220123121912

添加交互

  • 添加交互通过在组件上关联事件实现。本节将介绍如何用div、text、image组件关联 click事件,构建一个如下图所示的点赞按钮。 
  • 点赞按钮通过一个div组件关联click事件实现。div组件包含一个image组件和一个text组件: 
    • image组件用于显示未点赞和点赞的效果。click事件函数会交替更新点赞和未点赞图片的路径。 
    • text组件用于显示点赞数,点赞数会在click事件的函数中同步更新

点赞效果页面结构

  • click事件作为一个函数定义在js文件中,可以更改isPressed的状态,从而更新显示的 image组件。*
    • 如果isPressed为真,则点赞数加1。该函数在.hml文件中对应的div组件上 生效,点赞按钮各子组件的样式设置在.css文件当中。具体的实现示例如下:
<!-- xxx.hml -->
<!-- 点赞按钮 -->
<div>
    <div class="like" onclick="likeClick">
        <image class="like-img" src="{{likeImage}}" focusable="true"></image>
        <text class="like-num" focusable="true">{{total}}</text>
    </div>
</div>

点赞效果样式和交互

/* xxx.css */
.like {
    width: 104px;
    height: 54px;
    border: 2px solid #bcbcbc;
    justify-content: space-between;
    align-items: center;
    margin-left: 72px;
    border-radius: 8px;
}
.like-img {
    width: 33px;
    height: 33px;
    margin-left: 14px;
}
.like-num {
    color: #bcbcbc;
    font-size: 20px;
    margin-right: 17px;
}
// xxx.js
export default {
    data: {
        likeImage: "/common/unLike.png",
        isPressed: false,
        total: 20,
    },
    likeClick() {
        var temp;
        if (!this.isPressed) {
            temp = this.total + 1;
            this.likeImage = "/common/like.png";
        } else {
            temp = this.total - 1;
            this.likeImage = "/common/unLike.png";
        }
        this.total = temp;
        this.isPressed = !this.isPressed;
    },
};

页面路由

  • 很多应用由多个页面组成,比如用户可以从音乐列表页面点击歌曲,跳转到该歌曲的播 放界面。开发者需要通过页面路由·将这些页面串联起来,按需实现跳转。 
  • 页面路由router根据页面的uri来找到目标页面,从而实现跳转。以最基础的两个页面之 间的跳转为例,具体实现步骤如下: 
    • 在“Project”窗口,打开“entry > src > main > js > default”,右键点击 “pages”文件夹, 选择“New > JS Page”,创建一个详情页。
    • 调用router.push()路由到详情页。 
    • 调用router.back()回到首页。

构建页面结构

  • index和detail这两个页面均包含一个text组件和button组件:
    • text组件用来指明当前页面,
    • button组件用来实现两个页面之间的相互跳转。
    • hml文件代码示例如下:
<!-- 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>

<!-- detail.hml -->
<div class="container">
    <text class="title">This is the detail page.</text>
    <button
        type="capsule"
        value="Go back"
        class="button"
        onclick="launch"
    ></button>
</div> 

构建页面样式

  • 构建indexdetail页面的页面样式:
    • text组件和button组件居中显示,两个组件之间间距 为50px。
    • css代码如下(两个页面样式代码一致)
/* index.css */ /* detail.css */
.container {
    flex-direction: column;
    justify-content: center;
    align-items: center;
}
.title {
    font-size: 50px;
    margin-bottom: 50px;
}

实现跳转

  • 为了使button组件launch方法生效,需要在页面的.js文件中实现跳转逻辑
  • ·调用 router.push()接口将uri指定的页面添加到路由栈中,即跳转到uri指定的页面。
  • 在调用 router方法之前,需要导入router模块。代码示例如下:
// index.js
import router from "@system.router";
export default {
    launch() {
        router.push({
            uri: "pages/detail/detail",
        });
    },
};
// detail.js
import router from "@system.router";
export default {
    launch() {
        router.back();
    },
};

焦点逻辑

  • 焦点移动是智慧屏的主要交互方式,焦点逻辑的主要规则是: 
    • 容器组件焦点分发逻辑容器组件在第一次获焦时焦点一般都落在第一个可获焦的子组件上, 再次获焦时焦点落在上一次失去焦点时获焦的子组件上。容器组件一般都有特定的焦点分发逻 辑,以下分别说明常用容器组件的焦点分发逻辑。 
    • div组件通过按键移动获焦时,焦点会移动到在移动方向上与当前获焦组件布局中心距离最近 的可获焦叶子节点上。如图中焦点在上方的横向div的第二个子组件上,当点击down按键时, 焦点要移动到下方的横向div中。这时下方的横向div中的子组件会与当前焦点所在的子组件进 行布局中心距离的计算,其中距离最近的子组件获焦

20220123123631

各种组件的焦点获得

  • list组件包含list-itemlist-item-group,list组件每次获焦时会使第一个可获焦的item获焦。list-item-group为特殊的list-item,且两者都与div的焦点逻辑相同。 
  • stack组件只能由自顶而下的第一个可获焦的子组件获焦。 
  • swiper的每个页面和refresh的页面的焦点逻辑都与div的相同。 
  • tabs组件包含tab-bartab-content,tab-bar中的子组件默认都能获焦,与是否有可获焦的叶子结点无关。tab-bar与tab-content的每个页面都与div的焦点逻辑相同。 
  • dialog的button可获焦,若有多个button,默认初始焦点落在第二个button上。 
  • popup无法获焦

focusable属性使用

  • 通用属性focusable主要用于控制组件能否获焦本身不支持焦点的组件在设置此属性后 可以拥有获取焦点的能力。如text组件本身不能获焦,焦点无法移动到它上面,设置text 的focusable属性为true后,text组件便可以获焦。特别的是,如果在没有使用focusable 属性的情况下,使用了focus,blur或key事件,会默认添加focusable属性为true。 
  • 容器组件是否可获焦依赖于是否拥有可获焦的子组件如果容器组件内没有可以获焦的 子组件,即使设置了focusable为true,依然不能获焦当容器组件focusable属性设置为 false,则它本身和它所包含的所有组件都不可获焦

4.动画

静态动画

  • 静态动画的核心是transform样式,主要可以实现以下三种变换类型一次样式设置只能实现一种类型变换。 
    • translate:沿水平或垂直方向将指定组件移动所需距离; 
    • scale:横向或纵向将指定组件缩小或放大到所需比例; 
    • rotate:将指定组件沿横轴或纵轴或中心点旋转指定的角度
<!-- xxx.hml -->
<div class="container">
    <text class="translate">hello</text>
    <text class="rotate">hello</text>
    <text class="scale">hello</text>
</div>
/* xxx.css */
.container {
    flex-direction: column;
    align-items: center;
}
.translate {
    height: 150px;
    width: 300px;
    font-size: 50px;
    background-color: #008000;
    transform: translate(200px);
}
.rotate {
    height: 150px;
    width: 300px;
    font-size: 50px;
    background-color: #008000;
    transform-origin: 200px 100px;
    transform: rotateX(45deg);
}
.scale {
    height: 150px;
    width: 300px;
    font-size: 50px;
    background-color: #008000;
    transform: scaleX(1.5);
}

20220123124717

连续动画

  • 静态动画只有开始状态结束状态,没有中间状态,如果需要设置中间的过渡状态转换效果,需要使用连续动画实现。 
  • 连续动画的核心是animation样式,它定义了动画的开始状态结束状态以及时间和速度的变化曲线。通过animation样式可以实现的效果有: 
    • animation-name:设置动画执行后应用到组件上的背景颜色透明度宽高变换类型; 
    • animation-delay和animation-duration:分别设置动画执行后元素延迟和持续的时间; 
    • animation-timing-function:描述动画执行的速度曲线,使动画更加平滑; 
    • animation-iteration-count:定义动画播放的次数; 
    • animation-fill-mode:指定动画执行结束后是否恢复初始状态

连续动画页面结构

  • animation样式需要在css文件中先定义keyframe,在keyframe中设置动画的过渡效果, 并通过一个样式类型在hml文件中调用。animation-name的使用示例如下:
<!-- xxx.hml -->
<div class="item-container">
    <text class="header">animation-name</text>
    <div class="item {{colorParam}}">
        <text class="txt">color</text>
    </div>
    <div class="item {{opacityParam}}">
        <text class="txt">opacity</text>
    </div>
    <input
        class="button"
        type="button"
        name=""
        value="show"
        onclick="showAnimation"
    />
</div>

连续动画页面样式

/* xxx.css */
.item-container {
    margin-right: 60px;
    margin-left: 60px;
    flex-direction: column;
}
.header {
    margin-bottom: 20px;
}
.item {
    background-color: #f76160;
}
.txt {
    text-align: center;
    width: 200px;
    height: 100px;
}
.button {
    width: 200px;
    font-size: 30px;
    background-color: #09ba07;
}
.color {
    animation-name: Color;
    animation-duration: 8000ms;
}
.opacity {
    animation-name: Opacity;
    animation-duration: 8000ms;
}
@keyframes Color {
    from {
        background-color: #f76160;
    }
    to {
        background-color: #09ba07;
    }
}
@keyframes Opacity {
    from {
        opacity: 0.9;
    }
    to {
        opacity: 0.1;
    }
}

连续动画交互逻辑

// xxx.js
export default {
    data: {
        colorParam: "",
        opacityParam: "",
    },
    showAnimation: function () {
        this.colorParam = "";
        this.opacityParam = "";
        this.colorParam = "color";
        this.opacityParam = "opacity";
    },
};

20220123125938

5.用户交互

  • 事件主要包括手势事件按键事件
    • 手势事件主要用于智能穿戴等具有触摸屏的设备
    • 按键事件主要用于智慧屏设备

手势事件

  • 手势表示由单个或多个事件识别的语义动作(例如:点击、拖动和长按)。一个完整的 手势也可能由多个事件组成,对应手势的生命周期。JS UI框架支持的手势事件有:  触摸  点击  长按

触摸

  • touchstart:手指触摸动作开始。 
  • touchmove:手指触摸后移动。 
  • touchcancel:手指触摸动作被打断,如来电提醒、弹窗。 
  • touchend:手指触摸动作结束。 
  • 点击-click:用户快速轻敲屏幕。 
  • 长按-longpress:用户在相同位置长时间保持与屏幕接触

触摸事件示例

页面结构

<!-- xxx.hml -->
<div class="container">
    <div class="text-container" onclick="click">
        <text class="text-style">{{onClick}}</text>
    </div>
    <div class="text-container" ontouchstart="touchStart">
        <text class="text-style">{{touchstart}}</text>
    </div>
    <div class="text-container" ontouchmove="touchMove">
        <text class="text-style">{{touchmove}}</text>
    </div>
    <div class="text-container" ontouchend="touchEnd">
        <text class="text-style">{{touchend}}</text>
    </div>
    <div class="text-container" ontouchcancel="touchCancel">
        <text class="text-style">{{touchcancel}}</text>
    </div>
    <div class="text-container" onlongpress="longPress">
        <text class="text-style">{{onLongPress}}</text>
    </div>
</div>

样式

/* xxx.css */
.container {
    flex-direction: column;
    justify-content: center;
    align-items: center;
}
.text-container {
    margin-top: 10px;
    flex-direction: column;
    width: 750px;
    height: 50px;
    background-color: #09ba07;
}
.text-style {
    width: 100%;
    line-height: 50px;
    text-align: center;
    font-size: 24px;
    color: #ffffff;
}

交互逻辑

// xxx.js
export default {
    data: {
        touchstart: "touchstart",
        touchmove: "touchmove",
        touchend: "touchend",
        touchcancel: "touchcancel",
        onClick: "onclick",
        onLongPress: "onlongpress",
    },
    touchCancel: function (event) {
        this.touchcancel = "canceled";
    },
    touchEnd: function (event) {
        this.touchend = "ended";
    },
    touchMove: function (event) {
        this.touchmove = "moved";
    },
    touchStart: function (event) {
        this.touchstart = "touched";
    },
    longPress: function () {
        this.onLongPress = "longpressed";
    },
    click: function () {
        this.onClick = "clicked";
    },
};

按键事件

  • 按键事件是智慧屏上特有的手势事件,当用户操作遥控器按键时触发
    • 用户点击一个遥 控器按键,通常会触发两次key事件:先触发action为0,再触发action为1,即先触发按 下事件,再触发抬起事件
    • action为2的场景比较少见,一般为用户按下按键且不松开, 此时repeatCount将返回次数。每个物理按键对应各自的按键值(keycode)以实现不同 的功能

按键事件示例

按键示例页面结构和样式

<!-- xxx.hml -->
<div class="card-box">
    <div class="content-box">
        <text
            class="content-text"
            onkey="keyUp"
            onfocus="focusUp"
            onblur="blurUp"
            >{{up}}</text
        >
    </div>
    <div class="content-box">
        <text
            class="content-text"
            onkey="keyDown"
            onfocus="focusDown"
            onblur="blurDown"
            >{{down}}</text
        >
    </div>
</div>

/* xxx.css */
.card-box {
    flex-direction: column;
    justify-content: center;
}
.content-box {
    align-items: center;
    height: 200px;
    flex-direction: column;
    margin-left: 200px;
    margin-right: 200px;
}
.content-text {
    font-size: 40px;
    text-align: center;
}

按键事件处理

  • 按键事件通过获焦事件向下分发,因此示例中使用了focus事件blur事件明确当前焦点 的位置。
  • 点按上下键选中up或down按键,即相应的focused状态,失去焦点的按键恢复 正常的up或down按键文本。按确认键后该按键变为keyed状态
// xxx.js
export default {
    data: {
        up: 'up',
        down: 'down',
    },
    focusUp: function() {
        this.up = 'up focused';
    },
    blurUp: function() {
        this.up = 'up';
    },
    keyUp: function() {
        this.up = 'up keyed';
    },
    focusDown: function() {
        this.down = 'down focused';
    },
    blurDown: function() {
        this.down = 'down';
    },
    keyDown: function() {
        this.down = 'down keyed';
    },
}

多模输入

  • 多模输入使HarmonyOS的UI控件能够响应多种输入事件,事件来源于用户的按键、点击、 触屏、语音等。提供创建事件能力和获取输入设备信息能力。 
  • 多模输入的接口设计是基于多模事件基类(MultimodalEvent),派生出操作事件(ManipulationEvent)、按键事件类(KeyEvent)、语音事件(SpeechEvent)等,另 外提供创建事件类获取输入设备信息类

20220123131232

处理按钮事件

  • 参考HarmonyOS的Component的API创建KeyEventListener; 
  • 重写实现KeyEventListener类中的onKeyEvent(Component component, KeyEvent event) 方法; 
  • 开发者根据自身需求处理按键被按下以及 KEY_DPAD_CENTER、KEY_DPAD_LEFT等按键 被按下后的具体实现。
private Component.KeyEventListener onKeyEvent = new Component.KeyEventListener() 
{
    @Override
    public boolean onKeyEvent(Component component, KeyEvent keyEvent) {
        if (keyEvent.isKeyDown()) {}
    }
}

6.自定义组件

  • JS UI框架支持自定义组件,用户可根据业务需求将已有的组件进行扩展,增加自定义的 私有属性事件,封装成新的组件,方便在工程中多次调用,提高页面布局代码的可读 性。具体的封装方法示例如下

构建

子组件页面结构和样式

<!-- comp.hml -->
<div class="item"> 
    <text class="title-style">{{title}}</text>
    <text class="text-style" 
          onclick="childClicked" focusable="true">
        点击这里查看隐藏文本</text>
    <text class="text-style" 
          if="{{showObj}}">hello world</text>
</div>
/* comp.css */
.item { 
    width: 700px; 
    flex-direction: column; 
    height: 300px; 
    align-items: center; 
    margin-top: 100px; 
}
.text-style {
    width: 100%;
    text-align: center;
    font-weight: 500;
    font-family: Courier;
    font-size: 36px;
}
.title-style {
    font-weight: 500;
    font-family: Courier;
    font-size: 50px;
    color: #483d8b;
}
// comp.js
export default {
    props: {
        title: {
            default: 'title',
        },
        showObject: {},
    },
    data() { 
        return {
            showObj: this.showObject,
        };}, 
    childClicked () { 
        this.$emit('eventType1', {text: '收到子组件参数'});
        this.showObj = !this.showObj; 
    }, 
}

引用

父组件代码

<!-- xxx.hml -->
<element name='comp' 
         src='../../common/component/comp.hml'></element> 
<div class="container"> 
    <text>父组件:{{text}}</text>
    <comp title="自定义组件" show-object="{{isShow}}" 
          @event-type1="textClicked"></comp>
</div>
/* xxx.css */
.container { 
    background-color: #f8f8ff; 
    flex: 1; 
    flex-direction: column; 
    align-content: center;
} 
// xxx.js
export default { 
    data: {
        text: '开始',
        isShow: false,
    },
    textClicked (e) {
        this.text = e.detail.text;
    },
}

运行结果

  • 本示例中父组件通过添加自定义属性向子组件传递了名称为title的参数
    • 子组件在props 中接收,同时子组件也通过事件绑定向上传递了参数text
    • 接收时通过e.detail获取,要 绑定子组件事件,父组件事件命名必须遵循事件绑定规则。自定义组件效果如下图所示:

20220123133257

7.JS FA调用PA

  • FA调用PA接口 
  • FA调用PA常见问题 
  • 示例参考

两种PA调用方式

  • JS UI框架提供了JS FA(Feature Ability)调用Java PA(Particle Ability)的机制,该机 制提供了一种通道来传递方法调用数据返回以及订阅事件上报。 
  • 当前提供AbilityInternal Ability两种调用方式,开发者可以根据业务场景选择合适的调用方式进行开发。 
    • Ability:拥有独立的Ability生命周期,FA使用远端进程通信拉起并请求PA服务,适用于基本服务供多FA调用或者服务在后台独立运行的场景; 
    • Internal Ability:与FA共进程,采用内部函数调用的方式和FA进行通信适用于对服务响应时延要求较高的场景。该方式下PA不支持其他FA访问调用

交互流程

  • JS端与Java端通过bundleNameabilityName来进行关联。在系统收到JS调用请求后, 根据开发者在JS接口中设置的参数来选择对应的处理方式。开发者在onRemoteRequest() 中实现PA提供的业务逻辑

FA调用PA接口

FA端提供以下三个JS接口: 

  • FeatureAbility.callAbility(OBJECT):调用PA能力; 
  • FeatureAbility.subscribeAbilityEvent(OBJECT, Function):订阅PA能力; 
  • FeatureAbility.unsubscribeAbilityEvent(OBJECT):取消订阅PA能力。

两类接口

PA端提供以下两类接口

  • IRemoteObject.onRemoteRequest(int, MessageParcel, MessageParcel, MessageOption):
  • Ability调用方式,FA使用远端进程通信拉起并请求PA服务; 
  • AceInternalAbility.AceInternalAbilityHandler.onRemoteRequest(int, MessageParcel, MessageParcel, MessageOption):
    • Internal Ability调用方式,采用内部函数调用的方式 和FA进行通信

FA调用PA常见问题

  • callAbility返回报错:"Internal ability not register."返回该错误说明JS接口调用请求未在系统中找到对应的InternalAbilityHandler进行处理,因此需要检查以下几点是否正确执行: 
    • 在AceAbility继承类中对AceInternalAbility继承类执行了register方法; 
    • JS侧填写的bundleName和abilityName与AceInternalAbility继承类构造函数中填写的名 称保持相同大小写敏感; 
    • 检查JS端填写的abilityType(0:Ability; 1:Internal Ability),确保没有将abilityType 缺省或误填写为Ability方式

Ability和Internal Ability的区别

  • Ability和Internal Ability是两种不同的FA调用PA的方式。下表列举了在开发时各方面的 差异,避免开发时将两者混淆使用

20220123133423

同步参数

  • FeatureAbility.callAbility中syncOption参数说明: 
    • 对于JS FA侧,·返回的结果都是Promise对象,因此无论该参数取何值,都采用异步方式等待PA 侧响应
    • 对于JAVA PA侧,在Internal Ability方式下收到FA的请求后,根据该参数的取值来选择:通过 同步的方式获取结果后返回;或者异步执行PA逻辑,获取结果后使用 remoteObject.sendRequest的方式将结果返回FA。 
  • 使用await方式调用时IDE编译报错,需引入babel-runtime/regenerator

示例:

JS端

JS端调用FeatureAbility接口,传入两个Number参数,Java端接收后返回两个数的和。

var actionData = {};
actionData.firstNum = 1234;
actionData.secondNum = 2048;
var action = {};
action.bundleName = 'com.huawei.hiaceservice';
action.abilityName = 'com.huawei.hiaceservice.ComputeServiceAbility';
action.messageCode = ACTION_MESSAGE_CODE_PLUS;
action.data = actionData;
action.abilityType = ABILITY_TYPE_EXTERNAL;
action.syncOption = ACTION_SYNC;
var result = await FeatureAbility.callAbility(action);
var ret = JSON.parse(result);
if (ret.code == 0) {
    console.info('plus result is:' + JSON.stringify(ret.abilityResult)); 
}

20220123133528

PA端(Ability方式)

public class ComputeServiceAbility extends Ability {
    private static final String TAG = "ComputeServiceAbility";
    private MyRemote remote = new MyRemote();
    // FA在请求PA服务时会调用AbilityconnectAbility连接PA,连接成功后,需要在onConnect返回一个remote对象,
    供FA向PA发送消息
        @Override
        protected IRemoteObject onConnect(Intent intent) {
        super.onConnect(intent);
        return remote.asObject();
    }
    class MyRemote extends RemoteObject implements IRemoteBroker { 
        @Override
        public boolean onRemoteRequest(int code, MessageParcel data, MessageParcel reply, MessageOption option) {
            @Override
            public IRemoteObject asObject() {
                return this;
            }
        }
    }
}

本章总结

  • 本章主要介绍基于JS UI框架的前端界面开发。JS UI框架的构成 和JS项目的生命周期;
  • 接着对JS UI框架中的核心概念-组件进行了详细描述,包 括组件的通用特性,样式和交互,核心组件容器等;
  • 在深入理解组件功能的基 础上,进行了进阶内容如自定义组件和JS FA调用PA等探讨

Number参数,Java端接收后返回两个数的和。

var actionData = {};
actionData.firstNum = 1234;
actionData.secondNum = 2048;
var action = {};
action.bundleName = 'com.huawei.hiaceservice';
action.abilityName = 'com.huawei.hiaceservice.ComputeServiceAbility';
action.messageCode = ACTION_MESSAGE_CODE_PLUS;
action.data = actionData;
action.abilityType = ABILITY_TYPE_EXTERNAL;
action.syncOption = ACTION_SYNC;
var result = await FeatureAbility.callAbility(action);
var ret = JSON.parse(result);
if (ret.code == 0) {
    console.info('plus result is:' + JSON.stringify(ret.abilityResult)); 
}

[外链图片转存中…(img-xfpZfeWQ-1642927376083)]

PA端(Ability方式)

public class ComputeServiceAbility extends Ability {
    private static final String TAG = "ComputeServiceAbility";
    private MyRemote remote = new MyRemote();
    // FA在请求PA服务时会调用AbilityconnectAbility连接PA,连接成功后,需要在onConnect返回一个remote对象,
    供FA向PA发送消息
        @Override
        protected IRemoteObject onConnect(Intent intent) {
        super.onConnect(intent);
        return remote.asObject();
    }
    class MyRemote extends RemoteObject implements IRemoteBroker { 
        @Override
        public boolean onRemoteRequest(int code, MessageParcel data, MessageParcel reply, MessageOption option) {
            @Override
            public IRemoteObject asObject() {
                return this;
            }
        }
    }
}

本章总结

  • 本章主要介绍基于JS UI框架的前端界面开发。JS UI框架的构成 和JS项目的生命周期;
  • 接着对JS UI框架中的核心概念-组件进行了详细描述,包 括组件的通用特性,样式和交互,核心组件容器等;
  • 在深入理解组件功能的基 础上,进行了进阶内容如自定义组件和JS FA调用PA等探讨
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

CH6- JS UI前端开发 的相关文章

  • 无法在地图循环中访问 Axios 调用的值

    我有一个 javascript 对象 其 ID 对应于一组画廊 我使用地图循环遍历它 在每个循环中 我都会进行 axios 调用来获取当前 id 的图库 最后 我需要一个包含所有画廊内容的数组 问题是地图循环完成后我无法访问数据 当我 co
  • 在 javascript 原型事件处理程序中保留“this”引用[重复]

    这个问题在这里已经有答案了 正确的保存方法是什么this存储在对象原型内的事件处理程序中的 javascript 引用 我不想创建像 this 或 that 这样的临时变量 而且我不能使用像 jQuery 这样的框架 我看到很多人谈论使用
  • 为什么 useReducer 调度会导致重新渲染?

    假设我实现一个简单的全局加载状态 如下所示 hooks useLoading js import React createContext useContext useReducer from react const Context crea
  • Brunch 源映射:在 Chrome 开发工具中未命中断点

    我正在使用 Brunch 中内置的默认源映射 我看到文件很好 但无法在源映射文件中命中断点 使用 Javascript 访问调试器debugger 有效 这让我相信早午餐方面出了问题 这是我的 brunch config js module
  • Mozilla WebExtension API 存储 - 使用和不使用断点进行调试会导致不同的输出

    大家好 我正在尝试为 Mozilla Firefox 浏览器实现一个附加组件 以下脚本显示了我已经成功集成的一个后台脚本 它使用 Mozilla WebExtension API 存储 它被执行了 但浏览器控制台上的日志让我感到惊讶 我交替
  • 绑定 popstate 事件不起作用

    我尝试在浏览器的控制台中输入以下代码 window onpopstate function alert 1 然后单击后退按钮 没有显示任何警报 难道我做错了什么 或者是否不允许将 popstate 事件绑定到控制台的页面 使用 Chrome
  • 鼠标移动时画布拖动

    我正在尝试构建一个可以使用鼠标移动拖动的画布 我做了一些我无法理解的错误 因为一开始似乎有效 然后出现了一个增量错误 使画布移动得太快 考虑以下代码 window onload function var canvas document ge
  • 解释一下这个令人困惑的 dojo 教程声明语法

    我正在阅读使用的语法道场的声明 http dojotoolkit org documentation tutorials 1 8 declare 用于班级创建 描述很混乱 The declare function is defined in
  • 如何使用 Nextjs/React 将 JSON 对象导出到 Excel?

    我有一个检索 json 对象的端点 如下所示 data id 1 temaIndicador Indian codigo 001 observaciones Interactions Specialist tertiary Regional
  • 插件 gulp-babel 错误:插件/预设文件不允许导出对象,只能导出函数

    我现在尝试在我的 Ionic v1 应用程序中使用 JavaScript 2015 ES6 包 json name test version 1 0 0 dependencies ionic native deeplinks 4 18 0
  • 替换img路径jquery

    我正在尝试替换 jquery 中的 img 路径 注入远程页面 replaceexample com thumbs withexample com images 我已经尝试过这个 但似乎不起作用 img attr src replace t
  • 等待异步 grunt 任务完成

    我收到了 grunt 设置 其中一个新任务应该执行 grunt task run 已经存在的任务 要执行的任务是异步的 新任务应该等待异步任务完成 执行此操作的首选方法是什么 grunt 已经涵盖了这一点 你应该将你的任务声明为异步任务 并
  • 如何在数据表角度中基于 JSON 动态填充表值?

    我在用着Angular 数据表 https l lin github io angular datatables 我需要能够根据返回的数据动态创建表 换句话说 我不想指定列标题 Example json数据 id 2 city Baltim
  • 为什么 TypeScript 混合了模块和原型模式?

    我正在查看此页面上 TypeScript 生成的 JS 代码 http www typescriptlang org Playground http www typescriptlang org Playground 基本上 要创建一个Gr
  • chrome 选项卡/窗口中的 window.open 行为

    我有一小段 javascript 旨在打开两个或更多选项卡 这在 FF 和 IE 中工作正常 但 chrome 会在新窗口而不是选项卡中打开第二个窗口 它不依赖于 url 因为我已经尝试过使用两个相同的 url 第一个在选项卡中打开 第二个
  • 获取类中的所有静态 getter

    假设我有这个类 我像枚举一样使用它 class Color static get Red return 0 static get Black return 1 有没有类似的东西Object keys to get Red Black 我使用
  • 有序 JSON 对象

    我有一个 servlet 它与数据库通信 然后返回有序 按时间排序 对象的列表 在servlet部分 我有 access DB returns a list of User objects ordered ArrayList users M
  • HTML5 地理定位 - 在 iOS 上无法始终工作

    目前正在使用 HTML5 地理定位 我已经在所有网络浏览器上测试了它 它似乎工作正常 然而 当我在 iPad 上测试地理定位时 它在 iPad mini 上始终有效 但当我将其放在更大的 iPad iPad 2 上时 位置似乎并不总是有效
  • 突出显示单词并提取其附近文本的函数

    我有一个文本例如 Etiam porta semmalesuada magna mollis euismod 整数取数 ante venenatis dapibus posuere velit aliquet 埃蒂亚姆 门塔 塞姆 male
  • 拉斐尔路径交叉点不起作用

    我对拉斐尔和 pathIntersection method JSFiddle 示例 http jsfiddle net t6gWt 2 您可以看到有两条线都与曲线相交 但当我使用 pathIntersection method 有一个未解

随机推荐

  • 面试题:【数据库二】mysql:explain解释器type关键字

    mysql的explain解释器的相关资源网上很多 这里我只记录一下我关心的Type列 type type字段的意思 当前sql扫描表的方法 type字段对应的value值 system gt const gt eq ref gt ref
  • Table master训练测试流程

    一 环境配置 参考 https github com JiaquanYe TableMASTER mmocr 由于依赖mmdetection 对版本的要求如下 Python 3 6 PyTorch 1 3 CUDA 9 2 GCC 5 在服
  • JavaScript 颜色转为十六进制

    const rgbToHex r g b gt 1 lt lt 24 r lt lt 16 g lt lt 8 b toString 16 slice 1 rgbToHex 60 115 255 运行结果
  • MobaXterm 突破14个session限制

    通常情况下 随着工作时间的增长 我们会保存许许多多的linux到本地的mobastream 然后当超过14个 就会被被限制 这个会让人很头疼 1 安装python 配置好环境变量 测试安装成功 2 基于项目进行解除限制 git clone
  • ListControl中判定双击哪一行哪一列

    NM DBLCLK消息 void CDBResultDlg OnNMDblclkListDb NMHDR pNMHDR LRESULT pResult int nRet 0 LVHITTESTINFO HitTestInfo LPNMITE
  • 代码审查(Code Review)

    1 代码审查概述 1 1 什么是代码审查 对计算机源代码系统化地审查 常用软件同行评审的方式进行 其目的是在找出及修正在软件开发初期未发现的错误 提升软件质量及开发者的技术 1 2 为什么要做代码审查 可以帮助提高代码质量 代码审查的初衷是
  • Geoscience knowledge graph in the big data era

    Geoscience knowledge graph in the big data era 记录我的学习心得 如有不妥 联系删除 Information 作者包括Chenghu ZHOU Hua WANG Chengshan WANG等人
  • 收到大量垃圾短信怎么办?如何屏蔽垃圾短信?

    手机要是突然收到大量垃圾短信 先不要急 原因可能是短信接口被刷 有人用大量短信轰炸来掩盖消费通知 什么意思呢 就是我们手机上各种购物APP或者第三方支付平台等会绑定银行卡 一些诈骗平台会通过大量短信轰炸来掩盖消费通知 就是银行卡被刷了 但是
  • vscoode中使用vue报错

    前言 为什么写了这篇笔记 因为今天我们学习了vue脚手架的知识 我最开始使用的是hb的命令控制台 他可以使用 我心血来潮 其实是因为vscode的美化太好了 想使用vscode打开vue的脚手架 所以我满怀期待的打开了vscode 1 报错
  • Hadoop总结之HDFS-Client端向HDFS中读写数据的流程

    一 Client向HDFS中存入数据 1 客户端通过Distributed FileSystem模块向NameNode请求上传文件 NameNode检查目标文件是否已存在 父目录是否存在 2 NameNode返回是否可以上传 不能上传会返回
  • 用Java编写,要求输出1~100内的素数。

    public class SuShu public static void main String args for int i 2 i lt 100 i boolean isSuShu true for int j 2 j
  • 接口(interface)和抽象类(abstract)的特点和区别

    接口 interface 和抽象类 abstract 的共同点和区别 进入这个话题之前我们先思考一下以下几个问题 1 我们为什要使用抽象类和接口 2 使用抽象类和接口有什么好处 3 我们在设计复杂程序时该怎么合理使用抽象类和接口 抽象类的特
  • huggingface tokenizers

    专注 NLP 的初创团队抱抱脸 hugging face 发布帮助自然语言处理过程中 更快的词语切分 tokenization 工具 Tokenizers 只要 20 秒就能编码 1GB 文本 功能多样 适用于 BPE byte level
  • Bootstrap typeahead使用问题记录及解决方案

    简单介绍 Bootstrap typeahead插件是用来完成输入框的自动完成 模糊搜索和建议提示的功能 支持ajax数据加载 类似于jquery的流行插件Autocomplete typeahead的使用方式有两种 通过数据属性字段的方式
  • 计算机网络 将TCP封装成CTCP类

    首先我们在之前TCP的基础上 进行了优化 解决了粘包问题 这里的解决方式是 在包头给出包的大小 接收端接收到包时 先解析出包的大小 再根据大小分配空间 解决粘包代码 SOCKET sockWaiter my map GetCurrentTh
  • 学生信息管理系统(C语言版+详解+源代码)

    我二二学生信息管理系统 C语言版 详解 源代码 相信受这篇的都是为了期末项目而发愁吧 那么这篇文章最适合你了 我送给大家保姆级的教程 一 相信有部分同学不知道用什么软件运行吧 知道的可以直接看二哦 我用的软件是Devc 给大家发个链接 期末
  • 微信小程序换行 br 无效解决方法

    在微信小程序中 不识别 br 等标签 如果文字中想要折行显示 可以使用 n替代 br 注意 使用 n的时候 一定是在
  • 报错解决:APIConnectionError 调用异常处理 (openAI api)

    1 报错 raise error APIConnectionError openai error APIConnectionError Error communicating with OpenAI HTTPSConnectionPool
  • 26岁曾月薪15K,现已失业3个月,我依然没有拿到offer......

    我做测试5年 一线城市薪水拿到15K 中间还修了一个专升本 这个年限不说资深肯定也是配得上经验丰富的 今年行情不好人尽皆知 但我还是对我的薪水不是很满意 于是打算出去面试 希望可以搏一个高薪 但真到面试环节几个问题就把我问懵了 有没有做过接
  • CH6- JS UI前端开发

    文章目录 前言 目标 1 JS前端开发基础 JS FA的使用 AceAbility 如何加载JS FA JS FA开发目录 2 个典型JS FA应用开发 构建页面结构 构建页面样式 构建页面逻辑 适配设备类型 3 构建用户界面 组件通用特性