mirror of
https://gitee.com/wot-design-uni/wot-design-uni.git
synced 2025-12-06 09:08:51 +08:00
feat: ✨ Picker组件优化性能
This commit is contained in:
parent
09c75d4878
commit
24dd43f3a0
@ -222,7 +222,7 @@ function handleChange({ value }) {
|
||||
|
||||
| 参数 | 说明 | 类型 | 可选值 | 默认值 | 最低版本 |
|
||||
| ----------------- | ---------------------------------------------------------------------- | --------------------- | ------------------------------------------------------------------------------------------- | --------------------- | -------- |
|
||||
| v-model | 选中值,为 13 位时间戳或时间戳数组 | null / number / array | - | - | - |
|
||||
| v-model | 选中值,为 13 位时间戳或时间戳数组 | null / number / array | - | - | - |
|
||||
| type | 日期类型 | string | date / dates / datetime / week / month / daterange / datetimerange / weekrange / monthrange | date | - |
|
||||
| min-date | 最小日期,为 13 位时间戳 | number | - | 当前日期往前推 6 个月 | - |
|
||||
| max-date | 最大日期,为 13 位时间戳 | number | - | 当前日期往后推 6 个月 | - |
|
||||
@ -239,15 +239,15 @@ function handleChange({ value }) {
|
||||
|
||||
## Events
|
||||
|
||||
| 事件名称 | 说明 | 参数 | 最低版本 |
|
||||
| -------- | ---------------- | ------------------------ | -------- |
|
||||
| 事件名称 | 说明 | 参数 | 最低版本 |
|
||||
| -------- | ---------------- | ----------- | -------- |
|
||||
| change | 绑定值变化时触发 | `{ value }` | - |
|
||||
|
||||
## Methods
|
||||
|
||||
| 方法名称 | 说明 | 参数 | 最低版本 |
|
||||
| -------------- | ------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------- | -------- |
|
||||
| scrollIntoView | 使当前日期或者选中日期滚动到可视区域,并监听滚动,在面板从 隐藏状态(如 display: none) 切换为展示状态时调用 | thresholds,数字数组,具体使用见 [Intersection Observer](https://developer.mozilla.org/zh-CN/docs/Web/API/IntersectionObserver) | - |
|
||||
| 方法名称 | 说明 | 参数 | 最低版本 |
|
||||
| -------------- | ------------------------------------------------------------------------------------------------------------ | ---- | -------- |
|
||||
| scrollIntoView | 使当前日期或者选中日期滚动到可视区域,并监听滚动,在面板从 隐藏状态(如 display: none) 切换为展示状态时调用 | - |
|
||||
|
||||
## 外部样式类
|
||||
|
||||
|
||||
35
package.json
35
package.json
@ -52,19 +52,20 @@
|
||||
"upload:mp-dingtalk": "uni build -p mp-dingtalk && minici --platform dd"
|
||||
},
|
||||
"dependencies": {
|
||||
"@dcloudio/uni-app": "3.0.0-alpha-3080220230511001",
|
||||
"@dcloudio/uni-app-plus": "3.0.0-alpha-3080220230511001",
|
||||
"@dcloudio/uni-components": "3.0.0-alpha-3080220230511001",
|
||||
"@dcloudio/uni-h5": "3.0.0-alpha-3080220230511001",
|
||||
"@dcloudio/uni-mp-alipay": "3.0.0-alpha-3080220230511001",
|
||||
"@dcloudio/uni-mp-baidu": "3.0.0-alpha-3080220230511001",
|
||||
"@dcloudio/uni-mp-jd": "3.0.0-alpha-3080220230511001",
|
||||
"@dcloudio/uni-mp-kuaishou": "3.0.0-alpha-3080220230511001",
|
||||
"@dcloudio/uni-mp-lark": "3.0.0-alpha-3080220230511001",
|
||||
"@dcloudio/uni-mp-qq": "3.0.0-alpha-3080220230511001",
|
||||
"@dcloudio/uni-mp-toutiao": "3.0.0-alpha-3080220230511001",
|
||||
"@dcloudio/uni-mp-weixin": "3.0.0-alpha-3080220230511001",
|
||||
"@dcloudio/uni-quickapp-webview": "3.0.0-alpha-3080220230511001",
|
||||
"@dcloudio/uni-app": "3.0.0-alpha-3081220230802001",
|
||||
"@dcloudio/uni-app-plus": "3.0.0-alpha-3081220230802001",
|
||||
"@dcloudio/uni-components": "3.0.0-alpha-3081220230802001",
|
||||
"@dcloudio/uni-h5": "3.0.0-alpha-3081220230802001",
|
||||
"@dcloudio/uni-mp-alipay": "3.0.0-alpha-3081220230802001",
|
||||
"@dcloudio/uni-mp-baidu": "3.0.0-alpha-3081220230802001",
|
||||
"@dcloudio/uni-mp-jd": "3.0.0-alpha-3081220230802001",
|
||||
"@dcloudio/uni-mp-kuaishou": "3.0.0-alpha-3081220230802001",
|
||||
"@dcloudio/uni-mp-lark": "3.0.0-alpha-3081220230802001",
|
||||
"@dcloudio/uni-mp-qq": "3.0.0-alpha-3081220230802001",
|
||||
"@dcloudio/uni-mp-toutiao": "3.0.0-alpha-3081220230802001",
|
||||
"@dcloudio/uni-mp-weixin": "3.0.0-alpha-3081220230802001",
|
||||
"@dcloudio/uni-mp-xhs": "3.0.0-alpha-3081220230802001",
|
||||
"@dcloudio/uni-quickapp-webview": "3.0.0-alpha-3081220230802001",
|
||||
"vitepress": "^1.0.0-beta.6",
|
||||
"vue": "^3.2.45",
|
||||
"vue-i18n": "^9.1.9"
|
||||
@ -73,10 +74,10 @@
|
||||
"@commitlint/cli": "^17.4.4",
|
||||
"@commitlint/config-conventional": "^17.4.4",
|
||||
"@dcloudio/types": "^3.3.2",
|
||||
"@dcloudio/uni-automator": "3.0.0-alpha-3080220230511001",
|
||||
"@dcloudio/uni-cli-shared": "3.0.0-alpha-3080220230511001",
|
||||
"@dcloudio/uni-stacktracey": "3.0.0-alpha-3080220230511001",
|
||||
"@dcloudio/vite-plugin-uni": "3.0.0-alpha-3080220230511001",
|
||||
"@dcloudio/uni-automator": "3.0.0-alpha-3081220230802001",
|
||||
"@dcloudio/uni-cli-shared": "3.0.0-alpha-3081220230802001",
|
||||
"@dcloudio/uni-stacktracey": "3.0.0-alpha-3081220230802001",
|
||||
"@dcloudio/vite-plugin-uni": "3.0.0-alpha-3081220230802001",
|
||||
"@types/node": "^18.14.6",
|
||||
"@typescript-eslint/eslint-plugin": "^5.55.0",
|
||||
"@typescript-eslint/parser": "^5.55.0",
|
||||
|
||||
@ -358,7 +358,7 @@
|
||||
"mp-alipay": {
|
||||
"allowsBounceVertical": "NO"
|
||||
},
|
||||
"navigationBarTitleText": "Picker 选择器视图"
|
||||
"navigationBarTitleText": "Picker 选择器"
|
||||
}
|
||||
},
|
||||
{
|
||||
|
||||
@ -9,7 +9,7 @@
|
||||
<wd-calendar label="日期时间选择" type="datetime" v-model="value4" />
|
||||
<wd-calendar label="日期时间范围选择" type="datetimerange" v-model="value5" />
|
||||
<wd-calendar label="周选择" type="week" v-model="value6" />
|
||||
<wd-calendar label="月选择" type="month" v-model="value7" />
|
||||
<wd-calendar label="月选择" type="month" :min-date="minDate" v-model="value7" />
|
||||
<wd-calendar label="周范围选择" :first-day-of-week="1" type="weekrange" v-model="value8" />
|
||||
<wd-calendar label="月范围选择" type="monthrange" v-model="value9" />
|
||||
<wd-calendar label="日周月切换" :first-day-of-week="1" show-type-switch v-model="value10" />
|
||||
@ -51,6 +51,8 @@ import { useToast } from '@/uni_modules/wot-design-uni'
|
||||
import { dayjs } from '@/uni_modules/wot-design-uni'
|
||||
import { ref } from 'vue'
|
||||
|
||||
const minDate = ref<number>(new Date(new Date().getFullYear() - 20, new Date().getMonth() - 6, new Date().getDate()).getTime())
|
||||
|
||||
const value1 = ref<number>(Date.now())
|
||||
const value2 = ref<number[]>([Date.now() - 24 * 60 * 60 * 1000 * 3, Date.now()])
|
||||
const value3 = ref<number[]>([])
|
||||
|
||||
@ -23,7 +23,7 @@
|
||||
</demo-block>
|
||||
<demo-block title="自定义菜单选项" transparent>
|
||||
<view class="custom-menu">
|
||||
<wd-drop-menu style="flex: 1; min-width: 0">
|
||||
<wd-drop-menu custom-style="flex: 1; min-width: 0">
|
||||
<wd-drop-menu-item v-model="value4" :options="option1" @change="handleChange4" />
|
||||
</wd-drop-menu>
|
||||
<view style="flex: 1">
|
||||
|
||||
@ -69,6 +69,7 @@ onReady(() => {
|
||||
})
|
||||
|
||||
function handleResize(detail: Record<string, string | number>) {
|
||||
console.log(detail)
|
||||
const { height, width, top, right, bottom, left } = detail
|
||||
lastHeight.value = sizeHeight.value
|
||||
lastTop.value = sizeTop.value
|
||||
|
||||
@ -42,6 +42,10 @@
|
||||
}
|
||||
}
|
||||
|
||||
:deep(.wd-action-sheet__popup){
|
||||
border-radius: $-action-sheet-radius $-action-sheet-radius 0 0;
|
||||
}
|
||||
|
||||
@include b(action-sheet) {
|
||||
background-color: $-color-white;
|
||||
padding-bottom: 1px;
|
||||
|
||||
@ -1,57 +1,59 @@
|
||||
<template>
|
||||
<wd-popup
|
||||
custom-class="wd-action-sheet__popup"
|
||||
:custom-style="`${(actions && actions.length) || (panels && panels.length) ? 'background: transparent;' : ''}`"
|
||||
v-model="showPopup"
|
||||
:duration="duration"
|
||||
position="bottom"
|
||||
:close-on-click-modal="closeOnClickModal"
|
||||
:safe-area-inset-bottom="safeAreaInsetBottom"
|
||||
:lazy-render="lazyRender"
|
||||
@enter="handleOpen"
|
||||
@close="close"
|
||||
@after-enter="handleOpened"
|
||||
@after-leave="handleClosed"
|
||||
@clickmodal="handleClickModal"
|
||||
:z-index="zIndex"
|
||||
>
|
||||
<view
|
||||
class="wd-action-sheet"
|
||||
:style="`${(actions && actions.length) || (panels && panels.length) ? 'margin: 0 10px 10px; border-radius: 16px;' : ''}`"
|
||||
<view>
|
||||
<wd-popup
|
||||
custom-class="wd-action-sheet__popup"
|
||||
:custom-style="`${(actions && actions.length) || (panels && panels.length) ? 'background: transparent;' : ''}`"
|
||||
v-model="showPopup"
|
||||
:duration="duration"
|
||||
position="bottom"
|
||||
:close-on-click-modal="closeOnClickModal"
|
||||
:safe-area-inset-bottom="safeAreaInsetBottom"
|
||||
:lazy-render="lazyRender"
|
||||
@enter="handleOpen"
|
||||
@close="close"
|
||||
@after-enter="handleOpened"
|
||||
@after-leave="handleClosed"
|
||||
@clickmodal="handleClickModal"
|
||||
:z-index="zIndex"
|
||||
>
|
||||
<view v-if="title" :class="`wd-action-sheet__header ${customHeaderClass}`">
|
||||
{{ title }}
|
||||
<wd-icon custom-class="wd-action-sheet__close" name="add" @click="close" />
|
||||
</view>
|
||||
<view class="wd-action-sheet__actions" v-if="actions && actions.length">
|
||||
<button
|
||||
v-for="(action, rowIndex) in actions"
|
||||
:key="rowIndex"
|
||||
:class="`wd-action-sheet__action ${action.disabled ? 'wd-action-sheet__action--disabled' : ''} ${
|
||||
action.loading ? 'wd-action-sheet__action--loading' : ''
|
||||
}`"
|
||||
:style="`color: ${action.color}`"
|
||||
@click="select(rowIndex, 'action')"
|
||||
>
|
||||
<wd-loading v-if="action.loading" size="20px" />
|
||||
<view v-else class="wd-action-sheet__name">{{ action.name }}</view>
|
||||
<view v-if="!action.loading && action.subname" class="wd-action-sheet__subname">{{ action.subname }}</view>
|
||||
</button>
|
||||
</view>
|
||||
<view v-if="formatPanels && formatPanels.length">
|
||||
<view v-for="(panel, rowIndex) in formatPanels" :key="rowIndex" class="wd-action-sheet__panels">
|
||||
<view class="wd-action-sheet__panels-content">
|
||||
<view v-for="(col, colIndex) in panel" :key="colIndex" class="wd-action-sheet__panel" @click="select(rowIndex, 'panels', colIndex)">
|
||||
<image class="wd-action-sheet__panel-img" :src="(col as any).iconUrl" />
|
||||
<view class="wd-action-sheet__panel-title">{{ (col as any).title }}</view>
|
||||
<view
|
||||
class="wd-action-sheet"
|
||||
:style="`${(actions && actions.length) || (panels && panels.length) ? 'margin: 0 10px 10px; border-radius: 16px;' : ''}`"
|
||||
>
|
||||
<view v-if="title" :class="`wd-action-sheet__header ${customHeaderClass}`">
|
||||
{{ title }}
|
||||
<wd-icon custom-class="wd-action-sheet__close" name="add" @click="close" />
|
||||
</view>
|
||||
<view class="wd-action-sheet__actions" v-if="actions && actions.length">
|
||||
<button
|
||||
v-for="(action, rowIndex) in actions"
|
||||
:key="rowIndex"
|
||||
:class="`wd-action-sheet__action ${action.disabled ? 'wd-action-sheet__action--disabled' : ''} ${
|
||||
action.loading ? 'wd-action-sheet__action--loading' : ''
|
||||
}`"
|
||||
:style="`color: ${action.color}`"
|
||||
@click="select(rowIndex, 'action')"
|
||||
>
|
||||
<wd-loading v-if="action.loading" size="20px" />
|
||||
<view v-else class="wd-action-sheet__name">{{ action.name }}</view>
|
||||
<view v-if="!action.loading && action.subname" class="wd-action-sheet__subname">{{ action.subname }}</view>
|
||||
</button>
|
||||
</view>
|
||||
<view v-if="formatPanels && formatPanels.length">
|
||||
<view v-for="(panel, rowIndex) in formatPanels" :key="rowIndex" class="wd-action-sheet__panels">
|
||||
<view class="wd-action-sheet__panels-content">
|
||||
<view v-for="(col, colIndex) in panel" :key="colIndex" class="wd-action-sheet__panel" @click="select(rowIndex, 'panels', colIndex)">
|
||||
<image class="wd-action-sheet__panel-img" :src="(col as any).iconUrl" />
|
||||
<view class="wd-action-sheet__panel-title">{{ (col as any).title }}</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<slot />
|
||||
<button v-if="cancelText" class="wd-action-sheet__cancel" @click="handleCancel">{{ cancelText }}</button>
|
||||
</view>
|
||||
<slot />
|
||||
<button v-if="cancelText" class="wd-action-sheet__cancel" @click="handleCancel">{{ cancelText }}</button>
|
||||
</view>
|
||||
</wd-popup>
|
||||
</wd-popup>
|
||||
</view>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
export default {
|
||||
@ -114,7 +116,7 @@ const props = withDefaults(defineProps<Props>(), {
|
||||
closeOnClickModal: true,
|
||||
duration: 200,
|
||||
zIndex: 10,
|
||||
lazyRender: false,
|
||||
lazyRender: true,
|
||||
safeAreaInsetBottom: true
|
||||
})
|
||||
const formatPanels = ref<Array<Panel> | Array<Array<Panel>>>([])
|
||||
|
||||
@ -23,8 +23,10 @@
|
||||
|
||||
@include b(month) {
|
||||
@include e(title) {
|
||||
padding: 13px 0;
|
||||
text-align: center;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 45px;
|
||||
font-size: $-calendar-panel-title-fs;
|
||||
color: $-calendar-panel-title-color;
|
||||
}
|
||||
|
||||
@ -82,7 +82,7 @@ const monthTitle = computed(() => {
|
||||
}
|
||||
})
|
||||
const firstDayStyle = computed(() => {
|
||||
return (index, date, firstDayOfWeek) => {
|
||||
return (index: number, date: number, firstDayOfWeek: number) => {
|
||||
return getFirstDayStyle(index, date, firstDayOfWeek)
|
||||
}
|
||||
})
|
||||
|
||||
@ -8,16 +8,17 @@
|
||||
</view>
|
||||
<scroll-view
|
||||
:class="`wd-month-panel__container ${!!timeType ? 'wd-month-panel__container--time' : ''}`"
|
||||
:style="`height: ${!!timeType ? (panelHeight || 378) - 125 : panelHeight || 378}px`"
|
||||
:style="`height: ${scrollHeight}px`"
|
||||
scroll-y
|
||||
:scroll-into-view="scrollIntoViewValue"
|
||||
@scroll="monthScroll"
|
||||
:scroll-top="scrollTop"
|
||||
>
|
||||
<view v-for="(item, index) in months(minDate, maxDate)" :key="index" :id="`month${index}`">
|
||||
<month
|
||||
class="month"
|
||||
:type="type"
|
||||
:date="item"
|
||||
:data-date="item"
|
||||
:date="item.date"
|
||||
:data-date="item.date"
|
||||
:value="value"
|
||||
:min-date="minDate"
|
||||
:max-date="maxDate"
|
||||
@ -41,7 +42,6 @@
|
||||
v-model="timeValue"
|
||||
:columns="timeData"
|
||||
:columns-height="125"
|
||||
:show-picker="showPicker"
|
||||
@change="handleTimeChange"
|
||||
@pickstart="handlePickStart"
|
||||
@pickend="handlePickEnd"
|
||||
@ -64,8 +64,9 @@ export default {
|
||||
<script lang="ts" setup>
|
||||
import { computed, getCurrentInstance, nextTick, onMounted, ref, watch } from 'vue'
|
||||
import { debounce, getType, isEqual } from '../../common/util'
|
||||
import { compareMonth, formatMonthTitle, getMonths, getTimeData, getWeekLabel } from '../utils'
|
||||
import { compareMonth, formatMonthTitle, getMonthEndDay, getMonths, getTimeData, getWeekLabel } from '../utils'
|
||||
import Month from '../month/month.vue'
|
||||
import { MonthInfo } from './type'
|
||||
|
||||
interface Props {
|
||||
type: string
|
||||
@ -84,35 +85,44 @@ interface Props {
|
||||
// eslint-disable-next-line @typescript-eslint/ban-types
|
||||
timeFilter?: Function
|
||||
hideSecond: boolean
|
||||
// 是否展示picker(兼容支付宝和钉钉)
|
||||
showPicker: boolean
|
||||
}
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
showPicker: true,
|
||||
allowSameDay: false,
|
||||
showPanelTitle: false,
|
||||
hideSecond: false
|
||||
})
|
||||
|
||||
const title = ref<string>('')
|
||||
const scrollIntoViewValue = ref<string>('')
|
||||
const scrollTop = ref<number>(0) // 滚动位置
|
||||
const timeValue = ref<Array<string>>([])
|
||||
const timeData = ref<Array<string | string[]>>([])
|
||||
const timeType = ref<string>('') // 当前时间类型,是开始还是结束
|
||||
const innerValue = ref<string | number[]>('') // 内部保存一个值,用于判断新老值,避免监听器触发
|
||||
|
||||
let contentObserver: null | UniApp.IntersectionObserver = null
|
||||
const instance = getCurrentInstance() as any
|
||||
|
||||
const weekLabel = computed(() => {
|
||||
return (index: number) => {
|
||||
return getWeekLabel(index)
|
||||
return getWeekLabel(index - 1)
|
||||
}
|
||||
})
|
||||
|
||||
// 滚动区域的高度
|
||||
const scrollHeight = computed(() => {
|
||||
const scrollHeight: number = timeType.value ? (props.panelHeight || 378) - 125 : props.panelHeight || 378
|
||||
return scrollHeight
|
||||
})
|
||||
|
||||
// 月份日期和月份高度
|
||||
const months = computed(() => {
|
||||
return (minDate, maxDate) => {
|
||||
return getMonths(minDate, maxDate)
|
||||
return (minDate: number, maxDate: number): MonthInfo[] => {
|
||||
let months = getMonths(minDate, maxDate).map((month) => {
|
||||
const offset = (7 + new Date(month).getDay() - props.firstDayOfWeek) % 7
|
||||
const totalDay = getMonthEndDay(new Date(month).getFullYear(), new Date(month).getMonth() + 1)
|
||||
return {
|
||||
height: (offset + totalDay > 35 ? 64 * 6 : 64 * 5) + 45,
|
||||
date: month
|
||||
}
|
||||
})
|
||||
return months
|
||||
}
|
||||
})
|
||||
|
||||
@ -148,7 +158,6 @@ watch(
|
||||
)
|
||||
|
||||
onMounted(() => {
|
||||
initRect()
|
||||
scrollIntoView()
|
||||
})
|
||||
|
||||
@ -160,26 +169,6 @@ const handleChange = debounce((value) => {
|
||||
})
|
||||
}, 50)
|
||||
|
||||
function initRect(thresholds = [0, 0.7, 0.8, 0.9, 1]) {
|
||||
if (!props.showPanelTitle) return
|
||||
|
||||
if (contentObserver != null) {
|
||||
contentObserver.disconnect()
|
||||
}
|
||||
|
||||
contentObserver = uni.createIntersectionObserver(instance, {
|
||||
thresholds,
|
||||
observeAll: true,
|
||||
dataset: true
|
||||
} as any)
|
||||
|
||||
contentObserver.relativeTo('.wd-month-panel__container')
|
||||
contentObserver.observe('.month', (res: any) => {
|
||||
if (res.boundingClientRect.top <= res.relativeRect.top) {
|
||||
title.value = formatMonthTitle(res.dataset.date)
|
||||
}
|
||||
})
|
||||
}
|
||||
function scrollIntoView() {
|
||||
setTimeout(() => {
|
||||
let activeDate
|
||||
@ -194,17 +183,18 @@ function scrollIntoView() {
|
||||
activeDate = Date.now()
|
||||
}
|
||||
|
||||
const months = getMonths(props.minDate, props.maxDate)
|
||||
const monthsInfo = months.value(props.minDate, props.maxDate)
|
||||
|
||||
months.some((month, index) => {
|
||||
if (compareMonth(month, activeDate) === 0) {
|
||||
scrollIntoViewValue.value = ''
|
||||
nextTick(() => {
|
||||
scrollIntoViewValue.value = `month${index}`
|
||||
})
|
||||
return true
|
||||
let top: number = 0
|
||||
for (let index = 0; index < monthsInfo.length; index++) {
|
||||
if (compareMonth(monthsInfo[index].date, activeDate) === 0) {
|
||||
break
|
||||
}
|
||||
return false
|
||||
top += monthsInfo[index] ? Number(monthsInfo[index].height) : 0
|
||||
}
|
||||
scrollTop.value = 0
|
||||
nextTick(() => {
|
||||
scrollTop.value = top
|
||||
})
|
||||
}, 50)
|
||||
}
|
||||
@ -275,10 +265,6 @@ function setTime(value, type) {
|
||||
timeData.value = getTime(value, type) || []
|
||||
timeValue.value = getTimeValue(value, type)
|
||||
timeType.value = type
|
||||
|
||||
nextTick(() => {
|
||||
initRect([0, 0.58, 0.69, 0.83, 1])
|
||||
})
|
||||
}
|
||||
function handleDateChange({ value, type }) {
|
||||
if (!isEqual(value, props.value)) {
|
||||
@ -335,8 +321,31 @@ function handlePickEnd() {
|
||||
emit('pickend')
|
||||
}
|
||||
|
||||
const monthScroll = (event: { detail: { scrollTop: number } }) => {
|
||||
const monthsInfo = months.value(props.minDate, props.maxDate)
|
||||
if (monthsInfo.length <= 1) {
|
||||
return
|
||||
}
|
||||
const scrollTop = Math.max(0, event.detail.scrollTop)
|
||||
doSetSubtitle(scrollTop, monthsInfo)
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置小标题
|
||||
* scrollTop 滚动条位置
|
||||
*/
|
||||
function doSetSubtitle(scrollTop: number, monthsInfo: MonthInfo[]) {
|
||||
let height: number = 0 // 月份高度和
|
||||
for (let index = 0; index < monthsInfo.length; index++) {
|
||||
height = height + monthsInfo[index].height
|
||||
if (scrollTop < height + 45) {
|
||||
title.value = formatMonthTitle(monthsInfo[index].date)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
initRect,
|
||||
scrollIntoView
|
||||
})
|
||||
</script>
|
||||
|
||||
@ -0,0 +1,7 @@
|
||||
/**
|
||||
* 月份信息
|
||||
*/
|
||||
export interface MonthInfo {
|
||||
date: number
|
||||
height: number
|
||||
}
|
||||
@ -112,15 +112,14 @@ export function getWeekLabel(index) {
|
||||
* @param {timestamp} date
|
||||
* @param {number} firstDayOfWeek
|
||||
*/
|
||||
export function getFirstDayStyle(index, date, firstDayOfWeek) {
|
||||
export function getFirstDayStyle(index: number, date: number, firstDayOfWeek: number) {
|
||||
if (firstDayOfWeek >= 7) {
|
||||
firstDayOfWeek = firstDayOfWeek % 7
|
||||
}
|
||||
|
||||
if (index !== 0) return ''
|
||||
|
||||
date = new Date(date)
|
||||
const offset = (7 + date.getDay() - firstDayOfWeek) % 7
|
||||
const offset = (7 + new Date(date).getDay() - firstDayOfWeek) % 7
|
||||
|
||||
return 'margin-left: ' + (100 / 7) * offset + '%'
|
||||
}
|
||||
@ -129,10 +128,8 @@ export function getFirstDayStyle(index, date, firstDayOfWeek) {
|
||||
* 格式化年份
|
||||
* @param {timestamp} date
|
||||
*/
|
||||
export function formatYearTitle(date) {
|
||||
date = new Date(date)
|
||||
|
||||
const year = date.getFullYear()
|
||||
export function formatYearTitle(date: number) {
|
||||
const year = new Date(date).getFullYear()
|
||||
|
||||
return year + '年'
|
||||
}
|
||||
@ -160,7 +157,7 @@ export function getMonths(minDate, maxDate) {
|
||||
* @param {timestamp} minDate
|
||||
* @param {timestamp} maxDate
|
||||
*/
|
||||
export function getYears(minDate, maxDate) {
|
||||
export function getYears(minDate: number, maxDate: number) {
|
||||
const years: number[] = []
|
||||
const year = new Date(minDate)
|
||||
year.setMonth(0)
|
||||
|
||||
@ -33,7 +33,6 @@
|
||||
:panel-height="panelHeight"
|
||||
:time-filter="timeFilter"
|
||||
:hide-second="hideSecond"
|
||||
:show-picker="showPicker"
|
||||
@change="handleChange"
|
||||
@pickstart="handlePickStart"
|
||||
@pickend="handlePickEnd"
|
||||
@ -43,7 +42,6 @@
|
||||
<script lang="ts">
|
||||
export default {
|
||||
name: 'wd-calendar-view',
|
||||
behaviors: ['uni://form-field'],
|
||||
options: {
|
||||
addGlobalClass: true,
|
||||
virtualHost: true,
|
||||
@ -92,8 +90,6 @@ interface Props {
|
||||
timeFilter?: Function
|
||||
// type 为 'datetime' 或 'datetimerange' 时有效,是否不展示秒修改
|
||||
hideSecond: boolean
|
||||
// 是否展示picker(兼容支付宝和钉钉)
|
||||
showPicker: boolean
|
||||
}
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
customClass: '',
|
||||
@ -105,8 +101,7 @@ const props = withDefaults(defineProps<Props>(), {
|
||||
showPanelTitle: true,
|
||||
defaultTime: '00:00:00',
|
||||
panelHeight: 378,
|
||||
hideSecond: false,
|
||||
showPicker: true
|
||||
hideSecond: false
|
||||
})
|
||||
|
||||
const formatDefauleTime = ref<number[]>([])
|
||||
@ -128,9 +123,8 @@ watch(
|
||||
const emit = defineEmits(['change', 'update:modelValue', 'pickstart', 'pickend'])
|
||||
|
||||
// 对外暴露方法
|
||||
function scrollIntoView(thresholds) {
|
||||
function scrollIntoView() {
|
||||
const panel = getPanel()
|
||||
panel.initRect && panel.initRect(thresholds)
|
||||
panel.scrollIntoView && panel.scrollIntoView()
|
||||
}
|
||||
|
||||
|
||||
@ -24,8 +24,10 @@
|
||||
|
||||
@include b(year) {
|
||||
@include e(title) {
|
||||
padding: 13px 0;
|
||||
text-align: center;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 45px;
|
||||
font-size: $-calendar-panel-title-fs;
|
||||
color: $-calendar-panel-title-color;
|
||||
}
|
||||
|
||||
@ -0,0 +1,7 @@
|
||||
/**
|
||||
* 月份信息
|
||||
*/
|
||||
export interface YearInfo {
|
||||
date: number
|
||||
height: number
|
||||
}
|
||||
@ -1,18 +1,13 @@
|
||||
<template>
|
||||
<view class="wd-year-panel">
|
||||
<view v-if="showPanelTitle" class="wd-year-panel__title">{{ title }}</view>
|
||||
<scroll-view
|
||||
class="wd-year-panel__container"
|
||||
:style="`height: ${(panelHeight || 378) + (showPanelTitle ? 26 : 16)}px`"
|
||||
scroll-y
|
||||
:scroll-into-view="scrollIntoViewValue"
|
||||
>
|
||||
<scroll-view class="wd-year-panel__container" :style="`height: ${scrollHeight}px`" scroll-y @scroll="yearScroll" :scroll-top="scrollTop">
|
||||
<view v-for="(item, index) in years(minDate, maxDate)" :key="index" :id="`year${index}`">
|
||||
<year
|
||||
class="year"
|
||||
:type="type"
|
||||
:date="item"
|
||||
:data-date="item"
|
||||
:date="item.date"
|
||||
:data-date="item.date"
|
||||
:value="value"
|
||||
:min-date="minDate"
|
||||
:max-date="maxDate"
|
||||
@ -42,6 +37,7 @@ import { computed, getCurrentInstance, onMounted, ref, nextTick } from 'vue'
|
||||
import { compareYear, formatYearTitle, getYears } from '../utils'
|
||||
import { getType } from '../../common/util'
|
||||
import Year from '../year/year.vue'
|
||||
import { YearInfo } from './type'
|
||||
|
||||
interface Props {
|
||||
type: string
|
||||
@ -63,21 +59,34 @@ const props = withDefaults(defineProps<Props>(), {
|
||||
})
|
||||
|
||||
const title = ref<string>('')
|
||||
const scrollTop = ref<number>(0) // 滚动位置
|
||||
|
||||
const scrollIntoViewValue = ref<string>('')
|
||||
|
||||
let contentObserver: null | UniApp.IntersectionObserver = null
|
||||
const instance = getCurrentInstance() as any
|
||||
|
||||
// 滚动区域的高度
|
||||
const scrollHeight = computed(() => {
|
||||
const scrollHeight: number = (props.panelHeight || 378) + (props.showPanelTitle ? 26 : 16)
|
||||
return scrollHeight
|
||||
})
|
||||
|
||||
const years = computed(() => {
|
||||
return (minDate, maxDate) => {
|
||||
return getYears(minDate, maxDate)
|
||||
return (minDate: number, maxDate: number): YearInfo[] => {
|
||||
let years = getYears(minDate, maxDate).map((year) => {
|
||||
return {
|
||||
date: year,
|
||||
height: 237
|
||||
}
|
||||
})
|
||||
return years
|
||||
}
|
||||
})
|
||||
|
||||
const emit = defineEmits(['change'])
|
||||
|
||||
onMounted(() => {
|
||||
initRect()
|
||||
scrollIntoView()
|
||||
})
|
||||
|
||||
@ -94,25 +103,6 @@ const requestAnimationFrame = (cb = () => void 0) => {
|
||||
})
|
||||
}
|
||||
|
||||
function initRect(thresholds = [0, 0.15, 0.7, 0.8, 0.9, 1]) {
|
||||
if (!props.showPanelTitle) return
|
||||
|
||||
if (contentObserver != null) {
|
||||
contentObserver.disconnect()
|
||||
}
|
||||
|
||||
contentObserver = uni.createIntersectionObserver(instance, {
|
||||
thresholds,
|
||||
observeAll: true
|
||||
})
|
||||
|
||||
contentObserver.relativeTo('.wd-year-panel__container')
|
||||
contentObserver.observe('.year', (res: any) => {
|
||||
if (res.boundingClientRect.top <= res.relativeRect.top) {
|
||||
title.value = formatYearTitle(res.dataset.date)
|
||||
}
|
||||
})
|
||||
}
|
||||
function scrollIntoView() {
|
||||
requestAnimationFrame().then(() => {
|
||||
let activeDate
|
||||
@ -127,21 +117,46 @@ function scrollIntoView() {
|
||||
activeDate = Date.now()
|
||||
}
|
||||
|
||||
const years = getYears(props.minDate, props.maxDate)
|
||||
const yearsInfo = years.value(props.minDate, props.maxDate)
|
||||
|
||||
years.some((year, index) => {
|
||||
if (compareYear(year, activeDate) === 0) {
|
||||
scrollIntoViewValue.value = ''
|
||||
nextTick(() => {
|
||||
scrollIntoViewValue.value = `year${index}`
|
||||
})
|
||||
return true
|
||||
let top: number = 0
|
||||
for (let index = 0; index < yearsInfo.length; index++) {
|
||||
if (compareYear(yearsInfo[index].date, activeDate) === 0) {
|
||||
break
|
||||
}
|
||||
|
||||
return false
|
||||
top += yearsInfo[index] ? Number(yearsInfo[index].height) : 0
|
||||
}
|
||||
scrollTop.value = 0
|
||||
nextTick(() => {
|
||||
scrollTop.value = top
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
const yearScroll = (e: Event) => {
|
||||
const yearsInfo = years.value(props.minDate, props.maxDate)
|
||||
if (yearsInfo.length <= 1) {
|
||||
return
|
||||
}
|
||||
const scrollTop = Math.max(0, (e.target as Element).scrollTop)
|
||||
doSetSubtitle(scrollTop, yearsInfo)
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置小标题
|
||||
* scrollTop 滚动条位置
|
||||
*/
|
||||
function doSetSubtitle(scrollTop: number, yearsInfo: YearInfo[]) {
|
||||
let height: number = 0 // 月份高度和
|
||||
for (let index = 0; index < yearsInfo.length; index++) {
|
||||
height = height + yearsInfo[index].height
|
||||
if (scrollTop < height + 45) {
|
||||
title.value = formatYearTitle(yearsInfo[index].date)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function handleDateChange({ value }) {
|
||||
emit('change', {
|
||||
value
|
||||
@ -149,7 +164,6 @@ function handleDateChange({ value }) {
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
initRect,
|
||||
scrollIntoView
|
||||
})
|
||||
</script>
|
||||
|
||||
@ -31,8 +31,6 @@
|
||||
:safe-area-inset-bottom="safeAreaInsetBottom"
|
||||
:z-index="zIndex"
|
||||
@close="close"
|
||||
@opened="setShowPicker(true)"
|
||||
@closed="setShowPicker(false)"
|
||||
>
|
||||
<view class="wd-calendar__header">
|
||||
<view v-if="!showTypeSwitch && shortcuts.length === 0" class="wd-calendar__title">{{ title || '选择日期' }}</view>
|
||||
@ -86,7 +84,6 @@
|
||||
:default-time="defaultTime"
|
||||
:time-filter="timeFilter"
|
||||
:hide-second="hideSecond"
|
||||
:show-picker="showPicker"
|
||||
:show-panel-title="!range(type)"
|
||||
@change="handleChange"
|
||||
/>
|
||||
@ -101,7 +98,6 @@
|
||||
<script lang="ts">
|
||||
export default {
|
||||
name: 'wd-calendar',
|
||||
behaviors: ['uni://form-field'],
|
||||
options: {
|
||||
addGlobalClass: true,
|
||||
virtualHost: true,
|
||||
@ -274,7 +270,6 @@ const currentType = ref<CalendarType>('date')
|
||||
const lastCurrentType = ref<CalendarType>('date')
|
||||
const inited = ref<boolean>(false)
|
||||
const rangeLabel = ref<Array<string>>([])
|
||||
const showPicker = ref<boolean>(false)
|
||||
|
||||
const cell = useCell()
|
||||
|
||||
@ -342,10 +337,6 @@ const range = computed(() => {
|
||||
|
||||
const emit = defineEmits(['cancel', 'change', 'update:modelValue', 'confirm'])
|
||||
|
||||
const setShowPicker = debounce(function (show: boolean) {
|
||||
showPicker.value = show
|
||||
}, 100)
|
||||
|
||||
function scrollIntoView() {
|
||||
calendarView.value && calendarView.value && calendarView.value.$.exposed.scrollIntoView()
|
||||
}
|
||||
|
||||
@ -6,7 +6,6 @@
|
||||
<script lang="ts">
|
||||
export default {
|
||||
name: 'wd-checkbox-group',
|
||||
behaviors: ['uni://form-field'],
|
||||
options: {
|
||||
addGlobalClass: true,
|
||||
virtualHost: true,
|
||||
|
||||
@ -33,7 +33,6 @@
|
||||
<script lang="ts">
|
||||
export default {
|
||||
name: 'wd-checkbox',
|
||||
behaviors: ['uni://form-field'],
|
||||
options: {
|
||||
addGlobalClass: true,
|
||||
virtualHost: true,
|
||||
|
||||
@ -80,7 +80,6 @@
|
||||
<script lang="ts">
|
||||
export default {
|
||||
name: 'wd-col-picker',
|
||||
behaviors: ['uni://form-field'],
|
||||
options: {
|
||||
addGlobalClass: true,
|
||||
virtualHost: true,
|
||||
@ -217,8 +216,6 @@ watch(
|
||||
selectShowList.value = pickerColSelected.value.map((item, colIndex) => {
|
||||
return getSelectedItem(item, colIndex, newSelectedList)[props.labelKey]
|
||||
})
|
||||
console.log(selectShowList.value, 'watch props.columns')
|
||||
|
||||
lastSelectList.value = newSelectedList
|
||||
|
||||
if (newSelectedList.length > 0) {
|
||||
@ -372,8 +369,6 @@ function handleColChange(colIndex, item, index, callback?) {
|
||||
selectShowList.value = pickerColSelected.value.map((item, colIndex) => {
|
||||
return getSelectedItem(item, colIndex, selectList.value)[props.labelKey]
|
||||
})
|
||||
console.log(selectShowList.value, 'handleColChange')
|
||||
|
||||
callback()
|
||||
}
|
||||
},
|
||||
@ -509,6 +504,11 @@ function handleAutoComplete() {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
close,
|
||||
open
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
||||
@ -0,0 +1,24 @@
|
||||
export type DateTimeType = 'date' | 'year-month' | 'time' | 'datetime'
|
||||
|
||||
/**
|
||||
* @description 根据传入的值和类型,获取当前的选项数组,便于传入 pickerView
|
||||
* @param value
|
||||
* @param type picker类型
|
||||
* @return {Array} pickerValue
|
||||
*/
|
||||
export function getPickerValue(value, type) {
|
||||
const values: number[] = []
|
||||
const date = new Date(value)
|
||||
if (type === 'time') {
|
||||
const pair = value.split(':')
|
||||
values.push(parseInt(pair[0]), parseInt(pair[1]))
|
||||
} else {
|
||||
values.push(date.getFullYear(), date.getMonth() + 1)
|
||||
if (type === 'date') {
|
||||
values.push(date.getDate())
|
||||
} else if (type === 'datetime') {
|
||||
values.push(date.getDate(), date.getHours(), date.getMinutes())
|
||||
}
|
||||
}
|
||||
return values
|
||||
}
|
||||
@ -9,7 +9,6 @@
|
||||
:columnChange="columnChange"
|
||||
:loading="loading"
|
||||
:loading-color="loadingColor"
|
||||
:show-picker="showPicker"
|
||||
@change="onChange"
|
||||
@pickstart="onPickStart"
|
||||
@pickend="onPickEnd"
|
||||
@ -19,7 +18,6 @@
|
||||
<script lang="ts">
|
||||
export default {
|
||||
name: 'wd-datetime-picker-view',
|
||||
behaviors: ['uni://form-field'],
|
||||
virtualHost: true,
|
||||
addGlobalClass: true,
|
||||
styleIsolation: 'shared'
|
||||
@ -29,6 +27,7 @@ export default {
|
||||
<script lang="ts" setup>
|
||||
import { getCurrentInstance, onBeforeMount, onMounted, ref, watch } from 'vue'
|
||||
import { debounce, getType, isDef, padZero, range } from '../common/util'
|
||||
import { DateTimeType, getPickerValue } from './type'
|
||||
|
||||
// 本地时间戳
|
||||
/** @description 判断时间戳是否合法 */
|
||||
@ -58,15 +57,11 @@ const getMonthEndDay = (year, month) => {
|
||||
return 32 - new Date(year, month - 1, 32).getDate()
|
||||
}
|
||||
|
||||
type DateTimeType = 'date' | 'year-month' | 'time' | 'datetime'
|
||||
|
||||
interface Props {
|
||||
customClass?: string
|
||||
// 选中项,当 type 为 time 时,类型为字符串,否则为 Date
|
||||
modelValue: string | number | Date
|
||||
// PickerView的Props 开始
|
||||
// 是否展示picker(兼容支付宝和钉钉)
|
||||
showPicker: boolean
|
||||
// 加载中
|
||||
loading: boolean
|
||||
loadingColor: string
|
||||
@ -106,7 +101,6 @@ interface Props {
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
customClass: '',
|
||||
// PickerView的Props 开始
|
||||
showPicker: true,
|
||||
// 加载中
|
||||
loading: false,
|
||||
loadingColor: '#4D80F0',
|
||||
@ -131,7 +125,7 @@ const datePickerview = ref()
|
||||
// 内部保持时间戳的
|
||||
const innerValue = ref<null | number>(null)
|
||||
// 传递给pickerView的columns的数据
|
||||
const columns = ref<Array<string | string[]>>([])
|
||||
const columns = ref<Array<string | number>>([])
|
||||
// 传递给pickerView的value的数据
|
||||
const pickerValue = ref<string | number | boolean | Array<string | number | boolean>>([])
|
||||
// 自定义组件是否已经调用created hook
|
||||
@ -432,29 +426,6 @@ function getBoundary(type, innerValue) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 根据传入的值和类型,获取当前的选项数组,便于传入 pickerView
|
||||
* @param value
|
||||
* @param type picker类型
|
||||
* @return {Array} pickerValue
|
||||
*/
|
||||
function getPickerValue(value, type) {
|
||||
const values: number[] = []
|
||||
const date = new Date(value)
|
||||
if (type === 'time') {
|
||||
const pair = value.split(':')
|
||||
values.push(parseInt(pair[0]), parseInt(pair[1]))
|
||||
} else {
|
||||
values.push(date.getFullYear(), date.getMonth() + 1)
|
||||
if (type === 'date') {
|
||||
values.push(date.getDate())
|
||||
} else if (type === 'datetime') {
|
||||
values.push(date.getDate(), date.getHours(), date.getMinutes())
|
||||
}
|
||||
}
|
||||
return values
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 根据传入的value以及type,初始化innerValue,期间会使用format格式化数据
|
||||
* @param value
|
||||
@ -571,7 +542,7 @@ function onPickEnd() {
|
||||
}
|
||||
|
||||
function getSelects() {
|
||||
return datePickerview.value.getSelects()
|
||||
return datePickerview.value && datePickerview.value.getSelects ? datePickerview.value.getSelects() : undefined
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
|
||||
@ -33,14 +33,11 @@
|
||||
<wd-popup
|
||||
v-model="popupShow"
|
||||
position="bottom"
|
||||
:lazyRender="false"
|
||||
:hide-when-close="true"
|
||||
:hide-when-close="false"
|
||||
:close-on-click-modal="closeOnClickModal"
|
||||
:safe-area-inset-bottom="safeAreaInsetBottom"
|
||||
:z-index="zIndex"
|
||||
@close="onCancel"
|
||||
@enter="setShowPicker(true)"
|
||||
@leave="setShowPicker(false)"
|
||||
custom-class="wd-picker__popup"
|
||||
>
|
||||
<!--toolBar-->
|
||||
@ -89,7 +86,6 @@
|
||||
:max-minute="maxMinute"
|
||||
:min-minute="minMinute"
|
||||
:start-symbol="true"
|
||||
:show-picker="showPicker"
|
||||
@change="onChangeStart"
|
||||
@pickstart="onPickStart"
|
||||
@pickend="onPickEnd"
|
||||
@ -116,7 +112,6 @@
|
||||
:max-minute="maxMinute"
|
||||
:min-minute="minMinute"
|
||||
:start-symbol="false"
|
||||
:show-picker="showPicker"
|
||||
@change="onChangeEnd"
|
||||
@pickstart="onPickStart"
|
||||
@pickend="onPickEnd"
|
||||
@ -129,7 +124,6 @@
|
||||
<script lang="ts">
|
||||
export default {
|
||||
name: 'wd-datetime-picker',
|
||||
behaviors: ['uni://form-field'],
|
||||
options: {
|
||||
virtualHost: true,
|
||||
addGlobalClass: true,
|
||||
@ -140,14 +134,14 @@ export default {
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { getCurrentInstance, onBeforeMount, onMounted, ref, watch, nextTick } from 'vue'
|
||||
import { debounce, deepClone, getType, isArray, isDef, isEqual, padZero } from '../common/util'
|
||||
import { deepClone, getType, isArray, isDef, isEqual, padZero } from '../common/util'
|
||||
import { useCell } from '../mixins/useCell'
|
||||
type DateTimeType = 'date' | 'year-month' | 'time' | 'datetime'
|
||||
import { DateTimeType, getPickerValue } from '../wd-datetime-picker-view/type'
|
||||
interface Props {
|
||||
customClass?: string
|
||||
customViewClass?: string
|
||||
customLabelClass?: string
|
||||
customValueClass?: string
|
||||
customClass: string
|
||||
customViewClass: string
|
||||
customLabelClass: string
|
||||
customValueClass: string
|
||||
// 选择器左侧文案
|
||||
label?: string
|
||||
// 选择器占位符
|
||||
@ -220,7 +214,7 @@ interface Props {
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
customClass: '',
|
||||
customViewClass: '',
|
||||
customLabelVlass: '',
|
||||
customLabelClass: '',
|
||||
customValueClass: '',
|
||||
// 选择器占位符
|
||||
placeholder: '请选择',
|
||||
@ -273,7 +267,6 @@ const datetimePickerView1 = ref()
|
||||
|
||||
const showValue = ref<string | Date | Array<string | Date>>([])
|
||||
const popupShow = ref<boolean>(false)
|
||||
const showPicker = ref<boolean>(false)
|
||||
const showStart = ref<boolean>(true)
|
||||
const region = ref<boolean>(false)
|
||||
const showTabLabel = ref<string[]>([])
|
||||
@ -288,10 +281,6 @@ const { proxy } = getCurrentInstance() as any
|
||||
|
||||
const cell = useCell()
|
||||
|
||||
const setShowPicker = debounce(function (show: boolean) {
|
||||
showPicker.value = show
|
||||
}, 100)
|
||||
|
||||
watch(
|
||||
() => props.modelValue,
|
||||
(val, oldVal) => {
|
||||
@ -377,7 +366,7 @@ watch(
|
||||
watch(
|
||||
() => props.defaultValue,
|
||||
(val) => {
|
||||
if (getType(val) === 'array') {
|
||||
if (getType(val) === 'array' || region.value) {
|
||||
innerValue.value = deepClone(getDefaultInnerValue(true))
|
||||
endInnerValue.value = deepClone(getDefaultInnerValue(true, true))
|
||||
} else {
|
||||
@ -428,14 +417,11 @@ const customColumnFormatter = (picker) => {
|
||||
})
|
||||
})
|
||||
}
|
||||
console.log(mapColumns(columns))
|
||||
|
||||
return mapColumns(columns)
|
||||
}
|
||||
|
||||
onBeforeMount(() => {
|
||||
const { modelValue: value } = props
|
||||
|
||||
if (getType(value) === 'array') {
|
||||
region.value = true
|
||||
innerValue.value = deepClone(getDefaultInnerValue(true))
|
||||
@ -446,9 +432,28 @@ onBeforeMount(() => {
|
||||
})
|
||||
|
||||
onMounted(() => {
|
||||
setShowValue()
|
||||
setShowValue(false, false, true)
|
||||
})
|
||||
|
||||
/**
|
||||
* @description 根据传入的picker,picker组件获取当前cell展示值。
|
||||
*/
|
||||
function getSelects(picker: 'before' | 'after') {
|
||||
let value = picker === 'before' ? innerValue.value : endInnerValue.value
|
||||
let selected: number[] = []
|
||||
if (value) {
|
||||
selected = getPickerValue(value, props.type)
|
||||
}
|
||||
|
||||
let selects = selected.map((value) => {
|
||||
return {
|
||||
[props.labelKey]: padZero(value),
|
||||
[props.valueKey]: value
|
||||
}
|
||||
})
|
||||
return selects
|
||||
}
|
||||
|
||||
function noop() {}
|
||||
|
||||
function getDefaultInnerValue(isRegion?: boolean, isEnd?: boolean) {
|
||||
@ -491,7 +496,7 @@ function showPopup() {
|
||||
popupShow.value = true
|
||||
innerValue.value = deepClone(getDefaultInnerValue())
|
||||
}
|
||||
setShowValue(true, false)
|
||||
setShowValue(true, false, true)
|
||||
}
|
||||
|
||||
/**
|
||||
@ -531,6 +536,7 @@ function onChangeStart({ value }) {
|
||||
*/
|
||||
function onChangeEnd({ value }) {
|
||||
endInnerValue.value = deepClone(value)
|
||||
|
||||
showTabLabel.value = [deepClone(showTabLabel.value[0]), setTabLabel(1)]
|
||||
// emit('update:modelValue', [innerValue.value, value])
|
||||
emit('change', {
|
||||
@ -620,9 +626,13 @@ function setTabLabel(index: number = 0) {
|
||||
if (region.value) {
|
||||
let items = []
|
||||
if (index === 0) {
|
||||
items = (datetimePickerView.value && datetimePickerView.value.getSelects()) || []
|
||||
items =
|
||||
(datetimePickerView.value && datetimePickerView.value.getSelects && datetimePickerView.value.getSelects()) ||
|
||||
(innerValue.value && getSelects('before'))
|
||||
} else {
|
||||
items = (datetimePickerView1.value && datetimePickerView1.value.getSelects()) || []
|
||||
items =
|
||||
(datetimePickerView1.value && datetimePickerView1.value.getSelects && datetimePickerView1.value.getSelects()) ||
|
||||
(endInnerValue.value && getSelects('after'))
|
||||
}
|
||||
return defaultDisplayFormat(items, true)
|
||||
}
|
||||
@ -633,16 +643,25 @@ function setTabLabel(index: number = 0) {
|
||||
* @param {Boolean} tab 是否修改tab展示值(尽在区域选择情况下生效)
|
||||
* @param {Boolean} isConfirm 是否提交当前修改
|
||||
*/
|
||||
function setShowValue(tab = false, isConfirm = false) {
|
||||
function setShowValue(tab: boolean = false, isConfirm: boolean = false, beforeMount: boolean = false) {
|
||||
if (region.value) {
|
||||
const items = (datetimePickerView.value && datetimePickerView.value.getSelects()) || []
|
||||
const endItems = (datetimePickerView1.value && datetimePickerView1.value.getSelects()) || []
|
||||
const items = beforeMount
|
||||
? (innerValue.value && getSelects('before')) || []
|
||||
: (datetimePickerView.value && datetimePickerView.value.getSelects && datetimePickerView.value.getSelects()) || []
|
||||
|
||||
const endItems = beforeMount
|
||||
? (endInnerValue.value && getSelects('after')) || []
|
||||
: (datetimePickerView1.value && datetimePickerView1.value.getSelects && datetimePickerView1.value.getSelects()) || []
|
||||
|
||||
showValue.value = tab
|
||||
? showValue.value
|
||||
: [props.modelValue[0] || isConfirm ? defaultDisplayFormat(items) : '', props.modelValue[1] || isConfirm ? defaultDisplayFormat(endItems) : '']
|
||||
showTabLabel.value = [defaultDisplayFormat(items, true), defaultDisplayFormat(endItems, true)]
|
||||
} else {
|
||||
const items = (datetimePickerView.value && datetimePickerView.value.getSelects()) || []
|
||||
const items = beforeMount
|
||||
? (innerValue.value && getSelects('before')) || []
|
||||
: (datetimePickerView.value && datetimePickerView.value.getSelects && datetimePickerView.value.getSelects()) || []
|
||||
|
||||
showValue.value = deepClone(props.modelValue || isConfirm ? defaultDisplayFormat(items) : '')
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<view :class="`wd-drop-menu ${customClass}`" @click.stop="noop">
|
||||
<view :style="customStyle" :class="`wd-drop-menu ${customClass}`" @click.stop="noop">
|
||||
<view class="wd-drop-menu__list">
|
||||
<view
|
||||
v-for="(item, index) in titleList"
|
||||
@ -34,7 +34,8 @@ import { getRect } from '../common/util'
|
||||
|
||||
type DropDirction = 'up' | 'down'
|
||||
interface Props {
|
||||
customClass?: string
|
||||
customClass: string
|
||||
customStyle: string
|
||||
zIndex: number
|
||||
direction: DropDirction
|
||||
modal: boolean
|
||||
@ -44,6 +45,7 @@ interface Props {
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
customClass: '',
|
||||
customStyle: '',
|
||||
zIndex: 12,
|
||||
direction: 'down',
|
||||
modal: true,
|
||||
@ -126,7 +128,7 @@ function fold(child?: any) {
|
||||
const { top, bottom } = rect
|
||||
|
||||
if (props.direction === 'down') {
|
||||
offset.value = bottom + 44
|
||||
offset.value = bottom
|
||||
// #ifdef H5
|
||||
// H5端,导航栏为普通元素,需要将组件移动到导航栏的下边沿
|
||||
// H5的导航栏高度为44px
|
||||
|
||||
@ -26,7 +26,6 @@
|
||||
<script lang="ts">
|
||||
export default {
|
||||
name: 'wd-input-number',
|
||||
behaviors: ['uni://form-field'],
|
||||
options: {
|
||||
virtualHost: true,
|
||||
addGlobalClass: true,
|
||||
|
||||
@ -127,7 +127,6 @@
|
||||
<script lang="ts">
|
||||
export default {
|
||||
name: 'wd-input',
|
||||
behaviors: ['uni://form-field'],
|
||||
options: {
|
||||
virtualHost: true,
|
||||
addGlobalClass: true,
|
||||
|
||||
@ -21,6 +21,11 @@
|
||||
}
|
||||
}
|
||||
|
||||
:deep(.wd-message-box){
|
||||
border-radius: $-message-box-radius;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
@include bdeep(message-box) {
|
||||
border-radius: $-message-box-radius;
|
||||
overflow: hidden;
|
||||
|
||||
@ -1,49 +1,51 @@
|
||||
<template>
|
||||
<wd-popup
|
||||
transition="zoom-in"
|
||||
v-model="show"
|
||||
:close-on-click-modal="closeOnClickModal"
|
||||
:lazy-render="lazyRender"
|
||||
custom-class="wd-message-box"
|
||||
@clickmodal="toggleModal('modal')"
|
||||
:z-index="zIndex"
|
||||
:duration="200"
|
||||
>
|
||||
<view :class="rootClass">
|
||||
<!--内容部分-->
|
||||
<view :class="bodyClass">
|
||||
<!--公共title-->
|
||||
<view v-if="title" class="wd-message-box__title">
|
||||
{{ title }}
|
||||
<view>
|
||||
<wd-popup
|
||||
transition="zoom-in"
|
||||
v-model="show"
|
||||
:close-on-click-modal="closeOnClickModal"
|
||||
:lazy-render="lazyRender"
|
||||
custom-class="wd-message-box"
|
||||
@clickmodal="toggleModal('modal')"
|
||||
:z-index="zIndex"
|
||||
:duration="200"
|
||||
>
|
||||
<view :class="rootClass">
|
||||
<!--内容部分-->
|
||||
<view :class="bodyClass">
|
||||
<!--公共title-->
|
||||
<view v-if="title" class="wd-message-box__title">
|
||||
{{ title }}
|
||||
</view>
|
||||
<!--其它类型-->
|
||||
<view class="wd-message-box__content">
|
||||
<!--prompt类型-->
|
||||
<block v-if="type === 'prompt'">
|
||||
<!--输入框-->
|
||||
<wd-input v-model="inputValue" :type="inputType" size="large" :placeholder="inputPlaceholder || '请输入'" @input="inputValChange" />
|
||||
<!--错误提示-->
|
||||
<view v-if="showErr" class="wd-message-box__input-error">
|
||||
{{ inputError || '输入的数据不合法' }}
|
||||
</view>
|
||||
</block>
|
||||
<!--使用插槽-->
|
||||
<slot v-if="useSlot"></slot>
|
||||
<!--使用文本-->
|
||||
<block v-else>{{ msg }}</block>
|
||||
</view>
|
||||
</view>
|
||||
<!--其它类型-->
|
||||
<view class="wd-message-box__content">
|
||||
<!--prompt类型-->
|
||||
<block v-if="type === 'prompt'">
|
||||
<!--输入框-->
|
||||
<wd-input v-model="inputValue" :type="inputType" size="large" :placeholder="inputPlaceholder || '请输入'" @input="inputValChange" />
|
||||
<!--错误提示-->
|
||||
<view v-if="showErr" class="wd-message-box__input-error">
|
||||
{{ inputError || '输入的数据不合法' }}
|
||||
</view>
|
||||
</block>
|
||||
<!--使用插槽-->
|
||||
<slot v-if="useSlot"></slot>
|
||||
<!--使用文本-->
|
||||
<block v-else>{{ msg }}</block>
|
||||
<!--action按钮组合-->
|
||||
<view :class="`wd-message-box__actions ${showCancelButton ? 'wd-message-box__flex' : 'wd-message-box__block'}`">
|
||||
<wd-button type="info" block v-if="showCancelButton" custom-style="margin-right: 16px;" @click="toggleModal('cancel')">
|
||||
{{ cancelButtonText || '取消' }}
|
||||
</wd-button>
|
||||
<wd-button block @click="toggleModal('confirm')">
|
||||
{{ confirmButtonText || '确定' }}
|
||||
</wd-button>
|
||||
</view>
|
||||
</view>
|
||||
<!--action按钮组合-->
|
||||
<view :class="`wd-message-box__actions ${showCancelButton ? 'wd-message-box__flex' : 'wd-message-box__block'}`">
|
||||
<wd-button type="info" block v-if="showCancelButton" custom-style="margin-right: 16px;" @click="toggleModal('cancel')">
|
||||
{{ cancelButtonText || '取消' }}
|
||||
</wd-button>
|
||||
<wd-button block @click="toggleModal('confirm')">
|
||||
{{ confirmButtonText || '确定' }}
|
||||
</wd-button>
|
||||
</view>
|
||||
</view>
|
||||
</wd-popup>
|
||||
</wd-popup>
|
||||
</view>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
export default {
|
||||
|
||||
@ -0,0 +1,81 @@
|
||||
/*
|
||||
* @Author: weisheng
|
||||
* @Date: 2023-08-21 13:03:42
|
||||
* @LastEditTime: 2023-08-21 17:24:57
|
||||
* @LastEditors: weisheng
|
||||
* @Description:
|
||||
* @FilePath: \wot-design-uni\src\uni_modules\wot-design-uni\components\wd-picker-view\type.ts
|
||||
* 记得注释
|
||||
*/
|
||||
|
||||
import { getType } from '../common/util'
|
||||
|
||||
export type ColumnItem = {
|
||||
value?: string | number | boolean
|
||||
label?: string
|
||||
disabled?: boolean
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 为props的value为array类型时提供format
|
||||
* @param {Array<String|Number|Object>} array 列数组
|
||||
* @param {string} valueKey valueKey
|
||||
* @param {string} labelKey labelKey
|
||||
*/
|
||||
export function formatArray(array: Array<string | number | ColumnItem | Array<string | number | ColumnItem>>, valueKey: string, labelKey: string) {
|
||||
let tempArray: Array<string | number | ColumnItem | Array<string | number | ColumnItem>> = array instanceof Array ? array : [array]
|
||||
// 检测第一层的type
|
||||
const firstLevelTypeList = new Set(array.map(getType))
|
||||
/**
|
||||
* 存在三种类型的合法数据
|
||||
* 1.数组是一维元素,所有元素都是原始值
|
||||
* 2.数组是一维元素,所有元素都是object
|
||||
* 3.数组是二维元素,二维元素可以是任意内容
|
||||
*/
|
||||
if (firstLevelTypeList.size !== 1 && firstLevelTypeList.has('object')) {
|
||||
// 原始值和引用类型不用混用
|
||||
throw Error('The columns are correct')
|
||||
}
|
||||
/**
|
||||
* 数组的所有一维子元素都不是array,说明是它是一个一维数组
|
||||
* 所以需要把一维的转成二维,这样方便统一处理
|
||||
*/
|
||||
if (!(array[0] instanceof Array)) {
|
||||
tempArray = [tempArray as Array<string | number | ColumnItem>]
|
||||
}
|
||||
// 经过上述处理,都已经变成了二维数组,再把每一项二维元素包装成object
|
||||
const result: Array<Array<ColumnItem>> = (tempArray as Array<Array<string | number | ColumnItem>>).map((col) => {
|
||||
return col.map((row) => {
|
||||
const isObj = getType(row)
|
||||
/* 针对原始值,包装成{valueKey,labelKey} */
|
||||
if (isObj !== 'object') {
|
||||
return {
|
||||
[valueKey]: row,
|
||||
[labelKey]: row
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 针对已经是object的,修补成{valueKey,labelKey}
|
||||
* 如果没有labelKey,用valueKey代替
|
||||
* 如果没有valueKey,用labelKey代替
|
||||
* valueKey,labelKey都没有,直接抛错
|
||||
*/
|
||||
// eslint-disable-next-line no-prototype-builtins
|
||||
if (!row.hasOwnProperty(valueKey) && !row.hasOwnProperty(labelKey)) {
|
||||
// eslint-disable-next-line prettier/prettier
|
||||
throw Error('Can\'t find valueKey and labelKey in columns')
|
||||
}
|
||||
// eslint-disable-next-line no-prototype-builtins
|
||||
if (!row.hasOwnProperty(labelKey)) {
|
||||
row[labelKey] = row[valueKey]
|
||||
}
|
||||
// eslint-disable-next-line no-prototype-builtins
|
||||
if (!row.hasOwnProperty(valueKey)) {
|
||||
row[valueKey] = row[labelKey]
|
||||
}
|
||||
return row as ColumnItem
|
||||
})
|
||||
})
|
||||
|
||||
return result
|
||||
}
|
||||
@ -5,7 +5,6 @@
|
||||
</view>
|
||||
<view :style="`height: ${columnsHeight - 20}px;`">
|
||||
<picker-view
|
||||
v-if="showPicker"
|
||||
mask-class="wd-picker-view__mask"
|
||||
indicator-class="wd-picker-view__roller"
|
||||
:indicator-style="`height: ${itemHeight}px;`"
|
||||
@ -45,17 +44,10 @@ export default {
|
||||
<script lang="ts" setup>
|
||||
import { getCurrentInstance, ref, watch, nextTick } from 'vue'
|
||||
import { deepClone, getType, isEqual, range } from '../common/util'
|
||||
|
||||
type ColumnItem = {
|
||||
value?: string | number | boolean
|
||||
label: string
|
||||
disabled?: boolean
|
||||
}
|
||||
import { ColumnItem, formatArray } from './type'
|
||||
|
||||
interface Props {
|
||||
customClass?: string
|
||||
// 是否展示picker(兼容支付宝和钉钉)
|
||||
showPicker: boolean
|
||||
// 加载中
|
||||
loading: boolean
|
||||
loadingColor: string
|
||||
@ -68,7 +60,7 @@ interface Props {
|
||||
// 初始值
|
||||
modelValue: string | number | boolean | Array<string | number | boolean>
|
||||
// 选择器数据
|
||||
columns: Array<string | string[] | ColumnItem>
|
||||
columns: Array<string | number | ColumnItem | Array<string | number | ColumnItem>>
|
||||
// 多级联动
|
||||
// eslint-disable-next-line @typescript-eslint/ban-types
|
||||
columnChange?: Function
|
||||
@ -77,7 +69,6 @@ interface Props {
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
customClass: '',
|
||||
loading: false,
|
||||
showPicker: true,
|
||||
loadingColor: '#4D80F0',
|
||||
columnsHeight: 217,
|
||||
valueKey: 'value',
|
||||
@ -86,7 +77,7 @@ const props = withDefaults(defineProps<Props>(), {
|
||||
})
|
||||
|
||||
// 格式化之后,用于render 列表的数据
|
||||
const formatColumns = ref<Array<Record<string, any>[]>>([])
|
||||
const formatColumns = ref<Array<Array<Record<string, any>>>>([])
|
||||
const itemHeight = ref<number>(35)
|
||||
const selectedIndex = ref<Array<number>>([]) // 格式化之后,每列选中的下标集合
|
||||
const preSelectedIndex = ref<Array<number>>([])
|
||||
@ -108,7 +99,7 @@ watch(
|
||||
() => props.columns,
|
||||
(newValue) => {
|
||||
// props初始化的时候格式化formatColumns交给value的observer来做
|
||||
formatColumns.value = formatArray(newValue)
|
||||
formatColumns.value = formatArray(newValue, props.valueKey, props.labelKey)
|
||||
/**
|
||||
* 每次改变都要重置选中项
|
||||
* 1.选中每列的第一个
|
||||
@ -172,7 +163,7 @@ function selectWithValue(value) {
|
||||
if (type.indexOf(valueType) === -1) throw Error(`value must be one of ${type.toString()}`)
|
||||
// 在props初始化的时候有可能会调用此函数,此时需要保证formatColumns已经被设置,关于此问题更多详情参考/ISSUE.md。
|
||||
if (formatColumns.value.length === 0) {
|
||||
formatColumns.value = formatArray(props.columns)
|
||||
formatColumns.value = formatArray(props.columns, props.valueKey, props.labelKey)
|
||||
}
|
||||
/**
|
||||
* 1.单key转为Array<key>
|
||||
@ -234,67 +225,6 @@ function selectWithIndex(columnIndex, rowIndex) {
|
||||
return selectedIndex.value
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 为props的value为array类型时提供format
|
||||
* @param {Array<String|Number|Boolean|Object>} array
|
||||
*/
|
||||
function formatArray(array) {
|
||||
array = array instanceof Array ? array : [array]
|
||||
// 检测第一层的type
|
||||
const firstLevelTypeList = new Set(array.map(getType))
|
||||
/**
|
||||
* 存在三种类型的合法数据
|
||||
* 1.数组是一维元素,所有元素都是原始值
|
||||
* 2.数组是一维元素,所有元素都是object
|
||||
* 3.数组是二维元素,二维元素可以是任意内容
|
||||
*/
|
||||
if (firstLevelTypeList.size !== 1 && firstLevelTypeList.has('object')) {
|
||||
// 原始值和引用类型不用混用
|
||||
throw Error('The columns are correct')
|
||||
}
|
||||
/**
|
||||
* 数组的所有一维子元素都不是array,说明是它是一个一维数组
|
||||
* 所以需要把一维的转成二维,这样方便统一处理
|
||||
*/
|
||||
if (!(array[0] instanceof Array)) {
|
||||
array = [array]
|
||||
}
|
||||
// 经过上述处理,都已经变成了二维数组,再把每一项二维元素包装成object
|
||||
return array.map((col) =>
|
||||
col.map((row) => {
|
||||
const isObj = getType(row)
|
||||
const { valueKey, labelKey } = props
|
||||
/* 针对原始值,包装成{valueKey,labelKey} */
|
||||
if (isObj !== 'object') {
|
||||
return {
|
||||
[valueKey]: row,
|
||||
[labelKey]: row
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 针对已经是object的,修补成{valueKey,labelKey}
|
||||
* 如果没有labelKey,用valueKey代替
|
||||
* 如果没有valueKey,用labelKey代替
|
||||
* valueKey,labelKey都没有,直接抛错
|
||||
*/
|
||||
// eslint-disable-next-line no-prototype-builtins
|
||||
if (!row.hasOwnProperty(valueKey) && !row.hasOwnProperty(labelKey)) {
|
||||
// eslint-disable-next-line prettier/prettier
|
||||
throw Error('Can\'t find valueKey and labelKey in columns')
|
||||
}
|
||||
// eslint-disable-next-line no-prototype-builtins
|
||||
if (!row.hasOwnProperty(labelKey)) {
|
||||
row[labelKey] = row[valueKey]
|
||||
}
|
||||
// eslint-disable-next-line no-prototype-builtins
|
||||
if (!row.hasOwnProperty(valueKey)) {
|
||||
row[valueKey] = row[labelKey]
|
||||
}
|
||||
return row
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 滚动选中时更新选中的索引、触发change事件
|
||||
* @return {Number|Array<Number>}选中项的下标或者集合
|
||||
@ -389,7 +319,6 @@ function getSelects() {
|
||||
if (selects.length === 1) {
|
||||
return selects[0]
|
||||
}
|
||||
|
||||
return selects
|
||||
}
|
||||
|
||||
@ -449,7 +378,7 @@ function setColumnData(columnIndex, data, jumpTo = 0) {
|
||||
selectedIndex.value = selectWithIndex(columnIndex, jumpTo)
|
||||
// 经过formatArray处理的数据会变成二维数组,一定要拍成一维的。
|
||||
// ps 小程序基础库v2.9.3才可以用flat
|
||||
formatColumns.value[columnIndex] = formatArray(data).reduce((acc, val) => acc.concat(val), [])
|
||||
formatColumns.value[columnIndex] = formatArray(data, props.valueKey, props.labelKey).reduce((acc, val) => acc.concat(val), [])
|
||||
}
|
||||
|
||||
function getColumnsData() {
|
||||
|
||||
@ -69,7 +69,6 @@
|
||||
<script lang="ts">
|
||||
export default {
|
||||
name: 'wd-picker',
|
||||
behaviors: ['uni://form-field'],
|
||||
options: {
|
||||
virtualHost: true,
|
||||
addGlobalClass: true,
|
||||
@ -80,8 +79,9 @@ export default {
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { getCurrentInstance, onBeforeMount, ref, watch, computed, onMounted } from 'vue'
|
||||
import { deepClone, defaultDisplayFormat, getType } from '../common/util'
|
||||
import { deepClone, defaultDisplayFormat, getType, isArray } from '../common/util'
|
||||
import { useCell } from '../mixins/useCell'
|
||||
import { ColumnItem, formatArray } from '../wd-picker-view/type'
|
||||
|
||||
interface Props {
|
||||
customClass?: string
|
||||
@ -126,9 +126,9 @@ interface Props {
|
||||
// 选项对象中,展示的文本对应的 key
|
||||
labelKey: string
|
||||
// 初始值
|
||||
modelValue: string | number | boolean | Array<string | number | boolean>
|
||||
modelValue: string | number | Array<string | number>
|
||||
// 选择器数据
|
||||
columns: Array<string | string[]>
|
||||
columns: Array<string | number | ColumnItem | Array<string | number | ColumnItem>>
|
||||
// 多级联动
|
||||
// eslint-disable-next-line @typescript-eslint/ban-types
|
||||
columnChange?: Function
|
||||
@ -182,8 +182,8 @@ const popupShow = ref<boolean>(false)
|
||||
// 选定后展示的选中项
|
||||
const showValue = ref<string>('')
|
||||
const pickerValue = ref<string | number | boolean | (string | number | boolean)[]>('')
|
||||
const displayColumns = ref<Array<string | string[]>>([]) // 传入 pickerView 的columns
|
||||
const resetColumns = ref<Array<string | string[]>>([]) // 保存之前的 columns,当取消时,将数据源回滚,避免多级联动数据源不正确的情况
|
||||
const displayColumns = ref<Array<string | number | ColumnItem | Array<string | number | ColumnItem>>>([]) // 传入 pickerView 的columns
|
||||
const resetColumns = ref<Array<string | number | ColumnItem | Array<string | number | ColumnItem>>>([]) // 保存之前的 columns,当取消时,将数据源回滚,避免多级联动数据源不正确的情况
|
||||
const isPicking = ref<boolean>(false) // 判断pickview是否还在滑动中
|
||||
const hasConfirmed = ref<boolean>(false) // 判断用户是否点击了确认按钮
|
||||
|
||||
@ -264,6 +264,7 @@ const { proxy } = getCurrentInstance() as any
|
||||
const emit = defineEmits(['confirm', 'open', 'cancel', 'update:modelValue'])
|
||||
|
||||
onMounted(() => {
|
||||
props.modelValue && setShowValue(getSelects(props.modelValue))
|
||||
if (props.modelValue && pickerViewWd.value && pickerViewWd.value.getSelects) {
|
||||
setShowValue(pickerViewWd.value!.getSelects())
|
||||
}
|
||||
@ -274,6 +275,51 @@ onBeforeMount(() => {
|
||||
resetColumns.value = deepClone(props.columns)
|
||||
})
|
||||
|
||||
/**
|
||||
* @description 根据传入的value,picker组件获取当前cell展示值。
|
||||
* @param {String|Number|Array<String|Number|Array<any>>}value
|
||||
*/
|
||||
function getSelects(value) {
|
||||
const formatColumns = formatArray(props.columns, props.valueKey, props.labelKey)
|
||||
if (props.columns.length === 0) return
|
||||
|
||||
// 使其默认选中首项
|
||||
if (value === '' || value === null || value === undefined || (getType(value) === 'array' && value.length === 0)) {
|
||||
value = formatColumns.map((col) => {
|
||||
return col[0][props.valueKey]
|
||||
})
|
||||
}
|
||||
const valueType = getType(value)
|
||||
const type = ['string', 'number', 'boolean', 'array']
|
||||
if (type.indexOf(valueType) === -1) return []
|
||||
/**
|
||||
* 1.单key转为Array<key>
|
||||
* 2.根据formatColumns的长度截取Array<String>,保证下面的遍历不溢出
|
||||
* 3.根据每列的key值找到选项中value为此key的下标并记录
|
||||
*/
|
||||
value = value instanceof Array ? value : [value]
|
||||
value = value.slice(0, formatColumns.length)
|
||||
|
||||
if (value.length === 0) {
|
||||
value = formatColumns.map(() => 0)
|
||||
}
|
||||
let selected: number[] = []
|
||||
value.forEach((target, col) => {
|
||||
let row = formatColumns[col].findIndex((row) => {
|
||||
return row[props.valueKey].toString() === target.toString()
|
||||
})
|
||||
row = row === -1 ? 0 : row
|
||||
selected.push(row)
|
||||
})
|
||||
|
||||
const selects = selected.map((row, col) => formatColumns[col][row])
|
||||
// 单列选择器,则返回单项
|
||||
if (selects.length === 1) {
|
||||
return selects[0]
|
||||
}
|
||||
return selects
|
||||
}
|
||||
|
||||
// 对外暴露方法,打开弹框
|
||||
function open() {
|
||||
showPopup()
|
||||
|
||||
@ -38,16 +38,18 @@ interface Props {
|
||||
modal: boolean
|
||||
zIndex: number
|
||||
hideWhenClose: boolean
|
||||
modalStyle?: string
|
||||
modalStyle: string
|
||||
safeAreaInsetBottom: boolean
|
||||
modelValue: boolean
|
||||
customStyle?: string
|
||||
customStyle: string
|
||||
lazyRender: boolean
|
||||
customClass?: string
|
||||
customClass: string
|
||||
}
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
customClass: '',
|
||||
customStyle: '',
|
||||
modalStyle: '',
|
||||
position: 'center',
|
||||
closeOnClickModal: true,
|
||||
modal: true,
|
||||
|
||||
@ -6,7 +6,6 @@
|
||||
<script lang="ts">
|
||||
export default {
|
||||
name: 'wd-radio-group',
|
||||
behaviors: ['uni://form-field'],
|
||||
options: {
|
||||
virtualHost: true,
|
||||
addGlobalClass: true,
|
||||
|
||||
@ -21,7 +21,6 @@
|
||||
<script lang="ts">
|
||||
export default {
|
||||
name: 'wd-rate',
|
||||
behaviors: ['uni://form-field'],
|
||||
options: {
|
||||
addGlobalClass: true,
|
||||
virtualHost: true,
|
||||
|
||||
@ -94,6 +94,13 @@ onMounted(() => {
|
||||
width.value = lastWidth
|
||||
// 监听滚动事件
|
||||
onScrollHandler = () => {
|
||||
const query = uni
|
||||
.createSelectorQuery()
|
||||
// #ifndef MP-ALIPAY
|
||||
.in(proxy)
|
||||
// #endif
|
||||
.select('.wd-resize__container')
|
||||
.boundingClientRect()
|
||||
query.exec(([res]) => {
|
||||
// 前两次滚动事件被触发,说明 created 的修改已渲染,通知用户代码当前容器大小
|
||||
if (scrollEventCount.value++ === 0) {
|
||||
|
||||
@ -50,7 +50,6 @@
|
||||
<script lang="ts">
|
||||
export default {
|
||||
name: 'wd-search',
|
||||
behaviors: ['uni://form-field'],
|
||||
options: {
|
||||
virtualHost: true,
|
||||
addGlobalClass: true,
|
||||
|
||||
@ -88,7 +88,6 @@
|
||||
<script lang="ts">
|
||||
export default {
|
||||
name: 'wd-select-picker',
|
||||
behaviors: ['uni://form-field'],
|
||||
options: {
|
||||
addGlobalClass: true,
|
||||
virtualHost: true,
|
||||
|
||||
@ -44,7 +44,6 @@
|
||||
<script lang="ts">
|
||||
export default {
|
||||
name: 'wd-slider',
|
||||
behaviors: ['uni://form-field'],
|
||||
options: {
|
||||
addGlobalClass: true,
|
||||
virtualHost: true,
|
||||
|
||||
@ -67,7 +67,9 @@
|
||||
line-height: 1.1;
|
||||
|
||||
@include when(active) {
|
||||
:deep(.wd-sort-button__icon-up, .wd-sort-button__icon-down) {
|
||||
|
||||
:deep(.wd-sort-button__icon-up),
|
||||
:deep(.wd-sort-button__icon-down) {
|
||||
transform: scale(calc((10 / 14)));
|
||||
}
|
||||
}
|
||||
|
||||
@ -3,9 +3,9 @@
|
||||
<view
|
||||
:class="`wd-swipe-action ${customClass}`"
|
||||
@click.stop="onClick()"
|
||||
@touchstart="startDrag"
|
||||
@touchmove="stopPropagation ? nothing : ''"
|
||||
@touchmove.capture="onDrag"
|
||||
@touchstart="startDrag"
|
||||
@touchmove.prevent="onDrag"
|
||||
@touchend="endDrag"
|
||||
@touchcancel="endDrag"
|
||||
>
|
||||
@ -43,7 +43,7 @@ import { getRect } from '../common/util'
|
||||
interface Props {
|
||||
customClass?: string
|
||||
// eslint-disable-next-line @typescript-eslint/ban-types
|
||||
beforeClose: Function
|
||||
beforeClose?: Function
|
||||
disabled: boolean
|
||||
modelValue: string
|
||||
}
|
||||
@ -51,8 +51,7 @@ interface Props {
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
customStyle: '',
|
||||
modelValue: 'close',
|
||||
disabled: false,
|
||||
beforeClose: (v) => v
|
||||
disabled: false
|
||||
})
|
||||
|
||||
const wrapperStyle = ref<string>('')
|
||||
@ -280,7 +279,7 @@ function close(reason, position?: string) {
|
||||
}
|
||||
|
||||
if (reason && position) {
|
||||
props.beforeClose(reason, position)
|
||||
props.beforeClose && props.beforeClose(reason, position)
|
||||
}
|
||||
|
||||
swipeMove(0)
|
||||
|
||||
@ -6,7 +6,6 @@
|
||||
<script lang="ts">
|
||||
export default {
|
||||
name: 'wd-switch',
|
||||
behaviors: ['uni://form-field'],
|
||||
options: {
|
||||
addGlobalClass: true,
|
||||
virtualHost: true,
|
||||
|
||||
@ -42,7 +42,6 @@
|
||||
<script lang="ts">
|
||||
export default {
|
||||
name: 'wd-upload',
|
||||
behaviors: ['uni://form-field'],
|
||||
options: {
|
||||
addGlobalClass: true,
|
||||
virtualHost: true,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user