更新:登录功能

This commit is contained in:
2025-11-04 12:37:04 +08:00
commit a21fb92916
897 changed files with 51500 additions and 0 deletions

View File

@@ -0,0 +1,64 @@
@import '../common/abstracts/variable';
@import '../common/abstracts/mixin';
.wot-theme-dark {
@include b(floating-panel) {
background: $-dark-background2;
@include e(content) {
background: $-dark-background2;
}
}
}
@include b(floating-panel) {
position: fixed;
bottom: 0;
left: 0;
z-index: $-floating-panel-z-index;
display: flex;
flex-direction: column;
box-sizing: border-box;
width: 100vw;
border-top-left-radius: $-floating-panel-radius;
border-top-right-radius: $-floating-panel-radius;
background-color: $-floating-panel-bg;
touch-action: none;
will-change: transform;
@include when(safe) {
padding-bottom: constant(safe-area-inset-bottom);
padding-bottom: env(safe-area-inset-bottom);
}
&::after {
position: absolute;
bottom: -100vh;
display: block;
width: 100vw;
height: 100vh;
content: '';
background-color: inherit;
}
@include e(header) {
display: flex;
justify-content: center;
align-items: center;
height: $-floating-panel-header-height;
cursor: grab;
user-select: none;
&-bar {
width: $-floating-panel-bar-width;
height: $-floating-panel-bar-height;
background-color: $-floating-panel-bar-bg;
border-radius: $-floating-panel-bar-radius;
}
}
@include e(content) {
flex: 1;
min-width: 0;
min-height: 0;
background-color: $-floating-panel-content-bg;
}
}

View File

@@ -0,0 +1,32 @@
import type { ExtractPropTypes } from 'vue'
import { baseProps, makeArrayProp, makeBooleanProp, makeNumberProp, makeNumericProp, truthProp } from '../common/props'
export const floatingPanelProps = {
...baseProps,
/**
* 面板的显示高度
*/
height: makeNumberProp(0),
/**
* 设置自定义锚点,默认值 [100, windowHeight * 0.6]
*/
anchors: makeArrayProp<number>(),
/**
* 弹出面板是否设置底部安全距离iphone X 类型的机型)
*/
safeAreaInsetBottom: makeBooleanProp(false),
/**
* 是否显示滚动条,默认值为 true
*/
showScrollbar: truthProp,
/**
* 动画时长,单位毫秒,默认值为 300ms
*/
duration: makeNumericProp(300),
/**
* 是否允许内容区容器拖拽,默认值为 true
*/
contentDraggable: truthProp
}
export type FloatingPanelProps = ExtractPropTypes<typeof floatingPanelProps>

View File

@@ -0,0 +1,140 @@
<template>
<view
:class="`wd-floating-panel ${customClass} ${safeAreaInsetBottom ? 'is-safe' : ''}`"
:style="rootStyle"
@touchstart.passive="handleTouchStart"
@touchmove.passive="handleTouchMove"
@touchend="handleTouchEnd"
@touchcancel="handleTouchEnd"
>
<view :class="`wd-floating-panel__header`">
<view :class="`wd-floating-panel__header-bar`"></view>
</view>
<scroll-view
:class="`wd-floating-panel__content`"
data-id="content"
:show-scrollbar="showScrollbar"
scroll-y
@touchmove.stop.prevent="handleTouchMove"
>
<slot />
</scroll-view>
</view>
</template>
<script lang="ts">
export default {
name: 'wd-floating-panel',
options: {
virtualHost: true,
addGlobalClass: true,
styleIsolation: 'shared'
}
}
</script>
<script lang="ts" setup>
import { computed, onBeforeMount, ref, watch, type CSSProperties } from 'vue'
import { floatingPanelProps } from './type'
import { addUnit, closest, objToStyle } from '../common/util'
import { useTouch } from '../composables/useTouch'
const touch = useTouch()
const props = defineProps(floatingPanelProps)
const emit = defineEmits(['update:height', 'height-change'])
const heightValue = ref<number>(props.height)
const DAMP = 0.2 // 阻尼系数
let startY: number // 起始位置
const windowHeight = ref<number>(0)
const dragging = ref<boolean>(false) // 是否正在拖拽
const boundary = computed(() => ({
min: props.anchors[0] ? props.anchors[0] : 100,
max: props.anchors[props.anchors.length - 1] ? props.anchors[props.anchors.length - 1] : Math.round(windowHeight.value * 0.6)
}))
const anchors = computed(() => (props.anchors.length >= 2 ? props.anchors : [boundary.value.min, boundary.value.max]))
const rootStyle = computed(() => {
const style: CSSProperties = {
height: addUnit(boundary.value.max),
transform: `translateY(calc(100% + ${addUnit(-heightValue.value)}))`,
transition: !dragging.value ? `transform ${props.duration}ms cubic-bezier(0.18, 0.89, 0.32, 1.28)` : 'none'
}
return `${objToStyle(style)}${props.customStyle}`
})
const updateHeight = (value: number) => {
heightValue.value = value
emit('update:height', value)
}
const handleTouchStart = (event: TouchEvent) => {
touch.touchStart(event)
dragging.value = true
startY = -heightValue.value
}
const handleTouchMove = (event: TouchEvent) => {
const target = event.currentTarget as any
if (target.dataset.id == 'content') {
if (!props.contentDraggable) return
}
touch.touchMove(event)
const moveY = touch.deltaY.value + startY
updateHeight(-ease(moveY))
}
const handleTouchEnd = () => {
dragging.value = false
updateHeight(closest(anchors.value, heightValue.value))
if (heightValue.value !== -startY) {
emit('height-change', { height: heightValue.value })
}
}
const ease = (y: number) => {
const absDistance = Math.abs(y)
const { min, max } = boundary.value
if (absDistance > max) {
return -(max + (absDistance - max) * DAMP)
}
if (absDistance < min) {
return -(min - (min - absDistance) * DAMP)
}
return y
}
watch(
() => props.height,
(value) => {
heightValue.value = value
}
)
watch(
boundary,
() => {
updateHeight(closest(anchors.value, heightValue.value))
},
{ immediate: true }
)
onBeforeMount(() => {
const { windowHeight: _windowHeight } = uni.getSystemInfoSync()
windowHeight.value = _windowHeight
})
</script>
<style lang="scss" scoped>
@import './index.scss';
</style>