#夏日挑战赛# HarmonyOS - 自定义组件之Stepper步进器 原创 精华

发布于 2022-7-11 09:52
浏览
2收藏

作者:张凯

本文正在参加星光计划3.0–夏日挑战赛

前言

刚刚开始接触HarmonyOS,对于FA项目的开发还比较陌生,简单熟悉了一下ArkUI文档,了解了一些基本语法和自定义组件部分的内容,自己尝试编写一个比较实用的组件Stepper 步进器,这个组件在项目中也算常见,这里尽量编写完善一点,努力适用大部分项目。

组件描述

组件支持:步长、最大值、最小值、标题、当前值、精度,功能支持:增大、减小、禁用,在增大减小的同时,按钮高亮。

效果展示

#夏日挑战赛# HarmonyOS - 自定义组件之Stepper步进器-开源基础软件社区

组件代码

step.hml

<div class="step-wrapper {{ disabled ? 'step-wrapper-disabled' : 'step-wrapper-not-disabled' }}">
  <div class="step-minus">
    <div class="icon">
      <div
        class="step-minus-icon {{ num <= min ? 'step-btn-disabled' : 'step-btn-not-disabled' }}"
        disabled="{{ disabled || num <= min }}"
        @click="minusHandle">
      </div>
    </div>
  </div>
  <div class="step-state">
    <div if="{{ ! disabled || ! title }}" class="step-num {{ title ? 'small-top' : 'big-top' }}">
      <text>
        {{ showNum }}
      </text>
    </div>
    <div if="{{ title }}" class="{{ disabled ? 'step-disabled-title' : 'step-title' }}">
      <text>
        <span>{{ title }}</span>
      </text>
    </div>
  </div>
  <div class="step-add">
    <div class="icon">
      <div
        class="step-add-icon {{ num >= max ? 'step-btn-disabled' : 'step-btn-not-disabled' }}"
        disabled="{{ disabled || num >= max }}"
        @click="addHandle">
      </div>
    </div>
  </div>
</div>

step.js

export default {
	props: {
		disabled: {
			default: false
		},
		num: {
			default: 0
		},
		min: Number,
		max: Number,
		title: {
			default: ""
		},
		step: {
			default: 1
		},
		precision: {
			default: 0
		}
	},
	computed: {
		showNum() {
			let num = this.num
			return num.toFixed(this.precision);
		}
	},
	addHandle() {
		this.$emit("change", {
			num: this.num + this.step
		});
	},
	minusHandle() {
		this.$emit("change", {
			num: this.num - this.step
		});
	}
}

step.css

.step-wrapper {
	width: 100%;
	height: 64px;
	margin: 12px;
	border-radius: 16px;
	background-color: #fff;
}

.step-wrapper-disabled {
	opacity: 0.4;
}

.step-wrapper-not-disabled {
	opacity: 1;
}

.step-minus, .step-add, .step-state {
	flex: 1;
}

.step-minus, .step-add {
	justify-content: center;
}

.icon {
	width: 100%;
	margin-top: 21px;
	justify-content: center;
}

.step-minus-icon, .step-add-icon, .step-minus-icon:active, .step-add-icon:active {
	width: 24px;
	height: 24px;
	background-position: center;
	background-repeat: no-repeat;
	background-size: cover;
}

.step-minus-icon {
	background-image: url("/common/images/ic_minus_disabled.png");
}

.step-add-icon {
	background-image: url("/common/images/ic_add_disabled.png");
}


.step-minus-icon:active {
	background-image: url("/common/images/ic_minus_active.png");
}

.step-add-icon:active {
	background-image: url("/common/images/ic_add_active.png");
}


.step-btn-disabled {
	opacity: 0.4;
}

.step-btn-not-disabled {
	opacity: 1;
}

.step-state {
	flex-direction: column;
	align-items: center;
}

.step-num {
	margin-bottom: 2px;
}

.small-top {
	margin-top: 13px;
}

.big-top {
	margin-top: 21px;
}

.step-num > text {
	font-size: 16px;
	height: 21px;
	line-height: 22px;
}

.step-title > text {
	height: 16px;
	font-size: 12px;
	line-height: 16px;
}

.step-num, .step-title {
	width: 100%;
	font-family: HarmonyHeiTi-, HarmonyHeiTi;
	font-weight: normal;
	color: #000000;
	justify-content: center;
}

.step-disabled-title {
	width: 100%;
	margin-top: 21px;
}

.step-disabled-title > text {
	width: 100%;
	text-align: center;
	height: 21px;
	font-size: 16px;
	line-height: 22px;
}

使用示例

1. 基本用法

<step num="{{ num }}" @change="stepChange"></step> 

#夏日挑战赛# HarmonyOS - 自定义组件之Stepper步进器-开源基础软件社区

2. 禁用

<step num="{{ num }}" disabled="{{ true }}" @change="stepChange"></step>

#夏日挑战赛# HarmonyOS - 自定义组件之Stepper步进器-开源基础软件社区

3. 指定精度

<step num="{{ num }}" precision="{{ 2 }}" @change="stepChange"></step>

#夏日挑战赛# HarmonyOS - 自定义组件之Stepper步进器-开源基础软件社区

4. 指定步长

步长需要搭配对应的精度来使用

<step num="{{ num }}" precision="{{ 2 }}" step="{{ 0.01 }}" @change="stepChange"></step>

#夏日挑战赛# HarmonyOS - 自定义组件之Stepper步进器-开源基础软件社区

5. 指定最大值、最小值

<step num="{{ num }}" min="{{ 20 }}" max="{{ 26 }}" @change="stepChange"></step>

#夏日挑战赛# HarmonyOS - 自定义组件之Stepper步进器-开源基础软件社区

6. 指定标题

<step num="{{ num }}" title="{{ '目标' }}" @change="stepChange"></step>

#夏日挑战赛# HarmonyOS - 自定义组件之Stepper步进器-开源基础软件社区

指定标题后的禁用状态

#夏日挑战赛# HarmonyOS - 自定义组件之Stepper步进器-开源基础软件社区

属性

名称 类型 必传 说明
num Number true 组件显示的部分,和父组件进行关联
disabled Boolean false 是否禁用,禁用的样式根据有无title属性进行了区分显示
min Number false 计算的最小值
max Number false 计算的最大值
title String false 是否显示标题
step Number false 指定计算的步长,需要搭配precision使用
precision Number false 指定数值的精度

事件

名称 说明
change 绑定值被改变时触发,通过e.detail来获取

问题盘点

  1. 动态绑定样式
class="step-wrapper {{ disabled ? 'step-wrapper-disabled' : 'step-wrapper-not-disabled' }}"
  1. 0.00在页面中显示为0

​ 这里尝试过num.toString()和num += ""转为字符串,无效,所以使用了toFixed()转为对应精度的字符串。

computed: {
    showNum() {
        let num = this.num
        return num.toFixed(this.precision);
    }
}

相关资料

编写这个组件,简单用到了组件间通信、动态类名等,在这里列出官方API,以便后续查看。

Props

自定义组件可以通过props声明属性,父组件通过设置属性向子组件传递参数,props支持类型包括:String,Number,Boolean,Array,Object。camelCase (驼峰命名法) 的 prop 名,在外部父组件传递参数时需要使用 kebab-case (短横线分隔命名) 形式,即当属性compProp在父组件引用时需要转换为comp-prop。给自定义组件添加props,通过父组件向下传递参数的示例如下:

<!-- comp.hml -->
<div class="item">
	<text class="title-style">{{compProp}}</text>
</div>
// comp.js export default {   props: ['compProp'],}
<!-- xxx.hml -->
<element name='comp' src='../../common/component/comp/comp.hml'></element>
<div class="container">
	<comp comp-prop="{{title}}"></comp>
</div>

说明:自定义属性命名时禁止以on、@、on:、grab: 等保留关键字为开头。

Props添加默认值

子组件可以通过固定值default设置默认值,当父组件没有设置该属性时,将使用其默认值。此情况下props属性必须为对象形式,不能用数组形式,示例如下:

comp.hml

<div class="item">
    <text class="title-style">{{ title }}</text>
</div>
<!-- comp.jsexport default {   props: {    title: {      default: 'title',    },  },} -->

本示例中加入了一个text组件显示标题,标题的内容是一个自定义属性,显示用户设置的标题内容,当用户没有设置时显示默认值title。在引用该组件时添加该属性的设置:

xxx.hml

<element name='comp' src='../../common/component/comp/comp.hml'></element>
<div class="container">
    <comp title="自定义组件"></comp>
</div>

组件通信

1. Props子组件向上传递参数

comp.hml

<div class="item">
	<text class="text-style" onclick="childClicked">点击这里查看隐藏文本</text>
	<text class="text-style" if="{{showObj}}">hello world</text>
</div>

comp.js

export default {
	childClicked () {
    	this.$emit('eventType1', {text: '收到子组件参数'});
        this.showObj = !this.showObj;
    },
}

2. 父组件通过e.detail获取参数:

xxx.hml

<div class="container">
	<text>父组件:{{text}}</text>
    <comp @event-type1="textClicked"></comp>
</div>

xxx.js

export default {
	data: {
    	text: '开始',
    },
    textClicked (e) {
    	this.text = e.detail.text;
  	},
}

总结

在编写组件的过程中,发现一些js方法在FA中并不适用,需要反复的尝试来实现。这个组件还有一些需要完善的地方,希望大家有什么想法和意见可以提出来,后期可以进行补足。

更多原创内容请关注:中软国际 HarmonyOS 技术团队

入门到精通、技巧到案例,系统化分享HarmonyOS开发技术,欢迎投稿和订阅,让我们一起携手前行共建鸿蒙生态。

©著作权归作者所有,如需转载,请注明出处,否则将追究法律责任
11
收藏 2
回复
举报
回复
添加资源
添加资源将有机会获得更多曝光,你也可以直接关联已上传资源 去关联
    相关推荐