409 lines
9.7 KiB
Plaintext
409 lines
9.7 KiB
Plaintext
<script lang="ts">
|
|
import { PropType } from "vue"
|
|
import { getUid } from "../../core/util/xCoreUtil.uts"
|
|
import { checkIsCssUnit, rpx2px,getUnit } from "../../core/util/xCoreUtil.uts"
|
|
import { xConfig } from "../../config/xConfig.uts"
|
|
// import pickerItem from './picker-item.uvue'
|
|
import { X_PICKER_X_ITEM } from "../../interface.uts"
|
|
|
|
/**
|
|
* @name 选择容器子节点 xPickerViewItem
|
|
* @description xPickerView内部子组件,不可引用
|
|
* @page /pages/index/picker-view
|
|
* @category 表单组件
|
|
* @constant 平台兼容
|
|
* | Harmony | H5 | andriod | IOS | 小程序 | UTS | UNIAPP-X SDK | version |
|
|
| --- | --- | --- | --- | --- | --- | --- | --- |
|
|
| ☑ | ☑ | ☑️ | ☑️ | ☑️ | ☑️ | 4.76+ | 1.1.18 |
|
|
*/
|
|
export default {
|
|
// components: {
|
|
// 'picker-item': pickerItem
|
|
// },
|
|
data() {
|
|
return {
|
|
boxHeight: 0,
|
|
id: ('xPickerItem-' + getUid()) as string,
|
|
nowCurrentIndex: [0],
|
|
tid: 0,
|
|
tid2:0,
|
|
tid3:3,
|
|
}
|
|
},
|
|
emits: ['changeDeep', 'countChange'],
|
|
props: {
|
|
cellHeight: {
|
|
type: String,
|
|
default: '60'
|
|
},
|
|
duration: {
|
|
type: Number,
|
|
default: 350
|
|
},
|
|
list: {
|
|
type: Array as PropType<X_PICKER_X_ITEM[]>,
|
|
default: () : X_PICKER_X_ITEM[] => [] as X_PICKER_X_ITEM[]
|
|
},
|
|
wrapWight: {
|
|
type: Number,
|
|
default: 0
|
|
},
|
|
parentIndex: {
|
|
type: Number,
|
|
default: 0
|
|
},
|
|
selectedIndex: {
|
|
type: Array as PropType<number[]>,
|
|
default: () : number[] => [] as number[]
|
|
},
|
|
cellUnits: {
|
|
type: Array as PropType<string[]>,
|
|
default: () : string[] => [] as string[]
|
|
},
|
|
unitsFontSize:{
|
|
type:String,
|
|
default:'12'
|
|
},
|
|
fontSize: {
|
|
type: String,
|
|
default: "15"
|
|
}
|
|
},
|
|
mounted() {
|
|
let t = this;
|
|
this.pushDeepCount(this.parentIndex)
|
|
t.setNowCurrentIndex(false)
|
|
|
|
},
|
|
beforeUnmount() {
|
|
clearTimeout(this.tid)
|
|
clearTimeout(this.tid2)
|
|
clearTimeout(this.tid3)
|
|
},
|
|
computed: {
|
|
|
|
_fontSize() : string {
|
|
let fontSize = checkIsCssUnit(this.fontSize, xConfig.unit)
|
|
|
|
if(xConfig.fontScale==1) return fontSize;
|
|
let sizeNumber = parseInt(fontSize)
|
|
if(isNaN(sizeNumber)){
|
|
sizeNumber = 16
|
|
}
|
|
return (sizeNumber*xConfig.fontScale).toString() + getUnit(this.fontSize)
|
|
},
|
|
_parentIndex() : number {
|
|
return this.parentIndex
|
|
},
|
|
|
|
_cellHeight() : string {
|
|
return checkIsCssUnit(this.cellHeight, xConfig.unit)
|
|
},
|
|
_boxHeight() : number {
|
|
let p = parseInt(this.cellHeight);
|
|
if (this.cellHeight.lastIndexOf('rpx') > -1) {
|
|
p = rpx2px(p);
|
|
}
|
|
return p
|
|
},
|
|
|
|
_totalHeight() : number {
|
|
return (Math.max(1, this._list.length) + 4) * this._boxHeight
|
|
},
|
|
|
|
_wrapWight() : number {
|
|
return this.wrapWight
|
|
},
|
|
_selectedIndex() : number[] {
|
|
|
|
return this.selectedIndex
|
|
},
|
|
|
|
|
|
_unitsName() : string {
|
|
if (this.cellUnits.length == 0) return ""
|
|
if (this.cellUnits.length < this._parentIndex) return ""
|
|
return this.cellUnits[this._parentIndex]! as string
|
|
},
|
|
_cellUnits() : string[] {
|
|
return this.cellUnits as string[]
|
|
},
|
|
_list(): X_PICKER_X_ITEM[] {
|
|
return this.list
|
|
},
|
|
_nowChildren(): X_PICKER_X_ITEM[] {
|
|
if(this._list.length==0) return [] as X_PICKER_X_ITEM[]
|
|
let index = Math.max(0,Math.min(this.nowCurrentIndex[0],this._list.length-1))
|
|
let item = this._list[index];
|
|
|
|
return item.children
|
|
},
|
|
_isDark():boolean{
|
|
return xConfig.dark=='dark'
|
|
},
|
|
_maskStyle():string{
|
|
if(this._isDark){
|
|
|
|
return 'background-image:linear-gradient(180deg,rgba(0, 0, 0, 0),rgba(0, 0, 0, 0)),linear-gradient(0deg, rgba(0, 0, 0, 0),rgba(0, 0, 0, 0))'
|
|
}
|
|
return 'background-image:linear-gradient(180deg,rgba(255,255,255,0),rgba(255,255,255,0)),linear-gradient(0deg, rgba(255,255,255,0),rgba(255,255,255,0))'
|
|
}
|
|
},
|
|
watch: {
|
|
list(){
|
|
let t = this;
|
|
t.setNowCurrentIndex(true)
|
|
},
|
|
selectedIndex(newvaluse : number[]) {
|
|
let t = this;
|
|
t.setNowCurrentIndex(false)
|
|
}
|
|
},
|
|
methods: {
|
|
setNowCurrentIndex(isTmChange:boolean){
|
|
let t = this;
|
|
clearTimeout(this.tid3)
|
|
// #ifdef MP-WEIXIN
|
|
this.tid3 = setTimeout(function() {
|
|
t.nowCurrentIndex = [t.getIndexByid()] as number[]
|
|
if(isTmChange){
|
|
t.mchange(t.nowCurrentIndex)
|
|
}
|
|
}, 15);
|
|
// #endif
|
|
// #ifndef MP-WEIXIN
|
|
t.nowCurrentIndex = [t.getIndexByid()] as number[]
|
|
if(isTmChange){
|
|
t.mchange(t.nowCurrentIndex)
|
|
}
|
|
// #endif
|
|
},
|
|
getIndexByid():number{
|
|
let index = 0
|
|
|
|
if(this._selectedIndex.length==0) return index;
|
|
if(this.parentIndex>this._selectedIndex.length) return index
|
|
|
|
index = this._selectedIndex[this.parentIndex]
|
|
|
|
index = Math.max(0,Math.min(index,this._list.length-1))
|
|
return index;
|
|
},
|
|
getIdByindex():string|null{
|
|
let id = null;
|
|
if(this._list.length==0) return id
|
|
if(this.nowCurrentIndex.length==0) return id;
|
|
let index = Math.max(0,Math.min(this.nowCurrentIndex[0],this._list.length-1))
|
|
return this._list[index].id
|
|
|
|
},
|
|
mchange(indexs : number[]) {
|
|
|
|
let index = indexs[0];
|
|
let parentIndex = this.parentIndex;
|
|
let ids = this._selectedIndex.slice(0)
|
|
|
|
|
|
|
|
if(parentIndex<=ids.length-1){
|
|
ids.splice(parentIndex,1,index)
|
|
}else{
|
|
for(let i=0;i<this.parentIndex;i++){
|
|
ids.push(0)
|
|
}
|
|
ids.push(index)
|
|
|
|
}
|
|
|
|
this.$emit("changeDeep", ids)
|
|
},
|
|
change(s : number[]) {
|
|
this.$emit("changeDeep", s)
|
|
},
|
|
|
|
pushDeepCount(n:number){
|
|
|
|
this.$emit("countChange", n)
|
|
},
|
|
onChange(event : UniPickerViewChangeEvent) {
|
|
if (event.detail.value.length == 0 || this._list.length==0) return;
|
|
let indexs = event.detail.value!;
|
|
if (indexs.join('') == this.nowCurrentIndex.join('')) return;
|
|
let index = indexs[0]
|
|
index = Math.max(0,Math.min(index,this._list.length-1))
|
|
let item = this._list[index]
|
|
if (item.disabled) {
|
|
// 寻找最近的未禁用项
|
|
let left = index - 1
|
|
let right = index + 1
|
|
let found = -1
|
|
while (left >= 0 || right < this._list.length) {
|
|
if (left >= 0 && !this._list[left].disabled) { found = left; break }
|
|
if (right < this._list.length && !this._list[right].disabled) { found = right; break }
|
|
left -= 1
|
|
right += 1
|
|
}
|
|
if (found >= 0) {
|
|
index = found
|
|
indexs = [index]
|
|
} else {
|
|
// 全部禁用,回退到0
|
|
index = 0
|
|
indexs = [0]
|
|
}
|
|
}
|
|
this.nowCurrentIndex = indexs;
|
|
|
|
this.mchange(indexs)
|
|
}
|
|
|
|
|
|
|
|
},
|
|
}
|
|
</script>
|
|
<template>
|
|
<view>
|
|
<view class="xPickerViewUnit" v-if="_unitsName!=''">
|
|
<x-text :font-size="unitsFontSize" class="xPickerViewUnitText">{{_unitsName}}</x-text>
|
|
</view>
|
|
<view class="xPickerView">
|
|
<view style="padding: 0 2.5px;">
|
|
<picker-view :value="nowCurrentIndex" @change="onChange"
|
|
:style="{height:'250px',width:(_wrapWight-5)+'px'}"
|
|
:mask-style="`${_maskStyle}`"
|
|
:mask-bottom-style="_maskStyle"
|
|
:mask-top-style="_maskStyle"
|
|
:indicator-class="_isDark?'indicatorClassDark':'indicatorClassLight'"
|
|
:indicator-style="`height:50px;backgroundColor:${_isDark?'rgba(255,255,255,0.05)':'rgba(0,0,0,0.05)'};border-radius:10px`">
|
|
<picker-view-column>
|
|
<view :style="{height:'50px'}" v-for="(item,index) in _list" :key="index"
|
|
class="xPickerViewWrapCoumn">
|
|
<text class="xPickerViewWrapCoumnText" :style="{
|
|
fontSize:_fontSize,
|
|
lineHeight: 1.1,
|
|
fontWeight:nowCurrentIndex[0]==index?'bold':'inherit',
|
|
opacity:item.disabled?0.4:(nowCurrentIndex[0]==index?1:0.6),
|
|
color: _isDark?'rgba(255,255,255,0.8)':'#000000'}">
|
|
{{item.title}}
|
|
</text>
|
|
</view>
|
|
</picker-view-column>
|
|
</picker-view>
|
|
|
|
</view>
|
|
|
|
<x-picker-item @countChange="pushDeepCount" :font-size="fontSize" :cellUnits="_cellUnits" @changeDeep="change" :selectedIndex="_selectedIndex"
|
|
:wrapWight="_wrapWight" :parentIndex="_parentIndex+1" v-if="_nowChildren.length>0" :list="_nowChildren"
|
|
:cell-height="_cellHeight">
|
|
</x-picker-item>
|
|
</view>
|
|
</view>
|
|
|
|
|
|
</template>
|
|
<style>
|
|
/* #ifdef WEB */
|
|
.uni-picker-view-indicator:after,
|
|
.uni-picker-view-indicator:before {
|
|
border: none;
|
|
}
|
|
|
|
/* #endif */
|
|
/* #ifdef MP-WEIXIN */
|
|
.indicatorClassDark:after,
|
|
.indicatorClassDark:before,
|
|
.indicatorClassLight:after,
|
|
.indicatorClassLight:before {
|
|
content:'';
|
|
height: 0px;
|
|
width: 100%;
|
|
border-color: transparent;
|
|
}
|
|
.indicatorClassDark{
|
|
background-color: rgba(255,255,255,0.05);
|
|
}
|
|
.indicatorClassLight{
|
|
background-color: rgba(0,0,0,0.05);
|
|
}
|
|
/* #endif */
|
|
.xPickerViewUnit {
|
|
display: flex;
|
|
flex-direction: row;
|
|
justify-content: center;
|
|
padding: 8px;
|
|
}
|
|
|
|
.xPickerViewUnitText {
|
|
font-size: 12px;
|
|
color: #888;
|
|
font-weight: bold;
|
|
}
|
|
|
|
.xPickerViewWrapCoumnText {
|
|
margin:0 6px;
|
|
width: 100%;
|
|
text-align: center;
|
|
/* lines: 2; */
|
|
/* #ifdef WEB */
|
|
display: -webkit-box;
|
|
-webkit-line-clamp: 2;
|
|
-webkit-box-orient: vertical;
|
|
text-overflow: ellipsis;
|
|
overflow: hidden;
|
|
word-break: break-all;
|
|
/* #endif */
|
|
}
|
|
|
|
.xPickerView {
|
|
display: flex;
|
|
flex-direction: row;
|
|
}
|
|
|
|
.xPickerViewWrap {
|
|
position: relative;
|
|
}
|
|
|
|
.xPickerContent {
|
|
position: absolute;
|
|
left: 0;
|
|
top: 0;
|
|
width: 100%;
|
|
z-index: 5;
|
|
}
|
|
|
|
.xPickerMasker {
|
|
display: flex;
|
|
flex-direction: row;
|
|
align-items: center;
|
|
justify-content: center;
|
|
pointer-events: none;
|
|
height: 100%;
|
|
width: 100%;
|
|
top: 0px;
|
|
left: 0px;
|
|
position: absolute;
|
|
}
|
|
|
|
.xPickErBar {
|
|
background-color: #f5f5f5;
|
|
border-radius: 10px;
|
|
margin: 0 3px;
|
|
flex: 1;
|
|
|
|
}
|
|
|
|
.xPickerContent {
|
|
transition-duration: 350ms;
|
|
transition-property: left, right, top, bottom;
|
|
transition-timing-function: cubic-bezier(0, 0.55, 0.45, 1);
|
|
}
|
|
|
|
.xPickerViewWrapCoumn {
|
|
display: flex;
|
|
flex-direction: column;
|
|
justify-content: center;
|
|
align-items: center;
|
|
/* background-color: #f5f5f5; */
|
|
}
|
|
</style> |