uniapp开发小程序,制作选择下拉框(经验少,做的不完美)

一、最终效果

1、默认样式(默认选择第一条数据)

2、点击后默认展示10条数据

3、支持模糊查询

4、选择项目确认后

二、代码实现过程

<template>
	<view class="layout">
		<!-- #ifndef MP-TOUTIAO -->
		<custom-nav-bar title="物品出库" withBack @backPage="backSpace"></custom-nav-bar>
		<!-- #endif -->
		<view class="inner">
			<view class="content">
				<view class="goodsInfo">
					<view class="top">
						<view class="img">
							<u--image :src="baseUrl + info.goodsImages" width="80px" height="80px" radius="4"></u--image>
						</view>
						<view class="text">
							<u--text :text="info.goodsName" bold lines="1" size="20px"></u--text>
							<view style="margin-top: 10rpx;">
								<u--text :text="info.goodsCode"  lines="1" size="14px" color="#999"></u--text>
							</view>
						</view>
					</view>
					<view class="goodsDesc">
						<view class="row">
							<view class="left">
								仓库名
							</view>
							<view class="right">
								{{info.wareHouseName}}
							</view>
						</view>
						<view class="row">
							<view class="left">
								库位号
							</view>
							<view class="right">
								{{info.wareStorageCode}}
							</view>
						</view>
						<view class="row">
							<view class="left">
								规格
							</view>
							<view class="right">
								{{info.goodsSize==null ? '暂无' :info.goodsSize}}
							</view>
						</view>
						<view class="row">
							<view class="left">
								单位
							</view>
							<view class="right">
								{{info.goodsUnit}}
							</view>
						</view>
						<view class="row">
							<view class="left">
								类别
							</view>
							<view class="right">
								{{info.goodsCategory }}
							</view>
						</view>
						<view class="row">
							<view class="left">
								库存数量
							</view>
							<view class="right">
								{{info.goodsInventoryNum}}
							</view>
						</view>
					</view>
				</view>
			</view>
			<view class="intoNum">
				<u-form
				labelWidth="180rpx"
				      :model="formData"
				      :rules="rules"
				      ref="form"
				    >
				      <u-form-item
				        label="出库数量"
				        prop="outNum"
				      >
				        <u--input
				          v-model="formData.outNum"
				          type="number"
						  border="none"
				          placeholder="请输入数量"
				        />
				      </u-form-item>
					  
					  <!-- 下拉选择框-->
					 <view class="project" v-if="projectFlag">
					 	<u-form-item
					 	  label="关联项目"
					 	  prop="projectName"
					 	>
					 	  <view class="put" @click="isNation=!isNation">
					 	  	<u--input
								v-model="formData.projectName"
								type="text"
								border="none"
					 			disabled
								placeholder="请选择关联项目"
					 	  	/>
					 	  </view>
					 	</u-form-item>
					 </view>
				</u-form>
			</view>
			<view class="remark">
				<view class="text">
					备注信息
				</view>
				<u--textarea v-model="remarkText" placeholder="请输入备注信息" border="null"></u--textarea>
			</view>
			<view class="upLoadImg" >
				<view class="img">
					<text>出库照片</text>
				</view>
				<u-upload
					class="upload"
					:fileList="fileList1"
					@afterRead="afterRead"
					@delete="deletePic"
					name="1"
					multiple
					:maxCount="9"
				></u-upload>
			</view>
			<view class="footer">
				<view class="certain" @click="certain">
					<btn title="添加出库单"></btn>
				</view>
			</view>
		</view>
		<!-- 下拉选择框底部弹出框 -->
		<view class="date-background" v-show="isNation">
			<view class='date-gray-background' @click="hiddeDatePicker"></view>
			<view class='date-container'>
				<view class="transparent">
					<view class='date-confirm'>
						<view @click="hiddeDatePicker" class="pickerCancel">取消</view>
						<!-- 输入框 -->
						<u-search style="width: 70%;" placeholder="请输入项目名称" @clear="clearSearch" @change='searchChange'
							:show-action='false' v-model="searchValue" shape="round" clearabled></u-search>
						<view @click="confirm1" class="pickerConfirm">确认</view>
					</view>
						<picker-view :immediate-change='true' indicator-class="indicator" :value="setValues"
							@change="bindChange" mask-style="height:100rpx;"
							style="width: 100%; height: 80%;position:absolute;bottom:0rpx;text-align:center;background:white">
							<picker-view-column class="pickViewColumn">
								<view v-for="item in array" :key="item.id" class="u-column-item"
									style="height: 68rpx;overflow: hidden;">{{item.projectName}}
								</view>
							</picker-view-column>
						</picker-view>
				</view>
			</view>
		</view>
	</view>
</template>

<script>
	import config from '@/config'
	import { getToken } from '@/utils/auth'
	import {onLoad,onReady} from "@dcloudio/uni-app"
	import {apiGetGoodsInfo,apiFdProject} from "@/api/home.js"
	import {mounted,watch} from "vue"
	export default {
		data(){
			return{
				projectFlag:false,
				baseUrl:config.baseUrl,
				pageNum:1,
				pageSize:10,
				projectCode:'',
				//搜索下拉框
				proIndex:0,
				setValues:[0],
				array: [],
				searchValue:'',
				isNation:false,
				baseUrl:config.baseUrl,
				wareHouseName:'',
				info:{},
				remarkText:'',
				operationType:2,
				files:'',
				fileList1:[],
				lastList:[],
				//表单验证
				goodsNum:0,
				formData: {
						outNum: '', // 初始化为空字符串
						projectName:''
					},
				rules: {
					outNum: [
							{
								required: true,
								message: "请输入出库数量",
								trigger: ['blur', 'change']
							},
							{
								type: 'number',
								message: '请输入数字',
								trigger: ['blur', 'change']
							},
							{
								validator: (rule, value, callback) => {
									console.log(this.goodsNum)
									console.log(value)
								   if (value > this.goodsNum) {
											callback(new Error(`出库数量不能大于库存数量 ${this.goodsNum}`));
										} else if (value <= 0) {
											// 修正:判断小于等于 0
											callback(new Error('出库数量必须大于 0')); 
										} else {
											callback();
									}
								},
								trigger: ['blur','change']
							}
						],
					},
			}
		},
		methods:{
			setValueInit(){
				this.$nextTick(()=>{
					this.setValues=[0]
					this.formData.projectName=this.array[0].projectName
					this.projectCode = this.array[0].projectCode;
				})
			},
			backSpace(){
				// 返回上个页面,此处使用navigateBack避免页面栈爆掉
				uni.navigateBack({
					url:"/pages/home/outBill/outBill"
				})
			},
			//隐藏底部弹出框
			clearSearch() { 
				//清空搜索内容
				this.searchValue = ''
			},
			hiddeDatePicker(){
				this.isNation=false
			},
			bindChange(e) {
				 const proIndex = e.detail.value[0]; // 获取选中项目的索引
				  this.formData.projectName = this.array[proIndex].projectName;
				  this.projectCode = this.array[proIndex].projectCode;
				console.log(e)
				// 获取选择得项目的索引
				// let proIndex = e.detail.value.toString()
				// this.array.forEach((item,index)=>{
				// 	if(proIndex==index){
				// 		this.$nextTick(()=>{
				// 			this.formData.projectName=item.projectName
				// 			this.projectCode = item.projectCode
				// 		})
						
				// 	}
				// })
			},
			// 确认关闭
			confirm1(e) {
				console.log(this.array)
				this.setValues=[0]
				this.isNation=false
			},
			// 查询项目
			searchChange(e){
				this.searchValue=e
				this.getPro()
				this.setValueInit()
			},
			// 获取物品信息
			getGoodsInfo(id){
				apiGetGoodsInfo(id).then(res=>{
				this.info=res.data
			// 判断物品是否需要关联项目
				if(this.info.goodsCategoryCode==='3'||this.info.goodsCategoryCode==='5'){
					this.projectFlag=true
				}
				this.goodsNum=res.data.goodsInventoryNum
				})
			}, 
			// 获取项目数据
			getPro(){
				apiFdProject({pageNum:this.pageNum,pageSize:this.pageSize,projectName:this.searchValue}).then(res=>{
					this.array=[...res.rows]
				})
			},
			//删除图片
			deletePic(event) {
				this[`fileList${event.name}`].splice(event.index, 1)
				this.lastList.splice(event.index,1)
				this.files=this.lastList.join(',')
			},
			// 新增图片
			async afterRead(event) {
				// 当设置 multiple 为 true 时, file 为数组格式,否则为对象格式
				let lists = [].concat(event.file)
				let fileListLen = this[`fileList${event.name}`].length
				lists.map((item) => {
					this[`fileList${event.name}`].push({
						...item,
						status: 'uploading',
						message: '上传中'
					})
				})
				for (let i = 0; i < lists.length; i++) {
					const result = await this.uploadFilePromise(lists[i].url)
					let item = this[`fileList${event.name}`][fileListLen]
					this[`fileList${event.name}`].splice(fileListLen, 1, Object.assign(item, {
						status: 'success',
						message: '',
						url: result
					}))
					fileListLen++
				}
			},
			uploadFilePromise(url) {
				return new Promise((resolve, reject) => {
					let a = uni.uploadFile({
						url: this.baseUrl + '/common/upload',
						filePath: url,  
						name: 'file',  
						formData: {}, 
						header: {  
						  Authorization: 'Bearer ' + getToken(), 
						 'Content-Type': 'multipart/form-data' 
						},  
						success: (res) => {
							this.lastList.push(JSON.parse(res.data).fileName)
							this.files=this.lastList.join(',')
							setTimeout(() => {
								resolve(res.data.data)
							}, 500)
						}
					});
				})
			},
			certain(){
				if(this.formData.outNum<=0){
					uni.showModal({
						title:'提示',
						content:'请正确填写出库数量',
						showCancel:false,
						confirmText:"去填写",
						success: (res) => {
							if(res.confirm){
								// 用户点击确定,但因为没有填写数量,所以不需要跳转到其他页面或提交数据  
							}
						}
					})
					return
				}
				
				if(this.projectFlag){
					if(!this.formData.projectName){
						uni.showModal({
							title:'提示',
							content:'没有关联项目',
							showCancel:false,
							confirmText:"去关联",
							success: (res) => {
								if(res.confirm){
									// 用户点击确定,但因为没有填写数量,所以不需要跳转到其他页面或提交数据  
								}
							}
						})
						return
					}
				}
				//设置info对象的数据
				this.info.operationNum=Number(this.formData.outNum)
				this.info.remark=this.remarkText
				this.info.operationType = this.operationType
				this.info.projectCode = this.projectCode
				this.info.projectName = this.formData.projectName
				if(this.files!==''&&this.files){
					this.info.operationImage = this.files
				}else{
					this.info.operationImage = ''
				}
				this.$store.dispatch('addToOutCart',this.info).then(()=>{
				})
				.catch((err)=>{
					console.log('添加购物车失败',err)
				})
			}
		},
		onReady() {
			//如果需要兼容微信小程序,并且校验规则中含有方法等,只能通过setRules方法设置规则。
		    this.$refs.form.setRules(this.rules)
		    },
		// 与vue中的mounted作用类似,但是执行时间更早
		onLoad(options) {
			let id = options.id
			this.wareHouseName = options.wareHouseName
			this.getGoodsInfo(id)
			this.getPro()
		},
		watch:{
			array:function (newVal,oldVal) {
				console.log(newVal)
				this.formData.projectName = newVal[0].projectName;
				this.projectCode = newVal[0].projectCode;
			}
		},
		mounted(){
			this.setValueInit()
		}
	}
</script>

<style lang="scss" scoped>
.layout{
	width: 100%;
	height: 100%;
	box-sizing: border-box;
	padding: 30rpx;
	padding-bottom: 140rpx;
	background-color: #f2f4f8;
	.inner{
		height: 1240rpx;
		overflow: hidden;
		overflow-y: auto;
		.content{
			box-sizing: border-box;
			padding:20rpx 30rpx;
			background-color: #fff;
			border-radius: 20rpx;
			.top{
				height: 240rpx;
				box-sizing: border-box;
				background-color: #f2f4f8;
				padding: 20rpx;
				border-radius: 20rpx;
				position: relative;
				.img{
					position: absolute;
					top:20%;
					left: 60rpx;
				}
				.text{
					position: absolute;
					top:30%;
					left: 40%;
				}
			}
			.goodsDesc{
				margin-top: 40rpx;
				.row{
					margin-bottom: 15rpx;
					display: flex;
					justify-content: space-between;
					.left{
						color:#999;
						font-size: 14px;
					}
					.right{
						color:#333;
						font-size: 14px;
					}
				}
			}
		}
		.intoNum,.remark,.upLoadImg{
			margin-top: 20rpx;
			box-sizing: border-box;
			padding:20rpx 30rpx;
			background-color: #fff;
			border-radius: 15rpx;
			display: flex;
		}
		
		.intoNum{
			align-items: center;
			justify-content: start;
			.put{
				display: flex;
				align-items: center;
			}
		}
		.remark{
			align-items: start;
			.text{
				margin-top: 15rpx;
			}
		}
		.upLoadImg{
			align-items: center;
			justify-content: space-between;
			.upload{
				margin-left: 40rpx;
			}
		}
		.footer{
			padding: 0 20rpx;
			position: fixed;
			bottom: 0;
			left: 0;
			height: 160rpx;
			width: 100%;
			display: flex;
			align-items: center;
			justify-content: center;
			background-color: #fff;
			border-radius: 25rpx;
		}
	}
	//底部弹出框样式
	.date-background {
		position: fixed;
		left: 0;
		top: 0;
		bottom: 0;
		width: 100%;
		height: 100%;
		z-index: 1111;
	}
	 
	.date-gray-background {
		position: absolute;
		width: 100%;
		top: 0rpx;
		background: rgba(0, 0, 0, .5);
		height: calc(100% - 500rpx);
	}
	 
	.date-container {
		position: absolute;
		width: 100%;
		height: 60%;
		overflow: hidden;
		background: #fff;
		bottom: 0;
		z-index: 1000;
	}
	 
	.date-confirm {
		display: flex;
		justify-content: space-between;
		align-items: center;
		padding: 20rpx;
		font-size: 34rpx;
		line-height: 100rpx;
		z-index: 2;
	}
	 
	.pickViewColumn {
		height: 60%;
	}
	 
	.indicator {
		height: 40rpx;
	}
	 
	.pickerCancel {
		font-size: 30rpx;
		color: #606266;
		box-sizing: border-box;
		text-align: center;
		text-decoration: none;
	 
		padding: 0rpx 8rpx;
	}
	 
	.pickerConfirm {
		font-size: 30rpx;
		color: #2979ff;
		box-sizing: border-box;
		text-align: center;
		text-decoration: none;
		padding: 0rpx 8rpx;
	}
	 
	.u-column-item {
		display: flex;
		flex-direction: row;
		align-items: center;
		justify-content: center;
		font-size: 30rpx;
		color: #303133;
		padding: 0 8rpx;
	}
}
</style>

上述代码为实现过程

要实现下拉框懒加载和搜索,可以考虑以下步骤: 1. 在页面中添加一个输入框和一个下拉框组件。 2. 在下拉框组件的数据源中只初始化一部分数据,比如10条。 3. 当用户滚动到下拉框的底部时,触发下拉框的on-scrolltolower事件,在该事件中加载更多的数据并添加到数据源中。 4. 在输入框的输入事件中,获取输入的关键字,进行模糊匹配,并更新下拉框的数据源。 5. 当用户选择下拉框中的某一项时,将选中的值显示在输入框中。 实现代码如下: ```html <template> <view> <input type="text" placeholder="请输入搜索关键字" @input="onInput" /> <scroll-view scroll-y style="height: 300rpx;" @scrolltolower="onScrollToLower"> <view v-for="(item, index) in dataList" :key="index" @click="onItemClick(item)"> {{item.text}} </view> </scroll-view> </view> </template> <script> export default { data() { return { dataList: [], // 下拉框数据源 pageIndex: 0, // 当前页码 pageSize: 10, // 每页条数 keyword: '', // 关键字 }; }, onReady() { // 初始化数据 this.loadData(); }, methods: { // 加载数据 loadData() { // 模拟异步加载数据 setTimeout(() => { const data = []; for (let i = 0; i < this.pageSize; i++) { data.push({ id: this.pageIndex * this.pageSize + i + 1, text: `选项${this.pageIndex * this.pageSize + i + 1}`, }); } this.dataList = this.dataList.concat(data); this.pageIndex++; }, 1000); }, // 滚动到底部触发 onScrollToLower() { this.loadData(); }, // 输入框输入事件 onInput(e) { this.keyword = e.detail.value; this.filterData(); }, // 数据筛选 filterData() { const reg = new RegExp(this.keyword, 'g'); this.dataList = this.dataList.filter(item => reg.test(item.text)); }, // 下拉框项点击事件 onItemClick(item) { console.log('选中了:', item); }, }, }; </script> ``` 注意:为了方便演示,这里的数据是通过setTimeout模拟异步加载的,实际开发中需要根据实际情况进行调整。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值