文章目录
- [1. 从0做一个键盘组件](#1. 从0做一个键盘组件)
-
- [1.1. 最终效果](#1.1. 最终效果)
- [1.2. 分析](#1.2. 分析)
- [1.3. 实现](#1.3. 实现)
- [1.4. 如何引用](#1.4. 如何引用)
1. 从0做一个键盘组件
首先是why的问题:为什么需要做键盘组件?
我们目前可知的场景:
- 在新增账单的时候,需要用到键盘
- 在比如从账单列表页,进行行项目编辑某笔账单的时候,也需要用到键盘
如果都是每个vue页面自己写键盘的话,就比较尴尬了,回头需要优化的时候,就要多处维护。
所以,我们需要定义一个键盘组件。
1.1. 最终效果
或者是编辑的时候:
1.2. 分析
- 主要是显示:item_name账单类目名称、bill_money账单金额、账单日期选择、提交账单、删除账单
- 如果是新增账单,就不显示"删除账单"按钮;如果是编辑账单,展示"删除账单"按钮。
1.3. 实现
整体的键盘样式都比较简单,可以直接通过布局来绘制。
直接上代码:
vue
<template>
<view class="keyboardbox">
<view style="display: flex; font-size: 50rpx; justify-content: space-between; padding: 20rpx 20rpx;">
<view style="font-size: 40rpx;">{{item_name}}</view>
<view color = '#bbb' >{{bill_money}}</view>
</view>
<u-input
placeholder="备注: 点击填写备注"
:border="true"
v-model="bill_desc"
clearable
></u-input>
<view class="numkeyboard">
<view class="num-area">
<view class="row" v-for="(item,index) in numKeybordList" :key="index">
<view class="item"
v-for="(ite,idx) in item" hover-class="active" :hover-start-time="0"
:hover-stay-time="5" :key="idx" @tap="input(ite)">{{ite}}</view>
</view>
</view>
<view class="btn-area">
<view :class="['item','dateChoose']" hover-class="active" :hover-start-time="0" :hover-stay-time="5"
@tap="dateVal">
<view class="uni-input">{{choosedDateShow}}</view>
</view>
<view :class="['item','del']" hover-class="active" :hover-start-time="0" :hover-stay-time="5"
@tap="deleteVal">
<u-icon name="arrow-leftward"></u-icon>
</view>
<view class="confirem item" hover-class="active" :hover-start-time="0" :hover-stay-time="5"
@tap="submit">
完成
</view>
<view v-if="add_or_update=='编辑账单'" class="deletebill item" hover-class="active" :hover-start-time="0" :hover-stay-time="5"
@tap="deleteBill">
删除账单
</view>
</view>
</view>
</view>
<u-picker mode="time"
:default-time="date_picker_date"
v-model="date_picker_show"
:params="date_picker_params"
@confirm="date_pick_ok"
>
</u-picker>
<!-- <u-modal v-model="showDeleteBillModal" :content="content" negative-top=500></u-modal> -->
</template>
<script setup>
import {
ref, defineProps, defineEmits, watch, defineModel, computed
} from 'vue';
import {onLoad,onUnload,onReachBottom,onShareAppMessage,onShareTimeline} from "@dcloudio/uni-app"
onLoad((e)=>{
});
const add_or_update = defineModel("add_or_update", { type: String, default: '' });
const bill_id = defineModel("bill_id", { type: String, default: '' });
const item_name = defineModel("item_name", { type: String, default: '' });
const bill_money = defineModel("bill_money", { type: String, default: '' });
const bill_desc = defineModel("bill_desc", { type: String, default: '' });
const date_picker_date = defineModel("date_picker_date", {type: String, default: ''})
console.log(add_or_update.value);
console.log(date_picker_date.value);
console.log(bill_id.value);
const numKeybordList = ref([ // 键盘数值
[1, 2, 3],
[4, 5, 6],
[7, 8, 9],
[0, '.']
]);
// 默认不显示时间选择组件。在点击了"今天"之后,可以进行选择其他日期
const date_picker_show = ref(false);
// 选择时间时候的时间选择组件,仅展示年月日
const date_picker_params = ref({
year: true,
month: true,
day: true,
hour: false,
minute: false,
second: false
});
// 监听contentId
// watch(()=>props.item_name,(newValue, oldValue)=>{
// console.log(newValue);
// item_name.value = newValue
// },{ deep: true, immediate:true})
/**
* 按键
* @param {Object}
*/
// const clickInfo = () => {
const input = (val) => {
// input(val) {
let money = bill_money.value;
if (money.length >= 10) {
uni.showToast({
title: '金额过大',
icon: 'error'
})
return;
}
let arr = money.split('.');
if (money == '0.00' && val != null) {
money = val.toString();
} else {
let arr = money.split('.');
if (val == '.' && arr.length > 1) {
} else if (arr.length <= 1 || (arr.length > 1 && arr[1].length <= 1)) {
if (money == '0' && val != '.') {
money = val.toString();
} else if (money != '0' || val != '0')
money += val;
}
}
bill_money.value = money;
};
/**
* 删除
*/
const deleteVal = () => {
// deleteVal() {
let money = bill_money.value;
console.log(money.length);
if (money != '0.00' && money.length > 0)
money = money.substring(0, money.length - 1)
if (money.length <= 0)
money = '0.00';
bill_money.value = money;
};
const date_pick_ok = (callback_data) => {
// date_pick_ok(callback_data) {
date_picker_date.value = callback_data.year + '-' + callback_data.month + '-' + callback_data.day;
console.log('选择了:' + date_picker_date.value);
};
const dateVal = () => {
date_picker_show.value = true;
};
const emit = defineEmits(['submit', 'deleteBill']);
const submit = () => {
emit(
'submit',
{
bill_money: bill_money.value,
bill_desc: bill_desc.value,
date_picker_date: date_picker_date.value
},
(res)=>{
//回调函数的方法体.处理自己的业务.
console.log("获取到父组件执行结果的回调");
console.log(res);
}
);
};
const deleteBill = () => {
uni.showModal({
title: '提示',
content: '确定要删除此账单吗?',
success: function (res) {
if (res.confirm) {
console.log('用户点击确定');
emit(
'deleteBill',
{
bill_id: bill_id.value
},
(res)=>{
//回调函数的方法体.处理自己的业务.
console.log("获取到父组件执行结果的回调");
console.log(res);
}
);
} else if (res.cancel) {
console.log('用户点击取消');
}
}
});
};
const getTodayDateTime = () => {
var date = new Date();
var Y = date.getFullYear() + '-';
var M = (date.getMonth()+1 < 10 ? '0'+(date.getMonth()+1):date.getMonth()+1) + '-';
var D = (date.getDate()< 10 ? '0'+date.getDate():date.getDate())+ ' ';
var h = (date.getHours() < 10 ? '0'+date.getHours():date.getHours())+ ':';
var m = (date.getMinutes() < 10 ? '0'+date.getMinutes():date.getMinutes()) + ':';
var s = date.getSeconds() < 10 ? '0'+date.getSeconds():date.getSeconds();
return Y+M+D+h+m+s;
};
// 一个计算属性 ref
const choosedDateShow = computed(() => {
if (date_picker_date.value == getTodayDateTime().substring(0, 10)) {
return '今天';
}
else {
return date_picker_date.value;
}
})
</script>
<style lang="scss">
.keyboardbox {
width: 100%;
position: absolute;
left: 0;
bottom: 0;
background-color: #FFFFFF;
.numkeyboard {
height: 432rpx;
display: flex;
background-color: #ebedf0;
.btn-area {
width: 180rpx;
height: 100%;
display: flex;
flex-direction: column;
.item {
width: 100%;
display: flex;
justify-content: center;
align-items: center;
flex-grow: 1;
}
.del {
background-color: #ebedf0;
color: #333;
&.active {
background-color: #f1f3f5;
}
}
.confirem {
background-color: #4fae70;
color: #FFFFFF;
&.active {
background-color: #4fae70;
}
}
.deletebill {
background-color: #e94d26;
color: #333;
}
.dateChoose {
background-color: #f9db56;
color: #2d2d2d;
&.active {
background-color: #f9db56;
}
}
}
.num-area {
flex-grow: 1;
display: flex;
flex-wrap: wrap;
.row {
width: 100%;
height: 25%;
display: flex;
margin-top: 1px;
.item {
flex-grow: 1;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
background-color: #FFFFFF;
border-right: 1px solid #ebedf0;
width: 33.33%;
&.active {
background-color: #ebedf0;
}
&.z {
flex-grow: 2;
width: 66.66%;
}
&.disabled {
background: #FFFFFF;
color: #B9B9B9;
}
}
}
}
}
}
</style>
1.4. 如何引用
我们选择在父组件里面,通过一个u-popup来包裹此键盘组件,并在显示之前,把要传递进去显示的数据用v-model进行绑定:
- 如果是添加账单的场景:父组件传值给子组件;子组件要调用父组件的submit方法;子组件要知道父组件submit方法的执行结果。
vue
<u-popup v-model="popup_show" mode="bottom" border-radius="14" height="600rpx">
<keyboard-info
:item_name="item_name"
:bill_money="bill_money"
:bill_desc="bill_desc"
:date_picker_date="date_picker_date"
:add_or_update="'添加账单'"
@submit="submit"
>
</keyboard-info>
</u-popup>
js
// 上面的item_name、bill_money、bill_desc、date_picker_date要自行处理赋值。
selectItem(index) {
this.bill_money = '0.00';// 点击弹出的金额默认还原为0
this.bill_desc = '';// 理由同上
this.select_item = index;
this.popup_show = true; // 展示u-popup,也就能展示出来键盘子组件了。
if (this.current_type == 0) {
this.item_name = this.expenditure_list[index-1].text
this.item_img_path = this.expenditure_list[index-1].icon
this.item_id = this.expenditure_list[index-1].id
}
else {
this.item_name = this.income_list[index-1].text
this.item_img_path = this.income_list[index-1].icon
this.item_id = thisincome_list[index-1].id
}
},
// submit方法,主要是用来给键盘组件在点击键盘的"提交"按钮时,将键盘组件录入的数据回传到父组件的submit方法中
// 这里要再说一下callback参数,其实是键盘组件为了获取到父组件执行了submit方法之后的返回值,以便在成功执行操作之后,将键盘隐藏或引导页面跳转
submit(data, callback) {
console.log('收到键盘子组件触发submit方法');
console.log(data);
if (this.direction == '支出') {
data.bill_money = -data.bill_money;
}
// console.log('bill_add.vue的 submit() 方法被调用');
let bill_detail = {
bill_id: this.direction + this.getTodayDateTime(),
direction: this.direction,
year: parseInt(this.date_picker_date.substring(0, 4)),
month: parseInt(this.date_picker_date.substring(5,7)),
day: parseInt(this.date_picker_date.substring(8,10)),
week: this.getWeek(this.date_picker_date),
item_name: this.item_name,
item_img_path: this.item_img_path,
item_id: parseInt(this.item_id),
add_time: this.getTodayDateTime(),
update_time: this.getTodayDateTime(),
// 下面3个,是从键盘组件回调来的值
bill_desc: data.bill_desc,
bill_date: data.date_picker_date,
bill_money: parseFloat(data.bill_money)
}
console.log(bill_detail);
callback(true);
},
-
如果是编辑账单的场景
vue<u-popup v-model="popup_show" mode="bottom" border-radius="14" height="600rpx"> <keyboard-info :item_name="item_name" :bill_money="bill_money" :bill_desc="bill_desc" :date_picker_date="date_picker_date" :add_or_update="'编辑账单'" :bill_id="bill_id" @submit="submit" @deleteBill="deleteBill" > </keyboard-info> </u-popup>
跟之前的分析是类似的。