wx-mini-weview
Version:
weixin UI
430 lines (361 loc) • 12.5 kB
JavaScript
const { WvInheritable } = require('../../behaviors/WvInheritable');
Component({
options: {
styleIsolation: 'apply-shared',
addGlobalClass: true,
multipleSlots: false
},
behaviors: [
WvInheritable({
properties: {},
childrenProperties: {
selectorItems: {
// Add index property like in tag component
index: {
type: Number,
value: -1
},
// 选择项的值
value: {
type: null,
value: null
},
// 是否禁用
disabled: {
type: Boolean,
value: false
},
// 选中时应用的主题
theme: {
type: String,
value: 'wv-theme-primary wv-content-light'
},
// 是否选中
selected: {
type: Boolean,
value: false
},
// 选中状态的表现形式: 'scale', 'border', 'none'
selectionType: {
type: String,
value: 'none'
},
// 是否显示选中状态的勾选标记
checkmark: {
type: Boolean,
value: true
},
// 勾选标记的位置
checkmarkPosition: {
type: String,
value: 'top-right'
},
// 勾选标记的尺寸
checkmarkSize: {
type: String,
value: '60rpx'
},
// 选中时的缩放大小
scaleSize: {
type: String,
value: '1.06'
}
}
}
})
],
relations: {
'../selector-item/selector-item': {
type: 'child',
linked(target) {
// Use WvInheritable method to register child node
this.linkChildNode('selectorItems', target);
// Assign indices
this._assignItemIndices();
// Update item states
this._updateValue(this.data.value);
},
linkChanged() {
this._updateValue(this.data.value);
},
unlinked(target) {
// Use WvInheritable method to unregister child node
this.unlinkChildNode('selectorItems', target);
// Reassign indices
this._assignItemIndices();
// Update item states
this._updateValue(this.data.value);
}
}
},
properties: {
// External class
extClass: {
type: String,
value: ''
},
// Selection mode: 'single' or 'multiple'
mode: {
type: String,
value: 'single'
},
// Selected value(s)
value: {
type: null,
value: null,
observer(newVal) {
this._updateValue(newVal);
}
},
// Maximum number of selections (for multiple mode)
max: {
type: Number,
value: 0 // 0 means no limit
},
// Disable the selector
disabled: {
type: Boolean,
value: false
}
},
data: {
indexToValueMap: {}, // Maps indices to values
valueToIndexMap: {} // Maps values to indices
},
lifetimes: {
attached() {
// Component initialization
},
ready() {
// Initialize with default value
this._updateValue(this.data.value);
}
},
methods: {
/**
* Assign indices to all selector items
* @private
*/
_assignItemIndices() {
const items = this.getChildrenNodes('selectorItems');
if (!items || !items.length) return;
const indexToValueMap = {};
const valueToIndexMap = {};
items.forEach((item, idx) => {
item.setInheritedProps({ index: idx });
// Map item value to index
const itemValue = item.data.wvInheritableApply.value;
indexToValueMap[idx] = itemValue;
if (itemValue !== undefined && itemValue !== null) {
valueToIndexMap[itemValue] = idx;
}
});
// Update component data mappings
this.setData({
indexToValueMap,
valueToIndexMap
});
},
/**
* Update value and sync items state
* @param {Any} newVal - The new value (can be mixed type array like ["A", "B", 2])
*/
_updateValue(newVal) {
let value;
value = Array.isArray(newVal) ? newVal : [newVal];
this.setData({ value }, () => {
const items = this.getChildrenNodes('selectorItems');
if (!items || !items.length) return;
items.forEach(item => {
const itemIndex = item.data.wvInheritableApply.index;
const itemValue = item.data.wvInheritableApply.value;
let isSelected = false;
if(value.includes(itemIndex) || value.includes(itemValue)) {
isSelected = true;
}
item.setInheritedProps({ selected: isSelected });
});
this.triggerEvent('change', { value: this.data.value });
});
},
/**
* Toggle selection state
* @param {Any} valuesToToggle - Values to toggle (single value or array)
*/
toggle(valuesToToggle) {
if (this.data.disabled) return;
const itemsToToggle = Array.isArray(valuesToToggle) ? valuesToToggle : [valuesToToggle];
if (itemsToToggle.length === 0) return;
// Special handling for single mode
if (this.properties.mode === 'single') {
const item = itemsToToggle[0];
const selectorItem = typeof item === 'number' ? this.getItemByIndex(item) : this.getItemByValue(item);
if (!selectorItem) return;
const itemIndex = selectorItem.data.wvInheritableApply.index;
const itemValue = selectorItem.data.wvInheritableApply.value;
// Check if already selected
const currentValue = this.data.value;
const isSelected = currentValue === itemIndex || currentValue === itemValue;
// If selected, deselect; otherwise select new item
this._updateValue(isSelected ? null : (itemValue !== null ? itemValue : itemIndex));
return;
}
// Multiple mode
let newValues = Array.isArray(this.data.value) ? [...this.data.value] : [];
// Process each toggle item
itemsToToggle.forEach(item => {
const selectorItem = typeof item === 'number' ? this.getItemByIndex(item) : this.getItemByValue(item);
if (!selectorItem || selectorItem.data.wvInheritableApply.disabled) return;
const itemIndex = selectorItem.data.wvInheritableApply.index;
const itemValue = selectorItem.data.wvInheritableApply.value;
const isSelected = newValues.includes(itemIndex) || newValues.includes(itemValue);
if (isSelected) {
newValues = newValues.filter(val => val !== itemIndex && val !== itemValue);
} else {
if (this.properties.max > 0 && newValues.length >= this.properties.max) {
return;
}
// Prefer value, fallback to index
const valueToAdd = itemValue !== null && itemValue !== undefined ? itemValue : itemIndex;
newValues.push(valueToAdd);
}
});
this._updateValue(newValues);
},
/**
* Select items
* @param {Any} value - Values to select (single value or array)
*/
select(value) {
let newVal;
newVal = Array.isArray(value) ? value : [value];
if(newVal.length === 0) return;
if (this.properties.mode === 'single') {
newVal = newVal[0];
}
this._updateValue(newVal);
},
/**
* Unselect items
* @param {Any} valuesToUnselect - Values to unselect (single value or array)
*/
unselect(valuesToUnselect) {
const itemsToUnselect = Array.isArray(valuesToUnselect) ? valuesToUnselect : [valuesToUnselect];
if (itemsToUnselect.length === 0) return;
// Special handling for single mode
if (this.properties.mode === 'single') {
const currentValue = this.data.value;
if (currentValue === null) return;
// Check if current selection is in unselect list
for (const item of itemsToUnselect) {
const selectorItem = typeof item === 'number' ? this.getItemByIndex(item) : this.getItemByValue(item);
if (!selectorItem) continue;
const itemIndex = selectorItem.data.wvInheritableApply.index;
const itemValue = selectorItem.data.wvInheritableApply.value;
if (currentValue === itemIndex || currentValue === itemValue) {
this._updateValue(null);
return;
}
}
return;
}
// Multiple mode
if (!Array.isArray(this.data.value) || this.data.value.length === 0) return;
let newValues = [...this.data.value];
// Remove each unselect item
itemsToUnselect.forEach(item => {
const selectorItem = typeof item === 'number' ? this.getItemByIndex(item) : this.getItemByValue(item);
if (!selectorItem) return;
const itemIndex = selectorItem.data.wvInheritableApply.index;
const itemValue = selectorItem.data.wvInheritableApply.value;
// Remove both index and value from array
newValues = newValues.filter(val => val !== itemIndex && val !== itemValue);
});
// Only update if changed
if (newValues.length !== this.data.value.length) {
this._updateValue(newValues);
}
},
/**
* Clear all selections
*/
clear() {
const emptyValue = this.properties.mode === 'single' ? null : [];
this._updateValue(emptyValue);
},
/**
* Select all available items
*/
selectAll() {
if (this.properties.mode === 'single') return;
const items = this.getChildrenNodes('selectorItems');
if (!items || !items.length) return;
const indices = items
.filter(item => !item.data.wvInheritableApply.disabled)
.map(item => item.data.wvInheritableApply.index);
this._updateValue(indices);
},
/**
* Get item by index
* @param {Number} index - Item index
* @return {Object|null} Item component instance
*/
getItemByIndex(index) {
const items = this.getChildrenNodes('selectorItems');
if (!items || !items.length || typeof index !== 'number') return null;
return items.find(item => item.data.wvInheritableApply.index === index) || null;
},
/**
* Get item by value
* @param {Any} value - Item value
* @return {Object|null} Item component instance
*/
getItemByValue(value) {
const items = this.getChildrenNodes('selectorItems');
if (!items || !items.length) return null;
return items.find(item => item.data.wvInheritableApply.value === value) || null;
},
/**
* Get currently selected items
* @return {Array} Selected items array
*/
getSelectedItems() {
const items = this.getChildrenNodes('selectorItems');
if (!items || !items.length) return [];
const currentValue = this.data.value;
const selectedItems = [];
items.forEach(item => {
const itemIndex = item.data.wvInheritableApply.index;
const itemValue = item.data.wvInheritableApply.value;
let isSelected = false;
if (Array.isArray(currentValue)) {
// Array: match any index or value
isSelected = currentValue.some(val => {
if (typeof val === 'number') {
return val === itemIndex;
} else {
return val === itemValue;
}
});
} else if (typeof currentValue === 'number') {
// Single number: match index
isSelected = (itemIndex === currentValue);
} else if (currentValue !== null && currentValue !== undefined) {
// Other single value: match value
isSelected = (itemValue === currentValue);
}
if (isSelected) {
selectedItems.push(item);
}
});
return selectedItems;
},
/**
* Get selected values
* @return {Any} Current value
*/
getValue() {
return this.data.value;
}
}
});