7.从0做一个vue键盘组件

1. 从0做一个键盘组件

首先是why的问题:为什么需要做键盘组件?

我们目前可知的场景:

  1. 在新增账单的时候,需要用到键盘
  2. 在比如从账单列表页,进行行项目编辑某笔账单的时候,也需要用到键盘

如果都是每个vue页面自己写键盘的话,就比较尴尬了,回头需要优化的时候,就要多处维护。

所以,我们需要定义一个键盘组件。

1.1. 最终效果

或者是编辑的时候:

1.2. 分析

  1. 主要是显示:item_name账单类目名称、bill_money账单金额、账单日期选择、提交账单、删除账单
  2. 如果是新增账单,就不显示”删除账单“按钮;如果是编辑账单,展示”删除账单“按钮。

1.3. 实现

整体的键盘样式都比较简单,可以直接通过布局来绘制。

直接上代码:

<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方法的执行结果。
<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>
// 上面的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);
},
  • 如果是编辑账单的场景

    <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>
    

    跟之前的分析是类似的。

  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值