// components/filter-picker/filter-picker.js
Component({
properties: {
options: Array,
value: [String, Number],
placeholder: String,
disabled: Boolean,
maxHeight: {
type: Number,
value: 300
}
},
data: {
dropdownVisible: false,
searchText: '',
filteredOptions: [],
displayText: '',
isActive: false // 新增激活状态
},
methods: {
/**
* 安全更新筛选后的选项列表
* 1. 确保options是数组
* 2. 过滤掉非对象元素
* 3. 处理label属性缺失的情况
*/
updateFilteredOptions() {
let { options, searchText } = this.data;
// 确保options是数组,如果不是则重置为空数组
if (!Array.isArray(options)) {
options = [];
this.setData({ options });
}
// 过滤掉非对象元素
const validOptions = options.filter(item =>
item && typeof item === 'object' && 'label' in item
);
// 如果没有搜索文本,显示所有有效选项
if (!searchText) {
this.setData({ filteredOptions: validOptions });
return;
}
// 安全过滤:确保item有label属性
const filtered = validOptions.filter(item => {
const label = item.label || '';
return label.toString().toLowerCase().includes(searchText.toLowerCase());
});
this.setData({ filteredOptions: filtered });
},
/**
* 安全更新显示文本
* 1. 处理无效值
* 2. 处理找不到匹配项的情况
*/
updateDisplayText() {
const { value, options } = this.data;
// 确保options是有效数组
if (!Array.isArray(options) || options.length === 0) {
this.setData({ displayText: '' });
return;
}
// 处理空值
if (!value) {
this.setData({ displayText: '' });
return;
}
// 查找匹配项,忽略非对象元素
const selected = options.find(item =>
item && typeof item === 'object' &&
item.value === value
);
if (selected) {
this.setData({
displayText: selected.label || '',
searchText: selected.label || ''
});
} else {
this.setData({ displayText: '' });
}
},
/**
* 处理输入事件
* @param {Object} e - 事件对象
* @param {string} e.detail.value - 输入框的值
*/
onInput(e) {
const searchText = e.detail.value;
this.setData({ searchText }, () => {
this.updateFilteredOptions();
});
},
/**
* 当输入框获得焦点时的处理函数
* - 如果组件被禁用则直接返回
* - 设置下拉框可见状态、搜索文本和激活状态
* - 更新过滤后的选项列表
*/
onFocus() {
console.log('Picker focused'); // 调试日志
if (this.data.disabled) return;
this.setData({
dropdownVisible: true,
searchText: this.data.displayText,
isActive: true
}, () => {
this.updateFilteredOptions();
});
},
/**
* 处理输入框失去焦点事件
* 延迟200毫秒后隐藏下拉框并取消激活状态
*/
onBlur() {
setTimeout(() => {
this.setData({
dropdownVisible: false,
isActive: false
});
}, 200);
},
/**
* 切换下拉框的显示/隐藏状态
* 如果组件被禁用则不做任何操作
* 当下拉框显示时会触发更新过滤选项的操作
*/
toggleDropdown() {
console.log('Toggling dropdown'); // 调试日志
if (this.data.disabled) return;
this.setData({
dropdownVisible: !this.data.dropdownVisible,
isActive: !this.data.dropdownVisible
}, () => {
if (this.data.dropdownVisible) {
this.updateFilteredOptions();
}
});
},
/**
* 处理选择项事件
* @param {Object} e - 事件对象
* @param {Object} e.currentTarget.dataset - 事件目标数据
* @param {string} e.currentTarget.dataset.value - 选中项的值
* @param {Object} e.currentTarget.dataset.item - 选中项对象
* @param {string} e.currentTarget.dataset.item.label - 选中项的显示文本
* @fires change - 触发change事件,传递选中项的值和对象
*/
selectItem(e) {
const { value, item } = e.currentTarget.dataset;
this.setData({
value,
displayText: item.label,
searchText: item.label,
dropdownVisible: false,
isActive: false
});
this.triggerEvent('change', { value, item });
}
},
observers: {
// 监听options变化
'options': function() {
this.updateFilteredOptions();
this.updateDisplayText();
},
// 监听value变化
'value': function() {
this.updateDisplayText();
}
},
ready() {
this.updateFilteredOptions();
this.updateDisplayText();
}
});
<!-- filter-picker.wxml -->
<view class="filter-picker">
<!-- 输入框部分 -->
<view class="input-container" bindtap="toggleDropdown">
<input
class="picker-input"
placeholder="{{placeholder}}"
value="{{searchText}}"
bindinput="onInput"
bindfocus="onFocus"
bindblur="onBlur"
disabled="{{disabled}}"
/>
<view class="arrow-icon">
<image src="{{dropdownVisible ? '/images/arrow-up.png' : '/images/arrow-down.png'}}" />
</view>
</view>
<!-- 下拉选项部分 -->
<view class="dropdown-container" wx:if="{{dropdownVisible}}">
<scroll-view scroll-y class="dropdown-list" style="max-height: {{maxHeight}}px">
<block wx:for="{{filteredOptions}}" wx:key="key">
<view
class="dropdown-item {{item.value === value ? 'selected' : ''}}"
bindtap="selectItem"
data-value="{{item.value}}"
data-item="{{item}}"
>
{{item.label}}
</view>
</block>
<view wx:if="{{filteredOptions.length === 0}}" class="no-data">
无匹配数据
</view>
</scroll-view>
</view>
</view>
TypeError: null is not a function
at li.filter (<anonymous>)
at Function.o.safeCallback (VM1710 WASubContext.js:1)
at l.<anonymous> (VM1710 WASubContext.js:1)
at c.doUpdates (VM1710 WASubContext.js:1)
at Mn (VM1710 WASubContext.js:1)
at Yn (VM1710 WASubContext.js:1)
at Jn (VM1710 WASubContext.js:1)
at Jn (VM1710 WASubContext.js:1)
at Jn (VM1710 WASubContext.js:1)
at bo.createInstance (VM1710 WASubContext.js:1)(env: Windows,mp,1.06.2504010; lib: 3.8.10)
2TypeError: null is not a function
at li.filter (<anonymous>)
at Function.o.safeCallback (VM1710 WASubContext.js:1)
at l.<anonymous> (VM1710 WASubContext.js:1)
at c.doUpdates (VM1710 WASubContext.js:1)
at Mn (VM1710 WASubContext.js:1)
at Yn (VM1710 WASubContext.js:1)
at Jn (VM1710 WASubContext.js:1)
at Jn (VM1710 WASubContext.js:1)
at Jn (VM1710 WASubContext.js:1)
at bo.createInstance (VM1710 WASubContext.js:1)(env: Windows,mp,1.06.2504010; lib: 3.8.10)
TypeError: is not a function
at li.filter (<anonymous>)
at Function.o.safeCallback (VM1710 WASubContext.js:1)
at l.<anonymous> (VM1710 WASubContext.js:1)
at c.doUpdates (VM1710 WASubContext.js:1)
at Mn (VM1710 WASubContext.js:1)
at Yn (VM1710 WASubContext.js:1)
at Jn (VM1710 WASubContext.js:1)
at Jn (VM1710 WASubContext.js:1)
at Jn (VM1710 WASubContext.js:1)
at bo.createInstance (VM1710 WASubContext.js:1)(env: Windows,mp,1.06.2504010; lib: 3.8.10)
wx.getSystemInfo is deprecated.Please use wx.getSystemSetting/wx.getAppAuthorizeSetting/wx.getDeviceInfo/wx.getWindowInfo/wx.getAppBaseInfo instead.
(anonymous) @ safe-area.js? [sm]:8
getSafeArea @ safe-area.js? [sm]:3
created @ safe-area.js? [sm]:35
[Component] property "config" of "components/custom-form-modal/index" received type-uncompatible value: expected <Array> but got non-array value. Used empty array instead.
tianjia.js? [sm]:54 (9) [Proxy, Proxy, Proxy, Proxy, Proxy, Proxy, Proxy, Proxy, Proxy]0: Proxy {number: "2025-31", xiadan: "2025-06-28T00:00:00.000+00:00", jiaohuo: null, dingdan_chanpin: Array(0), id: 1, …}1: Proxy {number: "2025-33", xiadan: null, jiaohuo: null, dingdan_chanpin: Array(3), id: 2, …}2: Proxy {number: "2025-034", xiadan: "2025-07-01T00:00:00.000+00:00", jiaohuo: null, dingdan_chanpin: Array(5), id: 3, …}3: Proxy {number: "2025-034增加单", xiadan: "2025-07-02T00:00:00.000+00:00", jiaohuo: null, dingdan_chanpin: Array(1), id: 4, …}4: Proxy {number: "2025-031", xiadan: "2025-07-02T00:00:00.000+00:00", jiaohuo: null, dingdan_chanpin: Array(1), id: 5, …}5: Proxy {number: "2025-036", xiadan: "2025-06-13T00:00:00.000+00:00", jiaohuo: "2025-07-13T00:00:00.000+00:00", dingdan_chanpin: Array(2), id: 6, …}6: Proxy {number: "2025-037", xiadan: "2025-06-16T00:00:00.000+00:00", jiaohuo: "2025-07-16T00:00:00.000+00:00", dingdan_chanpin: Array(1), id: 7, …}7: Proxy {number: "2025-038", xiadan: "2025-06-17T00:00:00.000+00:00", jiaohuo: "2025-08-17T00:00:00.000+00:00", dingdan_chanpin: Array(1), id: 8, …}8: Proxy {number: "梦5", xiadan: "2025-07-03T00:00:00.000+00:00", jiaohuo: "2025-08-03T00:00:00.000+00:00", dingdan_chanpin: Array(1), id: 44, …}length: 9nv_length: (...)__proto__: Array(0)
TypeError: 1 is not a function
at li.filter (<anonymous>)
at Function.o.safeCallback (VM1710 WASubContext.js:1)
at l.<anonymous> (VM1710 WASubContext.js:1)
at c.doUpdates (VM1710 WASubContext.js:1)
at Mn (VM1710 WASubContext.js:1)
at no (VM1710 WASubContext.js:1)
at oo (VM1710 WASubContext.js:1)
at no (VM1710 WASubContext.js:1)
at oo (VM1710 WASubContext.js:1)
at no (VM1710 WASubContext.js:1)(env: Windows,mp,1.06.2504010; lib: 3.8.10)
最新发布