更新:登录功能
This commit is contained in:
@@ -0,0 +1,66 @@
|
||||
@import '../common/abstracts/variable';
|
||||
@import '../common/abstracts/mixin';
|
||||
|
||||
.wot-theme-dark {
|
||||
@include b(drop-item) {
|
||||
color: $-dark-color;
|
||||
|
||||
@include e(tip) {
|
||||
color: $-dark-color3;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@include b(drop-item) {
|
||||
position: fixed;
|
||||
right: 0;
|
||||
left: 0;
|
||||
overflow: hidden;
|
||||
font-size: $-drop-menu-item-fs;
|
||||
color: $-drop-menu-item-color;
|
||||
width: 100%;
|
||||
z-index: 101;
|
||||
|
||||
@include e(popup){
|
||||
position: absolute;
|
||||
max-height: 80%;
|
||||
}
|
||||
|
||||
@include e(option) {
|
||||
display: flex;
|
||||
height: $-drop-menu-item-height;
|
||||
line-height: $-drop-menu-item-height;
|
||||
padding: 0 $-drop-menu-side-padding;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
transition: color .2s;
|
||||
|
||||
@include when(active) {
|
||||
color: $-drop-menu-item-color-active;
|
||||
}
|
||||
}
|
||||
|
||||
@include e(title){
|
||||
display: block;
|
||||
}
|
||||
|
||||
@include e(tip) {
|
||||
display: inline-block;
|
||||
color: $-drop-menu-item-color-tip;
|
||||
font-size: $-drop-menu-item-fs-tip;
|
||||
margin-left: 2px;
|
||||
}
|
||||
|
||||
@include edeep(icon){
|
||||
display: block;
|
||||
font-size: $-drop-menu-option-check-size;
|
||||
}
|
||||
|
||||
@include e(modal) {
|
||||
position: fixed;
|
||||
left: 0;
|
||||
right: 0;
|
||||
background: rgba(0, 0, 0, 0.7);
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
import type { ComponentPublicInstance, ExtractPropTypes, PropType } from 'vue'
|
||||
import { baseProps, makeArrayProp, makeBooleanProp, makeNumericProp, makeStringProp, numericProp } from '../common/props'
|
||||
|
||||
export type DropMenuItemBeforeToggleOption = {
|
||||
// 操作状态:true 打开下拉菜单,false 关闭下拉菜单
|
||||
status: boolean
|
||||
// 回调函数,用于控制是否允许打开或关闭下拉菜单,true 允许打开或关闭,false 不允许打开或关闭
|
||||
resolve: (isPass: boolean) => void
|
||||
}
|
||||
|
||||
export type DropMenuItemBeforeToggle = (option: DropMenuItemBeforeToggleOption) => void
|
||||
|
||||
export const dorpMenuItemProps = {
|
||||
...baseProps,
|
||||
/**
|
||||
* DropMenuItem 左侧文字样式
|
||||
*/
|
||||
customTitle: makeStringProp(''),
|
||||
/**
|
||||
* DropMenuItem 右侧 icon 样式
|
||||
*/
|
||||
customIcon: makeStringProp(''),
|
||||
/**
|
||||
* 当前选中项对应选中的 value
|
||||
*/
|
||||
modelValue: [String, Number],
|
||||
/**
|
||||
* 列表数据,对应数据结构 [{label: '标题', value: '0', tip: '提示文字'}]
|
||||
*/
|
||||
options: makeArrayProp<Record<string, any>>(),
|
||||
/**
|
||||
* 禁用菜单
|
||||
*/
|
||||
disabled: makeBooleanProp(false),
|
||||
/**
|
||||
* 选中的图标名称(可选名称在 wd-icon 组件中)
|
||||
*/
|
||||
iconName: makeStringProp('check'),
|
||||
/**
|
||||
* 菜单标题
|
||||
*/
|
||||
title: String,
|
||||
/**
|
||||
* 菜单图标
|
||||
*/
|
||||
icon: makeStringProp('arrow-down'),
|
||||
/**
|
||||
* 菜单图标大小
|
||||
*/
|
||||
iconSize: numericProp,
|
||||
/**
|
||||
* 自定义点击事件
|
||||
*/
|
||||
beforeToggle: Function as PropType<DropMenuItemBeforeToggle>,
|
||||
/**
|
||||
* 选项对象中,value 对应的 key
|
||||
*/
|
||||
valueKey: makeStringProp('value'),
|
||||
/**
|
||||
* 选项对象中,展示的文本对应的 key
|
||||
*/
|
||||
labelKey: makeStringProp('label'),
|
||||
/**
|
||||
* 选项对象中,选项说明对应的 key
|
||||
*/
|
||||
tipKey: makeStringProp('tip'),
|
||||
/**
|
||||
* 自定义下拉菜单popup样式类
|
||||
*/
|
||||
customPopupClass: makeStringProp(''),
|
||||
/**
|
||||
* 自定义下拉菜单popup样式
|
||||
*/
|
||||
customPopupStyle: makeStringProp(''),
|
||||
/**
|
||||
* 弹出层高度 这里设置了 就取这里的
|
||||
*/
|
||||
popupHeight: makeStringProp(''),
|
||||
/**
|
||||
* 是否从页面中脱离出来,用于解决各种 fixed 失效问题 (H5: teleport, APP: renderjs, 小程序: root-portal)
|
||||
*/
|
||||
rootPortal: makeBooleanProp(false)
|
||||
}
|
||||
|
||||
export type DropMenuItemProps = ExtractPropTypes<typeof dorpMenuItemProps>
|
||||
|
||||
export type DropMenuItemExpose = {
|
||||
getShowPop: () => boolean
|
||||
open: () => void
|
||||
close: () => void
|
||||
toggle: () => void
|
||||
}
|
||||
|
||||
export type DropMenuItemInstance = ComponentPublicInstance<DropMenuItemProps, DropMenuItemExpose>
|
||||
@@ -0,0 +1,221 @@
|
||||
<template>
|
||||
<view
|
||||
v-if="showWrapper"
|
||||
:class="`wd-drop-item ${customClass}`"
|
||||
:style="`pointer-events: none; z-index: ${zIndex}; ${positionStyle};${customStyle}`"
|
||||
>
|
||||
<wd-popup
|
||||
v-model="showPop"
|
||||
:z-index="zIndex"
|
||||
:duration="duration"
|
||||
:position="position"
|
||||
:custom-style="`position: absolute; pointer-events: auto; max-height: ${popupHeight ? popupHeight : '80%'}; ${customPopupStyle}`"
|
||||
:custom-class="customPopupClass"
|
||||
:modal="false"
|
||||
:close-on-click-modal="false"
|
||||
:root-portal="rootPortal"
|
||||
@before-enter="beforeEnter"
|
||||
@after-enter="afterEnter"
|
||||
@before-leave="beforeLeave"
|
||||
@after-leave="afterLeave"
|
||||
>
|
||||
<scroll-view v-if="options.length" :style="popupHeight ? { height: popupHeight } : ''" scroll-y scroll-with-animation :show-scrollbar="true">
|
||||
<view
|
||||
v-for="(item, index) in options"
|
||||
:key="index"
|
||||
@click="choose(index)"
|
||||
:class="`wd-drop-item__option ${(item[valueKey] !== '' ? item[valueKey] : item) === modelValue ? 'is-active' : ''}`"
|
||||
>
|
||||
<view :class="`wd-drop-item__title ${customTitle}`">
|
||||
<text>{{ item[labelKey] ? item[labelKey] : item }}</text>
|
||||
<text v-if="item[tipKey]" class="wd-drop-item__tip">{{ item[tipKey] }}</text>
|
||||
</view>
|
||||
<wd-icon
|
||||
v-if="(item[valueKey] !== '' ? item[valueKey] : item) === modelValue"
|
||||
:name="iconName"
|
||||
:custom-class="`wd-drop-item__icon ${customIcon}`"
|
||||
/>
|
||||
</view>
|
||||
</scroll-view>
|
||||
<slot v-else />
|
||||
</wd-popup>
|
||||
</view>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
export default {
|
||||
name: 'wd-drop-menu-item',
|
||||
options: {
|
||||
virtualHost: true,
|
||||
addGlobalClass: true,
|
||||
styleIsolation: 'shared'
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import wdPopup from '../wd-popup/wd-popup.vue'
|
||||
import wdIcon from '../wd-icon/wd-icon.vue'
|
||||
import { computed, getCurrentInstance, inject, onBeforeMount, onBeforeUnmount, ref, watch } from 'vue'
|
||||
import { pushToQueue, removeFromQueue } from '../common/clickoutside'
|
||||
import { type Queue, queueKey } from '../composables/useQueue'
|
||||
import type { PopupType } from '../wd-popup/types'
|
||||
import { useParent } from '../composables/useParent'
|
||||
import { DROP_MENU_KEY } from '../wd-drop-menu/types'
|
||||
import { isDef, isFunction } from '../common/util'
|
||||
import { dorpMenuItemProps, type DropMenuItemExpose } from './types'
|
||||
|
||||
const props = defineProps(dorpMenuItemProps)
|
||||
const emit = defineEmits<{
|
||||
(e: 'update:modelValue', value: string | number): void
|
||||
(e: 'change', event: { value: string | number; selectedItem: Record<string, any> }): void
|
||||
(e: 'open'): void
|
||||
(e: 'opened'): void
|
||||
(e: 'close'): void
|
||||
(e: 'closed'): void
|
||||
}>()
|
||||
|
||||
const queue = inject<Queue | null>(queueKey, null)
|
||||
const showWrapper = ref<boolean>(false)
|
||||
const showPop = ref<boolean>(false)
|
||||
const position = ref<PopupType>()
|
||||
const zIndex = ref<number>(12)
|
||||
const duration = ref<number>(0)
|
||||
|
||||
const { parent: dropMenu } = useParent(DROP_MENU_KEY)
|
||||
|
||||
const { proxy } = getCurrentInstance() as any
|
||||
|
||||
const positionStyle = computed(() => {
|
||||
let style: string = ''
|
||||
if (showWrapper.value && dropMenu) {
|
||||
style =
|
||||
dropMenu.props.direction === 'down'
|
||||
? `top: calc(var(--window-top) + ${dropMenu.offset.value}px); bottom: 0;`
|
||||
: `top: 0; bottom: calc(var(--window-bottom) + ${dropMenu.offset.value}px)`
|
||||
} else {
|
||||
style = ''
|
||||
}
|
||||
return style
|
||||
})
|
||||
|
||||
watch(
|
||||
() => props.modelValue,
|
||||
(newValue) => {
|
||||
if (isDef(newValue) && typeof newValue !== 'number' && typeof newValue !== 'string') {
|
||||
console.error('[wot-design] warning(wd-drop-menu-item): the type of value should be a number or a string.')
|
||||
}
|
||||
},
|
||||
{
|
||||
deep: true,
|
||||
immediate: true
|
||||
}
|
||||
)
|
||||
|
||||
onBeforeMount(() => {
|
||||
if (queue && queue.pushToQueue) {
|
||||
queue.pushToQueue(proxy)
|
||||
} else {
|
||||
pushToQueue(proxy)
|
||||
}
|
||||
})
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
if (queue && queue.removeFromQueue) {
|
||||
queue.removeFromQueue(proxy)
|
||||
} else {
|
||||
removeFromQueue(proxy)
|
||||
}
|
||||
})
|
||||
|
||||
function getShowPop() {
|
||||
return showPop.value
|
||||
}
|
||||
// 模拟单选操作 默认根据 value 选中操作
|
||||
function choose(index: number) {
|
||||
if (props.disabled) return
|
||||
const { valueKey } = props
|
||||
const item = props.options[index]
|
||||
const newValue = item[valueKey] !== undefined ? item[valueKey] : item
|
||||
emit('update:modelValue', newValue)
|
||||
emit('change', {
|
||||
value: newValue,
|
||||
selectedItem: item
|
||||
})
|
||||
close()
|
||||
}
|
||||
// 外部关闭弹出框
|
||||
function close() {
|
||||
if (!showPop.value) {
|
||||
return
|
||||
}
|
||||
if (isFunction(props.beforeToggle)) {
|
||||
props.beforeToggle({
|
||||
status: false,
|
||||
resolve: (isPass: boolean) => {
|
||||
isPass && handleClose()
|
||||
}
|
||||
})
|
||||
} else {
|
||||
handleClose()
|
||||
}
|
||||
}
|
||||
|
||||
function handleClose() {
|
||||
if (showPop.value) {
|
||||
showPop.value = false
|
||||
}
|
||||
}
|
||||
|
||||
function open() {
|
||||
if (showPop.value) {
|
||||
return
|
||||
}
|
||||
if (isFunction(props.beforeToggle)) {
|
||||
props.beforeToggle({
|
||||
status: true,
|
||||
resolve: (isPass) => {
|
||||
isPass && handleOpen()
|
||||
}
|
||||
})
|
||||
} else {
|
||||
handleOpen()
|
||||
}
|
||||
}
|
||||
|
||||
function handleOpen() {
|
||||
showWrapper.value = true
|
||||
showPop.value = true
|
||||
if (dropMenu) {
|
||||
duration.value = Number(dropMenu.props.duration)
|
||||
position.value = dropMenu.props.direction === 'down' ? 'top' : 'bottom'
|
||||
}
|
||||
}
|
||||
|
||||
function toggle() {
|
||||
if (showPop.value) {
|
||||
close()
|
||||
} else {
|
||||
open()
|
||||
}
|
||||
}
|
||||
|
||||
function afterLeave() {
|
||||
showWrapper.value = false
|
||||
emit('closed')
|
||||
}
|
||||
function beforeEnter() {
|
||||
emit('open')
|
||||
}
|
||||
function afterEnter() {
|
||||
emit('opened')
|
||||
}
|
||||
function beforeLeave() {
|
||||
emit('close')
|
||||
}
|
||||
|
||||
defineExpose<DropMenuItemExpose>({ getShowPop, open, close, toggle })
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import './index.scss';
|
||||
</style>
|
||||
Reference in New Issue
Block a user