#夏日挑战赛# HarmonyOS - 自定义组件之Stepper步进器 原创 精华
作者:张凯
前言
刚刚开始接触HarmonyOS,对于FA项目的开发还比较陌生,简单熟悉了一下ArkUI文档,了解了一些基本语法和自定义组件部分的内容,自己尝试编写一个比较实用的组件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>
2. 禁用
<step num="{{ num }}" disabled="{{ true }}" @change="stepChange"></step>
3. 指定精度
<step num="{{ num }}" precision="{{ 2 }}" @change="stepChange"></step>
4. 指定步长
步长需要搭配对应的精度来使用
<step num="{{ num }}" precision="{{ 2 }}" step="{{ 0.01 }}" @change="stepChange"></step>
5. 指定最大值、最小值
<step num="{{ num }}" min="{{ 20 }}" max="{{ 26 }}" @change="stepChange"></step>
6. 指定标题
<step num="{{ num }}" title="{{ '目标' }}" @change="stepChange"></step>
指定标题后的禁用状态
属性
名称 | 类型 | 必传 | 说明 |
---|---|---|---|
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来获取 |
问题盘点
- 动态绑定样式
class="step-wrapper {{ disabled ? 'step-wrapper-disabled' : 'step-wrapper-not-disabled' }}"
- 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开发技术,欢迎投稿和订阅,让我们一起携手前行共建鸿蒙生态。
非常实用的项目,学习了
强👍
霞姐说,凯哥开大,就是强,6666
666学习学习学习666
学习了,我的云原生文章希望也能回个赞哦