Files
miniprogram-picker/src/index.js

353 lines
10 KiB
JavaScript
Raw Normal View History

2018-12-12 14:52:37 +08:00
Component({
2018-12-12 20:43:54 +08:00
/**
* 组件的属性列表
*/
2018-12-12 14:52:37 +08:00
properties: {
// 初始化时,是否需要自动返回结果给开发者
2018-12-12 20:43:54 +08:00
autoSelect: {
type: Boolean,
value: false
},
2018-12-13 15:26:03 +08:00
// 源数组sourceData有几维Picker就可以有几阶
2018-12-12 20:43:54 +08:00
sourceData: {
type: Array,
value: [],
observer: 'sourceDataChange'
},
// 阶数
steps: {
type: Number,
2018-12-14 11:48:17 +08:00
value: 1
2018-12-12 20:43:54 +08:00
},
// 展示数据的字段名称
shownFieldName: {
2018-12-12 14:52:37 +08:00
type: String,
2018-12-12 20:43:54 +08:00
value: 'name'
},
// 子节点名称,
subsetFieldName: {
type: String,
value: 'subset'
},
// 其他需要返回的字段
otherNeedFieldsName: {
type: Array,
value: []
2018-12-12 14:52:37 +08:00
},
2018-12-13 17:55:45 +08:00
// 选择了第n列后是否将大于n的列的选择值自动初始化为0
initColumnSelectedIndex: {
type: Boolean,
value: false,
},
// 默认选中项的下标数组
defaultIndex: {
type: Array,
value: []
},
// 默认选中项的值数组
defaultValue: {
type: Array,
value: []
},
// 默认选中项的值数组的唯一字段,用来和源数组进行比对
defaultValueUniqueField: {
type: String,
value: ''
2018-12-13 17:55:45 +08:00
}
2018-12-12 14:52:37 +08:00
},
2018-12-12 20:43:54 +08:00
/**
* 组件的初始数据
*/
2018-12-12 14:52:37 +08:00
data: {
2018-12-13 15:26:03 +08:00
// Picker当前所选择的索引数组 => 比如:[0, 0, 2]表示第一列选择第0项第二列选择第0项第三列选择第2项。
2018-12-12 20:43:54 +08:00
multiIndex: {
type: Array,
value: [],
},
2018-12-13 15:26:03 +08:00
// Picker当前所展示的数组 => 比如:[['河北', '山东'], ['石家庄', '保定'], ['桥西区', '裕华区', '长安区']]。
2018-12-12 20:43:54 +08:00
multiArray: {
type: Array,
value: [],
},
// 用户点击确定后,所选择的值数组 => 比如:
2018-12-13 15:26:03 +08:00
// [{name: '河北', id: '3110'}, {name: '石家庄', id: '3110xx'}, {name: '长安区', id: '3110xxx'}]。
2018-12-12 20:43:54 +08:00
selectedArray: {
type: Array,
value: [],
},
2018-12-12 14:52:37 +08:00
},
2018-12-12 20:43:54 +08:00
/**
* 组件的方法列表
*/
methods: {
/**
2018-12-13 15:26:03 +08:00
* 监听源数组更新变化
2018-12-13 17:55:45 +08:00
*
2018-12-13 15:26:03 +08:00
* @param {Array} newSourceData 源数组newSourceData有几维Picker就可以有几阶
2018-12-12 20:43:54 +08:00
*/
2018-12-13 15:26:03 +08:00
sourceDataChange(newSourceData) {
const { shownFieldName, subsetFieldName, steps } = this.data
// 源数组更新则需要更新multiIndex、multiArray
2018-12-12 20:43:54 +08:00
const multiIndex = []
const multiArray = []
2018-12-13 15:26:03 +08:00
const { countError } = this.checkSourceData(newSourceData)
if (countError > 0) {
console.warn(`miniprogram-picker: 检测到源数组中有${countError}个错误,为了方便排查修改已经为你做出了相关提示,请修改后再试,务必保证数据源的数据结构无误。`)
2018-12-13 15:26:03 +08:00
}
const defaultIndex = this.getDefaultIndex(newSourceData)
2018-12-13 15:26:03 +08:00
const handle = (source = [], columnIndex = 0) => {
// 当前遍历Picker的第columnIndex列
// 当columnIndex = 0时source表示sourceData其它则表示子集subset
const _multiArrayColumn0 = []
2018-12-12 20:43:54 +08:00
2018-12-13 15:26:03 +08:00
source.forEach((item, index) => {
if (columnIndex === 0) {
// newSourceData的第0维要单独处理最后unshift到multiArray中
_multiArrayColumn0.push(item[shownFieldName])
}
2018-12-12 20:43:54 +08:00
if (item[shownFieldName] && index === (defaultIndex[columnIndex] || 0)) {
2018-12-12 20:43:54 +08:00
// 选中的索引和值默认取每列的第0个
multiIndex.push(index)
2018-12-13 15:26:03 +08:00
if (columnIndex < steps - 1) {
2018-12-12 20:43:54 +08:00
if (item[subsetFieldName]) {
2018-12-13 15:26:03 +08:00
// 开始处理下一维的数据
const _subsetArr = item[subsetFieldName].map(sub => sub[shownFieldName])
multiArray.push(_subsetArr)
handle(item[subsetFieldName], columnIndex + 1)
2018-12-12 20:43:54 +08:00
}
}
}
})
2018-12-13 15:26:03 +08:00
if (columnIndex === 0) {
multiArray.unshift(_multiArrayColumn0)
}
2018-12-12 20:43:54 +08:00
}
2018-12-13 15:26:03 +08:00
handle(newSourceData)
2018-12-12 20:43:54 +08:00
this.setData({
multiIndex,
multiArray
})
},
getDefaultIndex(newSourceData) {
const {
defaultIndex,
defaultValue,
defaultValueUniqueField,
steps,
subsetFieldName
} = this.data
if (defaultIndex.length) {
return defaultIndex
} else if (defaultValue.length) {
if (!defaultValueUniqueField) {
console.error(new Error('你设置了"defaultValue"字段, 但是没有设置defaultValueUniqueField这将无法识别默认选项请补充后再试。'))
}
const _defaultIndex = []
const handle = (source = [], columnIndex = 0) => {
// 默认值
_defaultIndex[columnIndex] = 0
// 若是有报错则Interrupt为true将中断
let Interrupt = false
source.forEach((item, index) => {
if (!item[defaultValueUniqueField]) {
Interrupt = true
console.error(item, new Error(`源数组第${columnIndex}维(从0开始计算)的对象中缺少"${defaultValueUniqueField}"字段`))
} else {
defaultValue.forEach((def, key) => {
if (!def[defaultValueUniqueField]) {
Interrupt = true
console.error(def, new Error(`"defaultValue"中第${key}项(从0开始计算)的对象中缺少"${defaultValueUniqueField}"字段`))
}
if (!Interrupt &&
(def[defaultValueUniqueField] === item[defaultValueUniqueField])) {
// 相等则表示选中
_defaultIndex[columnIndex] = index
}
})
if (columnIndex < steps - 1) {
if (item[subsetFieldName]) {
// 开始处理下一维的数据
handle(item[subsetFieldName], columnIndex + 1)
}
}
}
})
}
handle(newSourceData)
return _defaultIndex
} else {
return []
}
},
2018-12-13 17:55:45 +08:00
2018-12-13 15:26:03 +08:00
/**
* 校验源数组是否正确
2018-12-13 17:55:45 +08:00
*
2018-12-13 15:26:03 +08:00
* @param {Array} sourceData 源数组
*/
checkSourceData(sourceData) {
const { shownFieldName, subsetFieldName, steps } = this.data
let countError = 0
const handle = (source = [], columnIndex = 0) => {
// 当前遍历Picker的第columnIndex列
// 当columnIndex = 0时source表示sourceData其它则表示子集subset
source.forEach((item) => {
if (!item[shownFieldName]) {
countError++
console.error(item, new Error(`源数组第${columnIndex}维(从0开始计算)的对象中缺少"${shownFieldName}"字段`))
}
if (item[shownFieldName]) {
// 有shownFieldName字段才会去遍历subsetFieldName字段
if (columnIndex < steps - 1) {
if (item[subsetFieldName]) {
// 开始处理下一维的数据
handle(item[subsetFieldName], columnIndex + 1)
} else {
countError++
console.error(item, new Error(`源数组第${columnIndex}维(从0开始计算)的对象中缺少"${subsetFieldName}"字段`))
}
}
}
})
}
handle(sourceData)
return { countError }
},
2018-12-13 17:55:45 +08:00
/**
* 用户点击了确认
*
* @param {Object} e 事件对象具体参考微信小程序api
* @param {Array} e.detail.value 用户选择的下标数组
*/
pickerChange(e) {
2018-12-12 20:43:54 +08:00
console.log('picker发送选择改变携带值为', e.detail.value)
this.setData({
multiIndex: e.detail.value
})
2018-12-13 17:55:45 +08:00
this.processData()
2018-12-12 20:43:54 +08:00
},
2018-12-13 17:55:45 +08:00
/**
* 处理最终数据将返回给开发者
*
*/
processData() {
const {
sourceData,
shownFieldName,
subsetFieldName,
otherNeedFieldsName,
multiIndex
} = this.data
2018-12-12 20:43:54 +08:00
const selectedArray = []
2018-12-13 17:55:45 +08:00
const handle = (source = [], columnIndex = 0) => {
source.forEach((item, index) => {
if (index === multiIndex[columnIndex]) {
2018-12-12 20:43:54 +08:00
const selectedItem = {}
selectedItem[shownFieldName] = item[shownFieldName]
otherNeedFieldsName.forEach(key => {
selectedItem[key] = item[key]
})
selectedArray.push(selectedItem)
if (columnIndex < this.data.steps - 1) {
handle(item[subsetFieldName], columnIndex + 1)
}
}
})
}
2018-12-13 17:55:45 +08:00
handle(sourceData)
2018-12-12 20:43:54 +08:00
this.setData({
selectedArray
})
const detail = {
2018-12-13 17:55:45 +08:00
selectedIndex: this.data.multiIndex,
2018-12-12 20:43:54 +08:00
selectedArray: this.data.selectedArray
}
this.triggerEvent('change', detail)
},
2018-12-13 17:55:45 +08:00
/**
* 用户滚动了某一列
*
* @param {Object} e 事件对象具体参考微信小程序api
*/
pickerColumnChange(e) {
2018-12-13 15:26:03 +08:00
const {
shownFieldName,
subsetFieldName,
multiArray,
sourceData,
2018-12-13 17:55:45 +08:00
steps,
initColumnSelectedIndex
2018-12-13 15:26:03 +08:00
} = this.data
2018-12-13 17:55:45 +08:00
let { multiIndex } = this.data
2018-12-13 15:26:03 +08:00
const { column, value: changeIndex } = e.detail
2018-12-12 20:43:54 +08:00
2018-12-13 15:26:03 +08:00
console.log(`修改了Picker的第${column}列(从0开始计算),选中了第${changeIndex}个值(从0开始计算)`)
2018-12-12 20:43:54 +08:00
// multiIndex变化了所以也要同步更新multiArray
2018-12-13 15:26:03 +08:00
multiIndex[column] = changeIndex
2018-12-12 20:43:54 +08:00
2018-12-13 17:55:45 +08:00
if (initColumnSelectedIndex) {
// 每次重置之后的index为0但是有bug待定。 => 经检查,是编辑器的问题,真机上是没有问题的。
const _multiIndex = multiIndex.map((item, index) => {
if (column >= index) {
return item
} else {
return 0
}
})
multiIndex = _multiIndex
}
2018-12-12 20:43:54 +08:00
2018-12-13 15:26:03 +08:00
const handle = (source = [], columnIndex = 0) => {
2018-12-12 20:43:54 +08:00
// 当前遍历第 columnIndex 列
2018-12-13 15:26:03 +08:00
source.forEach((item, index) => {
if (index === multiIndex[columnIndex]) {
if (columnIndex < steps - 1) {
2018-12-12 20:43:54 +08:00
if (!item[subsetFieldName]) {
item[subsetFieldName] = []
}
2018-12-13 15:26:03 +08:00
const multiArrayItem = item[subsetFieldName].map((sub) => sub[shownFieldName])
// 从第1列开始才有可能变化
multiArray[columnIndex + 1] = multiArrayItem
2018-12-12 20:43:54 +08:00
handle(item[subsetFieldName], columnIndex + 1)
}
}
})
}
2018-12-13 15:26:03 +08:00
handle(sourceData)
2018-12-12 20:43:54 +08:00
this.setData({
2018-12-13 15:26:03 +08:00
multiArray,
multiIndex,
2018-12-12 20:43:54 +08:00
})
},
},
lifetimes: {
attached() {
if (this.data.autoSelect) {
2018-12-13 17:55:45 +08:00
this.processData()
2018-12-12 20:43:54 +08:00
}
2018-12-12 14:52:37 +08:00
}
}
})