uniapp u--input实现select下拉列表 input点击事件

背景:

技术框架:

uniapp框架(vue2语法)+uView组件库。

通过form表单实现数据列表的"查询"功能。注意:

1、<u--form>内部嵌套<u-form-item>,<u-form-item>内部嵌套<u--input>表单组件。

2、H5浏览器端,input输入框可以整块点击。但uniapp打包成App,不能整块点击;在平板上运行,可以整块点击。

3、input实现 select下拉列表功能

4、在App上,实现input输入框的整块点击,点击之后出现select弹框区域。

5、Form表单封装组件。接收绑定Form的数据(父传子formItems[]);监听formInline的变化,监听到变化后emit(子传父,)

效果展示:

官网链接:点击跳转官网 form

接下来便是要解决的问题:让整块input输入框都可以点击。。。

一、selet下拉列表的实现

实现思路:

input输入框,通过点击右侧的插槽图标,实现select弹框弹出。实际是两部分组成。。。

javascript 复制代码
<u--input 
    :readonly="true" 
    v-model="inputValue" 
    :placeholder="'请选择'"
    suffixIcon="arrow-down" 
>
</u--input>

下拉列表:

javascript 复制代码
<!-- 下拉列表显示 -->
<u-action-sheet 
    :show="showOption" 
    :actions="currentSelectItem.option.optionList"
    :title="currentSelectItem.option.title" 
    :description="currentSelectItem.option.description"
    @close="handleCloseOption(false)" 
    @select="handleSelect" 
    v-if="currentSelectItem.option"
>
</u-action-sheet>

官网链接:点击跳转官网 action-sheet

二、input框整块点击,打开select弹框

实现思路:

要想实现input框的整块点击。

实现思路是:

1、给当前input外层套一个盒子,在此盒子上绑定@click事件;

2、给input添加鼠标点击样式:style="pointer-events:none"。

none表示:鼠标事件"穿透"该元素并且指定该元素"下面"的任何东西。

给input外层套一层盒子,并绑定事件:

javascript 复制代码
<template @click='handleOpenOption(item)'>
<u--input 
:readonly="true" 
style="pointer-events:none" 
v-model="inputValue"				
:placeholder="'整块点击'" 
suffixIcon="arrow-down" 
>
</u--input>
</template>

事件:

javascript 复制代码
methods: {
		handleOpenOption(item) {
			if (item.type === 'calendar') {
				this.currentSelectItem = {
					...item
				};
				this.handleCloseCalendar(true);//打开日期选择弹框
			}
			if (item.type === 'select') {
				this.currentSelectItem = {
					...item
				};
				this.handleCloseOption(true);//打开select弹框
			}
		},
}

三、封装form表单组件

背景:

理论知识:

父传子:通过props,获取到传递到子组件的formItems[];

子传父:通过watch监听表单组件绑定的数据的变化,使用emit('自定义事件名',传给父组件的数据值)

图片:

formItems封装代码:

javascript 复制代码
//formItems分装代码
<template>
	<view>
		<u--form labelPosition="left" :model="formInline" :rules="formRules" ref="uForm" :errorType="errorType">
			<u-form-item :required="item.rule.required" labelWidth="230rpx" labelAlign="right" :label="item.label"
				:prop="item.key" :borderBottom="false" @tap="handleOpenOption(item)" v-for="item, index in formItems"
				:key="index">
				<u--input v-model="formInline[item.key]" :placeholder="item.placeholder" v-if="item.type === 'input'"
					:customStyle="item.customStyle"></u--input>
				<!-- input带后置图标 -->
				<u--input v-model="formInline[item.key]" :placeholder="item.placeholder" suffixIcon="search"
					suffixIconStyle="color: #333333;font-size: 42rpx" v-if="item.type === 'input2'"
					:customStyle="item.customStyle" :clearable="true" @clear="handleClear(item.key)"></u--input>
				<!-- 以下点击设置hideKeyboard(),让移动端不弹出键盘 -->
				<template @click='handleOpenOption(item)'>
					<u--input :readonly="true" style="pointer-events:none" v-model="formInline[item.key].name"
						:placeholder="item.placeholder" suffixIcon="arrow-down" v-if="item.type === 'select'"
						:customStyle="item.customStyle"></u--input>
				</template>
				<template @click='handleOpenOption(item)'>
					<u--input :readonly="true" style="pointer-events:none" v-model="formInline[item.key]"
						:placeholder="item.placeholder" suffixIcon="clock" v-if="item.type === 'calendar'"
						:customStyle="item.customStyle" :clearable="true" @clear="handleClear(item.key)" ></u--input>
				</template>
			</u-form-item>
		</u--form>
		<!-- 下拉列表显示 -->
		<u-action-sheet :show="showOption" :actions="currentSelectItem.option.optionList"
			:title="currentSelectItem.option.title" :description="currentSelectItem.option.description"
			@close="handleCloseOption(false)" @select="handleSelect" v-if="currentSelectItem.option">
		</u-action-sheet>
		<!-- 日历显示 -->
		<u-calendar :closeOnClickOverlay="true" monthNum="12" :minDate="minDate" :maxDate="maxDate" :show="showCalendar"
			mode="range" :allowSameDay="true" @confirm="handleConfirmCalendar"
			@close="handleCloseCalendar(false)"></u-calendar>
	</view>
</template>

<script>
import {
	getLayerData
} from '@/api/index.js'

export default {
	name: "FormItem",
	data() {
		return {
			formInline: {},
			formRules: {},

			showOption: false,
			currentSelectItem: {},
			showCalendar: false,
			readonlyCalendar: true,
			minDate: '2023-01-01',
			maxDate: '2023-11-07',
		};
	},
	props: {
		formItems: Array,
		errorType: {
			type: String,
			default: 'none'
		}
	},
	computed: {},
	watch: {
		formItems: {
			immediate: true,
			handler(newval, oldval) {
				newval.forEach(item => {
					// 动态请求下拉列表
					(item.type === 'select' && item.option.optionsSrc) && this.getOptionList(item);
					this.getFormRules();
					this.getFormInlineDefault();
				});
			}
		},
		formInline: {
			immediate: true,
			deep: true,
			handler(newval, oldval) {
				this.$emit('searchData', newval);
			}
		}
	},
	methods: {
		handleConfirmCalendar(e) { //日历选项选择完毕确认
			this.formInline[this.currentSelectItem.key] = e[0] + '至' + e[e.length - 1]
			this.handleCloseCalendar(false);
			// this.readonlyCalendar = !this.readonlyCalendar;
		},
		handleCloseCalendar(state) { //日历选项关闭
			this.showCalendar = state;
		},

		handleOpenOption(item) {
			if (this.readonlyCalendar) {
				if (item.type === 'calendar') {
					this.currentSelectItem = {
						...item
					};
					this.handleCloseCalendar(true);
				}
			}
			if (item.type === 'select') {
				//当前选择框的信息,因为复用了同一个下拉选择弹出层
				this.currentSelectItem = {
					...item
				};
				this.handleCloseOption(true);
			}
		},
		handleSelect(e) { //下拉选项选择目标逻辑
			this.formInline[this.currentSelectItem.key] = e;
		},
		handleCloseOption(state) { //下拉选项关闭逻辑
			this.showOption = state;
		},
		async getOptionList(item) {
			const {
				data: res
			} = await getLayerData(item.option.optionsSrc);
			const resData = res.data;
			item.option.optionList = resData.reduce((cre, pre) => [...cre, {
				name: pre[item.option.optionContent.name],
				// 下拉选项是对各值还是一个值
				value: item.option.optionContent.value === 'objString' ? JSON.stringify(pre) : pre[
					item.option.optionContent.value]
			}], [...item.option.options]);

			this.getFormInlineDefault();
		},
		getFormInlineDefault() {
			this.formInline = this.formItems.reduce((cre, pre) => {
				let handlePre = '';
				if (pre.defaultVal) {
					if (pre.defaultVal instanceof Array) {
						// 动态请求的内容作为默认值
						if (pre.option.optionList?.length > pre.defaultVal[0]) {
							handlePre = pre.option.optionList[pre.defaultVal[0]];
						} else {
							const emptyTarget = pre.option.optionList?.find(item => item.value === '')
							handlePre = emptyTarget || '';
						}
					} else {
						handlePre = pre.defaultVal;
					}
				} else {
					// const emptyTarget = pre.option?.optionList?.find(item => item.value === '')
					// handlePre = emptyTarget || '';
					handlePre = ''
				}
				return {
					...cre,
					[pre.key]: handlePre
				}
			}, {});
		},
		getFormRules() {
			this.formRules = this.formItems.reduce((cre, pre) => {
				return pre.rule && {
					...cre,
					[pre.key]: pre.rule
				}
			}, {});
		},
		handleClear(_key) {
			this.formInline[_key] = '';
			this.readonlyCalendar = true;
			this.readonlySelect = true
		},
		clickshowOption() {
			this.showOption = !this.showOption
		},
		getCurrentData() {
			const d = new Date()
			const year = d.getFullYear()
			let month = d.getMonth() + 1
			month = month < 10 ? `0${month}` : month
			const date = d.getDate()
			return [`${year}-${month}-${date}`]
		},
		getMinDate(_yesteMonth) {
			const yesteMonth = _yesteMonth || 2
			const d = new Date()
			const year = d.getFullYear()
			let month = d.getMonth() - yesteMonth
			month = month < 10 ? `0${month}` : month
			const date = d.getDate()
			return `${year}-${month}-${date}`
		}
	},
	onLoad() {
		this.formInline = {}
	},
	created() {
		this.maxDate = this.getCurrentData()[0]
		this.minDate = this.getMinDate(6)
	}
}
</script>

<style scoped lang="scss">
/deep/.u-form {

	>.u-form-item {

		>.u-form-item__body {
			padding: 0;

			>.u-form-item__body__right {
				// background-color: #F6F7FA;
				/* border-radius: 12rpx;
					border: 1px solid #E3E7EE;
					padding: 10rpx; */
			}
		}
	}
}

// /deep/ .u-input__content__clear {
// 	position: relative;
// }

// /deep/.u-icon__icon {
// 	position: absolute;
// 	left: 0px;
// 	right: 0px;
// 	top: 0px;
// 	bottom: 0px;
// 	justify-content: center;
// }</style>

父组件使用方法:

javascript 复制代码
//父传子myformItems
//子传父触发事件mysearchData
<FormItem :formItems="myformItems" @searchData="mysearchData"></FormItem>

上面用到的数据和方法:

数据formItems,示例如下:

javascript 复制代码
[
    {
      type: "input2",
      // label: "船舶名称",
      key: "name",
      placeholder: "请输入船舶名称",
      rule: {
        required: false,
      },
      customStyle: {
        "margin-bottom": "20rpx",
      },
    },
    {
      type: "input2",
      // label: "MMSI",
      key: "mmsi",
      placeholder: "请输入MMSI",
      rule: {
        required: false,
      },
      customStyle: {
        "margin-bottom": "20rpx",
      },
    },
  ],

mysearchData事件,示例如下:

javascript 复制代码
methods: {
        mysearchData(_data) {
            console.log(_data);
            this.pages.name = _data.name
            this.pages.mmsi = _data.mmsi
            this.pages.pageNum = 1
            this.pages.pageSize = 7
            this.getTableList(this.pages)//查询接口
         }
}
相关推荐
断墨先生1 小时前
uniapp—android原生插件开发(3Android真机调试)
android·uni-app
guai_guai_guai2 小时前
uniapp
前端·javascript·vue.js·uni-app
阿伟来咯~8 小时前
一些 uniapp相关bug
uni-app·bug
瑶琴AI前端11 小时前
uniapp组件实现省市区三级联动选择
java·前端·uni-app
mosen86812 小时前
Uniapp去除顶部导航栏-小程序、H5、APP适用
vue.js·微信小程序·小程序·uni-app·uniapp
尚梦20 小时前
uni-app 封装刘海状态栏(适用小程序, h5, 头条小程序)
前端·小程序·uni-app
尚学教辅学习资料1 天前
基于SSM+uniapp的营养食谱系统+LW参考示例
java·uni-app·ssm·菜谱
Bessie2341 天前
微信小程序eval无法使用的替代方案
微信小程序·小程序·uni-app
qq22951165021 天前
小程序Android系统 校园二手物品交换平台APP
微信小程序·uni-app
qq22951165022 天前
微信小程序uniapp基于Android的流浪动物管理系统 70c3u
微信小程序·uni-app