增强uni-app的uni-picker-view组件(添加搜索和禁选功能)

本文介绍了如何在uni-app中增强uni-picker-view组件,增加了搜索和禁选功能。通过组件文件的修改和配置,实现了用户在选择列表中能够进行搜索过滤,并能对特定选项进行禁用,提升用户体验。
该文章已生成可运行项目,

1、组件文件如下:
 

<template>
	<view>
		<view>
			<!-- 普通弹窗 -->
			<uni-popup ref="popup" background-color="#fff" @change="change">
				<view>
					<view>
						<uni-row>
						    <uni-col :span="6">
								<button plain="true" style="margin-top: 20rpx;border-style:none;" @click="cancelChange()"><text class="button-text">取消</text></button>
						    </uni-col>
						    <uni-col :span="12">
						        <uni-search-bar style="margin-top: 15rpx;font-size: 3em;" :value="searchKey" radius="0" placeholder="搜索" clearButton="none" cancelButton="none" @input="search"/>
						    </uni-col>
							<uni-col :span="6">
								<button plain="true" style="margin-top: 20rpx;border-style:none;" @click="sureSelect()"><text class="button-text">确定</text></button>
							</uni-col>
						</uni-row>
						<picker-view v-if="visible" :value="pickerValue" indicator-style="height:50px;" @change="bindChange">
							<picker-view-column>
								<view class="item" v-for="(item,index) in pickerList" :key="index">{{item}}</view>
							</picker-view-column>
						</picker-view>
					</view>
				</view>
			</uni-popup>
		</view>
	</view>
</template>

<script>
	export default {
		props:{
			value:String //确认选择值
			,list:Array //数据列表
			,disableKey:String//禁用关键词
			,disableTips:String//禁用提示
		}
		,watch:{
			value() {
				this.$emit('input',this.value);
			}
			,list(){
				this.init()
			}
			,disableKey(){
				this.defaultVal.picker.disableKey=this.disableKey
			}
			,disableTips(){
				this.defaultVal.picker.disableTips=this.disableTips
			}
			,immediate: true
		}
		,data() {
			const defaultVal= //默认常量
			{
				global:{
					debug:true
					,title:'my-picker-view'
				}
				,show:{
					value:'未选择'
				}
				,search:{
					searchKey:''
				}
				,picker:{
					pickerValue:[0]
					,visible:true
					,pickerList:[]
					,isChoose:false
					,chooseVal:''
					,disableKey:'已'
					,disableTips:'该选择项已在不可选状态,请重新选择!'
				}
			}
			return {
				defaultVal
				,title: ''
				,debug:true
				,pickerValue:[]
				,visible: true
				,pickerList:[]
				,searchKey:''
				,isChoose:true
				,chooseVal:''
			}
		}
		,mounted() {//初始化
			this.init()
		}
		,methods: {
			change(e) {
				// console.log('当前模式:' + e.type + ',状态:' + e.show);
				if(e.type=='center'&&e.show==false){
					this.resetSearch()
				}
			}
			,toggle(type) {
				// open 方法传入参数 等同在 uni-popup 组件上绑定 type属性
				this.$refs.popup.open(type)
			}
			,sureSelect(){
				this.debuglog('this.defaultVal.picker.disableKey')
				if(this.chooseVal.toString().indexOf(this.disableKey)>0){
					//弹窗提示:无法选取已代理区域
					uni.showToast({
					    title: this.disableTips,
					    duration: 2000
					});
				}else{
					this.value=this.chooseVal
					this.$refs.popup.close()
					this.resetSearch()
				}
			}
			,cancelChange(){
				this.$refs.popup.close()
				this.resetSearch()
			}
			,requestList(){//请求列表数据
				this.defaultVal.show.value=this.value
				this.defaultVal.picker.pickerList=this.list
				this.defaultVal.picker.pickerValue=[this.defaultVal.picker.pickerList.length-1]
				this.defaultVal.picker.chooseVal=this.defaultVal.picker.pickerList[this.defaultVal.picker.pickerValue[0]]
				this.defaultVal.picker.disableKey=this.disableKey
				this.defaultVal.picker.disableKey=this.disableTips
			}
			,resetAll(){//重置或初始化默认设置
				//初始化初始值
				this.debug=this.deepCopy(this.defaultVal.global.debug)
				this.title=this.deepCopy(this.defaultVal.global.title)
				this.searchKey=this.deepCopy(this.defaultVal.search.searchKey)
				this.pickerList=this.deepCopy(this.defaultVal.picker.pickerList)
				this.asc=this.deepCopy(this.defaultVal.picker.asc)
				this.visible=this.deepCopy(this.defaultVal.picker.visible)
				this.pickerValue= this.deepCopy(this.defaultVal.picker.pickerValue)
				this.isChoose=this.deepCopy(this.defaultVal.picker.isChoose)
				this.chooseVal=this.deepCopy(this.defaultVal.picker.chooseVal)
			}
			,init(){
				this.requestList()
				this.resetAll()
			}
			,bindChange(e){
				this.chooseVal=this.pickerList[e.detail.value[0]]
			}
			,search(e){
				this.searchKey=e
				if(this.searchKey==''){
					this.resetSearch()
				}else{
					this.pickerList.splice(0,this.pickerList.length)
					this.debuglog('this.searchKey')
					this.debuglog('this.defaultVal.picker.pickerList')
					for(let i=0;i<=this.defaultVal.picker.pickerList.length-1;i++){
						let searchVal=this.defaultVal.picker.pickerList[i].toString()
						if(searchVal.indexOf(this.searchKey)!=-1)
						{
							this.pickerList.push(searchVal)
						}
					}
					this.pickerValue=[this.pickerList.length-1]
					this.chooseVal=this.pickerList[this.pickerValue[0]]
				}
			}
			,resetSearch(){
				this.searchKey=''
				this.pickerList.splice(0,this.pickerList.length)
				this.pickerList= this.deepCopy(this.defaultVal.picker.pickerList);
				this.pickerValue=[this.pickerList.length-1]
				this.chooseVal=this.pickerList[this.pickerValue[0]]
			}
			,debuglog(obj,open){
				if(open==true||open==undefined){
					if(this.debug){
						console.log('debug调试中,检测的对象'+obj+'内容为'+JSON.stringify(eval(obj)))
					}
				}
			}
			,deepCopy(obj) 
			{
				// 判断如果不是引用类型,直接返回数据即可
				if (typeof obj === 'string' || typeof obj === 'number' || typeof obj === 'boolean' || typeof obj === 'undefined' || !obj) 
				{
					return obj
				}  
				return JSON.parse(JSON.stringify(obj));
			}
		}
	}
</script>

<style>
    picker-view {
        width: 100%;
        height: 600rpx;
        margin-top:20rpx;
    }

    .item {
        line-height: 100rpx;
        text-align: center;
    }
</style>

2、演示实例如下:
 

<template>
	<view>
		<view>当前选取确认值:{{selectVal}}</view>
		<button @click="changeList()">更换列表</button>
		<button class="button" type="primary" @click="openMpv()"><text class="button-text">打开选择器</text></button>
		<mpv ref='mpv' v-model="selectVal" :list="list" :disableKey="disableKey" :disableTips="disableTips"></mpv>
	</view>
</template>

<script>
	import mpv from '../../picker-view/my-picker-view/my-picker-view.vue'
	export default {
		components:{
			mpv
		}
		,data() {
			return {
				selectVal:'请选择'
				,aa:[['苹果(售罄)','香蕉','菠萝(售罄)','橘子'],['apple(sellof)','banana','boluo','orange']]
				,list:['苹果(售罄)','香蕉','菠萝(售罄)','橘子'] //数据列表
				,disableKey:'售罄'//禁用关键词
				,disableTips:'抱歉,此水果已售罄,请重新选择!'//禁用提示
			}
		}
		,methods: {
			changeList(){
				if(this.list[0]==this.aa[0][0]){
					this.list=this.aa[1]
					this.disableKey='sellof'
				}else{
					this.list=this.aa[0]
					this.disableKey='售罄'
				}
			}
			,openMpv(){
				this.$refs.mpv.toggle('bottom')
			}
		}
	}
</script>

<style>

</style>

3、界面截图如下:

 

 

 

 

本文章已经生成可运行项目
<think>好的,我现在需要解决用户的问题:在uni-app微信小程序中如何通过代码主动触发内置picker组件的单击事件。用户之前已经询问过如何触发内置组件的点击事件,我之前给出了两种方法,但现在针对picker组件需要具体分析。 首先,我要回顾之前的回答。之前提到的方法一是直接调用事件处理函数,方法二是使用小程序节点操作API。但picker组件可能有不同的行为,需要验证这些方法是否适用。 查看用户提供的引用资料,引用[4]提到了通过$emit触发自定义事件,但picker是内置组件,可能无法直接使用这种方法。引用[1]提到mpvue/uni-app中的一些坑,比如不支持v-show,用tap代替click,阻止冒泡的方法,这些可能影响事件触发。引用[2]提到maskClick无效的问题,可能涉及到事件绑定是否正确。引用[3]展示了跳转小程序的代码,但当前问题关联不大。 接下来,我需要考虑picker组件uni-app中的特性。根据微信小程序文档,picker组件需要通过用户点击来展开,可能无法直接通过代码触发其点击事件,因为安全限制或框架限制。但用户希望以编程方式触发,可能需要模拟点击或者调用组件的方法。 根据之前的回答,方法一是直接调用事件处理函数。例如,如果picker绑定了@change事件,手动调用该处理函数,并传递模拟的参数。但用户可能想展开picker择界面,这可能需要触发其内部的点击事件。 方法二是使用节点操作API,获取picker的节点并调用tap或click方法。但根据引用[1]的第7点,微信小程序中tap事件代替click,可能需要触发tap事件。但微信小程序的picker组件是否允许通过API触发tap事件呢?需要查阅相关文档。 此外,引用[1]提到部分原生组件可能有特殊行为,比如不支持直接触发事件。因此,picker作为原生组件,可能无法通过常规方式触发其点击事件。这时候可能需要替代方案,比如通过隐藏的按钮触发,或者调整UI逻辑。 用户提供的引用[4]中的例子是自定义组件中使用$emit,但内置组件可能没有暴露这样的接口。因此,可能需要结合之前的两种方法,或者寻找其他途径。 可能还需要考虑平台差异,比如在H5端是否可行,而微信小程序端是否有限制。根据之前的注意事项,部分原生组件可能无法直接触发,所以需要验证在微信小程序中picker是否属于这种情况。 总结可能的解决方案: 1. 尝试方法一,直接调用picker绑定的事件处理函数,模拟事件对象。 2. 使用方法二,通过节点操作触发tap事件,但可能受限于微信小程序的限制。 3. 使用替代UI元素,比如隐藏的按钮,绑定picker的打开方法,然后通过代码触发该按钮的点击事件。 4. 查阅uni-app文档,是否有picker组件的API可以主动打开,比如修改某个属性或调用方法。 现在,需要检查uni-apppicker组件是否有提供方法。例如,在微信小程序中,picker有bindcancelbindchange事件,但没有直接的方法展开。可能需要通过设置某个属性,比如show属性,但uni-apppicker可能没有这个属性。或者,是否有其他方式,比如focus某个输入框来触发picker,但不确定。 或者,uni-apppicker组件是否封装了原生的picker,可能无法直接触发其点击事件。这时候,可能需要使用原生小程序的API,比如通过createSelectorQuery获取节点,再调用dispatchEvent,但可能不被支持。 另外,用户引用[2]中提到的maskClick问题,可能涉及到事件绑定的正确性,需要确保事件监听正确,比如使用@mask-click或其他的事件名称。 综合这些信息,可能需要建议用户使用替代方法,例如用一个隐藏的按钮,点击该按钮时手动显示picker,或者通过改变picker的绑定值来触发其展开。或者,如果uni-apppicker支持通过ref调用方法,如open(),但需要查阅文档确认。 如果以上方法都不可行,可能需要告知用户受限于小程序的安全策略,无法直接触发picker的点击事件,建议调整交互设计。</think>在uni-app微信小程序中主动触发picker组件的点击事件,需要根据具体场景采用以下解决方案: ### 一、直接调用事件处理函数(推荐) ```html <template> <picker @change="onPickerChange" :value="index" :range="array"> <view class="picker">点击择</view> </picker> </template> <script> export default { data() { return { index: 0, array: ['项1', '项2'] } }, methods: { // 手动触发择器 triggerPicker() { this.onPickerChange({ detail: { value: 1 }, // 模拟中第二个项 target: { dataset: {} } }) }, onPickerChange(e) { this.index = e.detail.value console.log('当前中:', this.array[this.index]) } } } </script> ``` 通过手动调用事件处理函数并构造符合规范的`detail`对象,可以直接模拟择器变化事件[^1][^4]。 ### 二、使用DOM操作API(需处理平台差异) ```html <template> <picker id="myPicker" @change="onPickerChange"> <view>择器</view> </picker> </template> <script> export default { mounted() { uni.createSelectorQuery() .select('#myPicker') .node(res => { const pickerNode = res.node // 触发触摸事件(微信小程序环境) pickerNode.dispatchEvent('tap') // H5环境兼容方案 if (typeof pickerNode.click === 'function') { pickerNode.click() } }).exec() } } </script> ``` 注意:该方法在部分小程序版本中可能受限,建议配合防抖处理使用[^1][^3]。 ### 三、替代方案(推荐) 通过隐藏按钮组合实现: ```html <template> <view @click="realClickHandler"> <picker :disabled="true" @change="onPickerChange"></picker> </view> </template> <script> export default { methods: { realClickHandler() { uni.showActionSheet({ itemList: ['项1', '项2'], success: (res) => { this.onPickerChange({ detail: { value: res.tapIndex } }) } }) } } } </script> ``` 这种方式能绕过原生组件的事件限制,同时保持UI效果一致性[^2][^4]。 ### 注意事项 1. 原生picker组件的事件触发受小程序安全策略限制,直接DOM操作可能失效 2. 需特别注意事件对象中`detail.value`的赋值逻辑 3. iOS/Android平台对触摸事件的响应存在差异 4. 推荐优先使用Vue标准的事件驱动模式[^4]
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值