From 8e9c8f51dda9a0745aecedc54a5701b32d14a9e2 Mon Sep 17 00:00:00 2001 From: chaorenluo <1243357953@qq.com> Date: Tue, 5 Nov 2024 13:55:11 +0800 Subject: [PATCH] =?UTF-8?q?=E9=87=87=E7=94=A8=E7=AC=AC=E4=B8=80=E7=89=88pi?= =?UTF-8?q?cker?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- web/package.json | 1 + .../pages/edit/components/Picker/event.ts | 24 + .../pages/edit/components/Picker/index.vue | 614 +++++------------- .../pages/edit/components/Picker/list.ts | 145 +++++ .../edit/components/Picker/pickerHeader.vue | 83 --- .../edit/components/Picker/pickerList.vue | 250 ------- .../pages/edit/components/Picker/utils.ts | 29 - .../MultilevelModule/BaseMultilevel/index.vue | 11 +- web/src/render/main.js | 1 + 9 files changed, 353 insertions(+), 805 deletions(-) create mode 100644 web/src/management/pages/edit/components/Picker/event.ts create mode 100644 web/src/management/pages/edit/components/Picker/list.ts delete mode 100644 web/src/management/pages/edit/components/Picker/pickerHeader.vue delete mode 100644 web/src/management/pages/edit/components/Picker/pickerList.vue delete mode 100644 web/src/management/pages/edit/components/Picker/utils.ts diff --git a/web/package.json b/web/package.json index f9060096..9022a32d 100644 --- a/web/package.json +++ b/web/package.json @@ -22,6 +22,7 @@ "axios": "^1.4.0", "clipboard": "^2.0.11", "crypto-js": "^4.2.0", + "default-passive-events": "^2.0.0", "echarts": "^5.5.0", "element-plus": "^2.8.3", "lodash-es": "^4.17.21", diff --git a/web/src/management/pages/edit/components/Picker/event.ts b/web/src/management/pages/edit/components/Picker/event.ts new file mode 100644 index 00000000..b9a041a5 --- /dev/null +++ b/web/src/management/pages/edit/components/Picker/event.ts @@ -0,0 +1,24 @@ + +interface IEvent { + handleConfirm: () => void, + handleCancel: () => void +} + +const useEvent = ({ emit, ctx }: any): IEvent => { + const handleConfirm = () => { + emit('confirm', ctx.list[ctx.index]) + emit('update:modelValue', false) + } + + const handleCancel = () => { + emit('update:modelValue', false) + emit('cancel', false) + } + + return { + handleConfirm, + handleCancel + } +} + +export default useEvent diff --git a/web/src/management/pages/edit/components/Picker/index.vue b/web/src/management/pages/edit/components/Picker/index.vue index 2c69dab2..9766eefa 100644 --- a/web/src/management/pages/edit/components/Picker/index.vue +++ b/web/src/management/pages/edit/components/Picker/index.vue @@ -1,468 +1,206 @@ - + \ No newline at end of file + +.x-picker__content-item { + height: 40px; + line-height: 40px; + transition: color .5s; + text-align: center +} + +.slide-picker-enter-active, +.slide-picker-leave-active { + transition: all .5s; +} + +.slide-picker-enter-from, +.slide-picker-leave-to { + transform: translateY(100%); +} + + diff --git a/web/src/management/pages/edit/components/Picker/list.ts b/web/src/management/pages/edit/components/Picker/list.ts new file mode 100644 index 00000000..0d7b0289 --- /dev/null +++ b/web/src/management/pages/edit/components/Picker/list.ts @@ -0,0 +1,145 @@ +import { ref, computed } from 'vue' +import type { Ref } from 'vue' + +interface IList { + box: Ref, + list: Ref>, + getOffsetY: any, + getStyle: any, + handleMove: (e: TouchEvent) => void, + handleStart: (e: TouchEvent) => void, + handleEnd: (e: TouchEvent) => void, + goItem: (idx: number) => void, + resetData: () => void, + index: Ref, + isTouch:boolean +} + +const useList = (props: any): IList => { + const colors = ['gray', '#ccc', '#ddd', '#eee'] + const scales = [.96, .9, .88, .84] + const isTouch = 'ontouchstart' in window || navigator.maxTouchPoints > 0 + let startY: number, activeIndex = 0, isDragging = false + const box = ref() + const offY = ref() + const index = ref(0) + const list = ref(props.list) + const getStyle = (idx: number) => { + let color = '#000', scale = 1 + const len = colors.length - 1 + if (idx > activeIndex) { + const _idx = idx - activeIndex > len ? len : idx - activeIndex - 1 + color = colors[_idx] + scale = scales[_idx] + } else if (idx < activeIndex) { + const _idx = activeIndex - idx > len ? len : activeIndex - idx - 1 + color = colors[_idx] + scale = scales[_idx] + } + return { color, transform: `scale(${scale})` } + } + + // 节流 + const throttle = function (callback: any, delay = 20) { + let timer: any = null + return function (args: any) { + if (timer) { + return + } + timer = setTimeout(() => { + callback(args) + timer = null + }, delay) + } + } + + // 移动的实现 + const move = throttle((e: any) => { + const clientY = e.touches ? e.touches[0].clientY : e.clientY; + offY.value = clientY - startY + if (offY.value > 40) { + offY.value = 40 + } else if (offY.value < -box.value.offsetHeight - 40) { + offY.value = -box.value.offsetHeight - 40 + } + // 计算当前位置的就近下标 + index.value = Math.abs(Math.ceil(offY.value / 40)) + // 判断顶部和底部的一个界限,然后做一个位置的重置 + if (index.value <= 0 || offY.value > 0) { + index.value = 0 + } else if (index.value > list.value.length - 1 || offY.value < -box.value.offsetHeight - 18) { + index.value = list.value.length - 1 + } + activeIndex = index.value + }) + + const goItem = (idx: number) => { + index.value = idx; + activeIndex = idx; + } + + const resetData = () => { + startY = 0; + activeIndex = 0 + index.value = 0 + box.value = null; + offY.value = null; + } + + const handleStart = (e: MouseEvent | TouchEvent) => { + isDragging = true + const transform = box.value.style.transform + transform.match(/,(.*)px/) + const clientY = e instanceof MouseEvent ? e.clientY : e.touches[0].clientY + startY = clientY - Number(RegExp.$1) + + document.addEventListener('mousemove', handleMove) + document.addEventListener('mouseup', handleEnd) + + } + + const handleMove = (e: MouseEvent | TouchEvent) => { + if (isDragging) { + move(e) + } + } + + const handleEnd = () => { + // 重置当前位置,加setTimeout避免出现Bug + isDragging = false + setTimeout(() => { + offY.value = -index.value * 40 - 18 + }, 100) + document.removeEventListener('mousemove', handleMove) + document.removeEventListener('mouseup', handleEnd) + } + + const getOffsetY = computed(() => { + if (typeof offY.value === 'number') { + return { + transform: `translate(-50%, ${offY.value}px)` + } + } else { + return { + transform: 'translate(-50%, -18px)' + } + } + }) + + return { + box, + list, + getOffsetY, + getStyle, + handleMove, + handleStart, + handleEnd, + goItem, + resetData, + index, + isTouch + } +} + +export default useList + diff --git a/web/src/management/pages/edit/components/Picker/pickerHeader.vue b/web/src/management/pages/edit/components/Picker/pickerHeader.vue deleted file mode 100644 index ad4ca08e..00000000 --- a/web/src/management/pages/edit/components/Picker/pickerHeader.vue +++ /dev/null @@ -1,83 +0,0 @@ - - - - - \ No newline at end of file diff --git a/web/src/management/pages/edit/components/Picker/pickerList.vue b/web/src/management/pages/edit/components/Picker/pickerList.vue deleted file mode 100644 index da66289b..00000000 --- a/web/src/management/pages/edit/components/Picker/pickerList.vue +++ /dev/null @@ -1,250 +0,0 @@ - - - - - \ No newline at end of file diff --git a/web/src/management/pages/edit/components/Picker/utils.ts b/web/src/management/pages/edit/components/Picker/utils.ts deleted file mode 100644 index 5502f1b3..00000000 --- a/web/src/management/pages/edit/components/Picker/utils.ts +++ /dev/null @@ -1,29 +0,0 @@ -export const DEFTAULT_ITEM_HEIGHT = 44 - -// 兼容pc 移动端 -export const HAS_TOUCH = 'ontouchstart' in window -export const START_EVENT = HAS_TOUCH ? 'touchstart' : 'mousedown' -export const MOVE_EVENT = HAS_TOUCH ? 'touchmove' : 'mousemove' -export const END_EVENT = HAS_TOUCH ? 'touchend' : 'mouseup' - -export const getClient = (e:any) => { - const clientX = HAS_TOUCH ? e.changedTouches[0].clientX : e.clientX - const clientY = HAS_TOUCH ? e.changedTouches[0].clientY : e.clientY - return { - x: clientX, - y: clientY - } -} - -export const isPC = () => { - const userAgentInfo = navigator.userAgent - const Agents = ['Android', 'iPhone', 'SymbianOS', 'Windows Phone', 'iPad', 'iPod'] - let flag = true - for (let v = 0; v < Agents.length; v++) { - if (userAgentInfo.indexOf(Agents[v]) > 0) { - flag = false - break - } - } - return flag -} \ No newline at end of file diff --git a/web/src/materials/questions/widgets/MultilevelModule/BaseMultilevel/index.vue b/web/src/materials/questions/widgets/MultilevelModule/BaseMultilevel/index.vue index 0522cce4..68db39f4 100644 --- a/web/src/materials/questions/widgets/MultilevelModule/BaseMultilevel/index.vue +++ b/web/src/materials/questions/widgets/MultilevelModule/BaseMultilevel/index.vue @@ -23,8 +23,8 @@ - +
@@ -105,8 +105,8 @@ const handleChange = async(val,i) => { } const onConfirm = (val) => { - valList.value[pickIndex.value] = val[0]; - handleChange(val[0], pickIndex.value); + valList.value[pickIndex.value] = val; + handleChange(val, pickIndex.value); pickIndex.value=-1 } const onCancel = () => { @@ -115,12 +115,13 @@ const onCancel = () => { const showPickPop = (list, index) => { pickPop.value = true; - listPop.value = [list]; + listPop.value = list; pickIndex.value = index } const updateEquipment = () => { isMobile.value = isInMobile() + pickPop.value = false } onMounted(() => { diff --git a/web/src/render/main.js b/web/src/render/main.js index ca68f229..e097d4ca 100644 --- a/web/src/render/main.js +++ b/web/src/render/main.js @@ -3,6 +3,7 @@ import App from './App.vue' import EventBus from './utils/eventbus' import router from './router' import { createPinia } from 'pinia' +import 'default-passive-events' const app = createApp(App) const pinia = createPinia()