uniapp~PDA扫码枪实现组件封装

1,660 阅读1分钟

有没有实现用PDA扫描二维码或者一维码获取数据操作的? 其实是一个简单的输入框封装

要求

  1. 拿起扫码枪随时可扫,焦点随时必须在输入框内(使用定时器手动获取焦点)
  2. 需要绑定一个值实现父子组件的值同步(使用v-model)
  3. 需要给其他输入框需要输入时让出焦点(控制是否获取焦点)
  4. 扫码输入框不能拉起软键盘,其他输入框需要拉起软键盘(添加readonly属性)
以以上几点来完成扫描框组件

添加一个scanInput.vue

<view class="scan">
  <uni-easyinput id="scaninput" :auto-blur="false" ref="scanInputRef"
    class="scaninput" :focus='focusState'
    :clearable="false" v-model="scanValue" :placeholder="placeholder"
    @blur='focusBlur' @focus="focusDo" @confirm="confirmDo">
    </uni-easyinput>
 <!-- 遮住input框 不点到其弹起软键盘 -->
 <view class="masksty">
    <view class="vm" style="background: #fff;">
       <uni-icons type="close" v-if="inputValue" size="27" class="vm"
            @click="clearDo" color="#999"></uni-icons>
       <uni-icons type="scan" size="26" class="vm" @click="iconClick" 
           color="#3DCEC9"></uni-icons>
	</view>
    </view>
</view>
</template>

<script setup>
    /* 
	 说明:更改传入的isFous焦点状态来确认是否获取焦点,true:获取,false:不获取
	 props参数:inputValue 输入框值
                 isFous 是否获取扫描框焦点
		  placeholder 扫描框占位符
						
        回调函数:@scanSuccess 扫描成功回调 返回扫描的值
		@iconClick 点击扫描按钮触发 返回扫描框的值
		@clear 点击清除按钮触发 没有返回
		@confirm 点击完成按钮触达 返回扫描框的值
	 
     */
	import {ref,reactive,defineProps,defineEmits,watch,} from 'vue';
	import {onReady,onLoad,} from '@dcloudio/uni-app'
	//接收到的参数
	const props = defineProps({
            placeholder: String, //占位符
            isFous: Boolean, //是否需要聚焦
            inputValue: String, //输入框值
	})
	//@scanSuccess 扫描成功回调
	const emit = defineEmits(['update:inputValue', "scanSuccess",
            'iconClick', 'clear', 'confirm'])
	let scanTimer = ref(null);
	let scanValue = ref('');
	let scanInputRef = ref();
	let focusState = ref(true);

	onLoad(() => {
		focusState.value = props.isFous;
		scanValue.value = props.inputValue
		//监听值变化,并回调
		watch(scanValue, (newVal, oldVal) => {
			// console.log('newVal',newVal);
			emit('update:inputValue', newVal)
			if(!newVal) return
			if (newVal) {
                            emit("scanSuccess", newVal);
			}
		})
		watch(() => props.isFous, (newVal, oldVal) => {
			if (newVal) { //是
				focusState.value = true;
				hideKeyboard();
			} else {
				destroyTimer(); //否
			}

		})
		watch(() => props.inputValue, (newVal, oldVal) => {
			scanValue.value = newVal
		})
	})

	function updateInput() {
            emit('update:inputValue', scanValue.value)
	}

	/**
	 * 创建定时任务 始终获取焦点[两输入框时,输入完成后,创建任务]
	 */
	function createTimer() {
		scanTimer.value = setInterval(function() {
			// console.log('监听聚焦');
			focusState.value = true;
			//获取焦点后 清除定时器
			clearInterval(scanTimer.value);
			hideKeyboard();
		}, 1300)
	}
	/**
	 * 销毁定时任务[例如页面上有两输入框时,在输入框聚焦时销毁该任务,防止条码框一直聚焦无法输入]
	 */
	function destroyTimer() {
		clearInterval(scanTimer.value);
		focusState.value = false;

	}
	//扫描框失去焦点时现更改状态 然后定时手动聚焦
	function focusBlur() {
		if (focusState.value) {
			focusState.value = false;
			createTimer();
		}
	}
	//获取到焦点更改状态
	function focusDo() {
		focusState.value = true;
		clearInterval(scanTimer.value);
		hideKeyboard();
	}
	//隐藏软键盘
	function hideKeyboard() {
		let scanInputEle = document.querySelector('#scaninput input');
		
		if (scanInputEle) {
			scanInputEle.setAttribute("readonly", true);
			setTimeout(() => {
				scanInputEle.removeAttribute("readonly");
			}, 100);
		}
	}

	function iconClick() {
		//点击扫描图标触发,返回扫描框的值
		emit("scanSuccess", scanValue.value);
	}
	//点击清除按钮时操作
	function clearDo() {
		scanValue.value = '';
		emit('update:inputValue', scanValue.value)
		emit("clear");
	}
	//点击确认时操作
	function confirmDo() {
		emit("confirm", scanValue.value);
	}
</script>

<style lang="scss">
	.scan {
		padding: 28rpx 30rpx;
		position: relative;

		.masksty {
			position: absolute;
			top: 0;
			right: 0;
			left: 0;
			bottom: 0;
			background: transparent;
			padding: 38rpx 46rpx;
			text-align: right;
		}

		.closeico {}

		.scaninput {
			:deep(.is-input-border) {
				border: 1px solid #3DCEC9 !important;
				border-radius: 32rpx !important;
			}

			:deep(.uni-icons) {
				color: #3DCEC9 !important;
			}
		}
	}
</style>

使用

	import scanInput from '../../components/scanInput.vue'
</script>
<scan-input :placeholder="'请将设备对准条形码进行扫描'"
    v-model:inputValue="inputValue" :isFous='scanFous'
    @scanSuccess="scanSuccess" @clear="clearScan"></scan-input>
    
<uni-easyinput v-model="em.scannedNum" placeholder="请输入本次出库数量" 
    type="number" @focus="scanFous = false" @blur="scanFous = true"></uni-easyinput>
			

其实这个组件最头痛的是收起输入法的软键盘,uni有一个API hideKeyboard()方法,但是这里使用就是一个坑,键盘到是收起来了,但是却再也获取不到焦点了,官方也没有提出解决方法,就只能自己小试牛刀了,而且uni内部组件input的封装也没有readonly的属性,姑且按照H5的方式给input加一个readOnly的属性来不弹起输入法软键盘,h5是亲测可用,打包成APP待验证~

09fe63fc1d97467091944da277324b20.jpeg