hy-app 0.2.6 → 0.2.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/common/shakeService.ts +0 -2
- package/components/hy-address-picker/hy-address-picker.vue +75 -91
- package/components/hy-avatar/hy-avatar.vue +64 -73
- package/components/hy-button/hy-button.vue +2 -2
- package/components/hy-float-button/hy-float-button.vue +115 -37
- package/components/hy-float-button/props.ts +3 -3
- package/components/hy-float-button/typing.d.ts +20 -7
- package/components/hy-icon/hy-icon.vue +1 -1
- package/components/hy-image/hy-image.vue +69 -104
- package/components/hy-image/index.scss +21 -5
- package/components/hy-image/props.ts +11 -10
- package/components/hy-image/typing.d.ts +23 -19
- package/components/hy-modal/index.scss +1 -1
- package/components/hy-popover/hy-popover.vue +200 -0
- package/components/hy-popover/index.scss +83 -0
- package/components/hy-popover/props.ts +13 -0
- package/components/hy-popover/typing.d.ts +56 -0
- package/components/hy-qrcode/hy-qrcode.vue +44 -45
- package/components/hy-rate/props.ts +6 -6
- package/components/hy-transition/hy-transition.vue +64 -72
- package/components/hy-transition/typing.d.ts +10 -6
- package/composables/index.ts +4 -2
- package/composables/usePopover.ts +221 -0
- package/composables/useQueue.ts +52 -0
- package/libs/css/mixin.scss +88 -0
- package/package.json +2 -2
- package/utils/inside.ts +96 -108
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
class="hy-transition"
|
|
5
5
|
ref="u-transition"
|
|
6
6
|
@tap.stop="clickHandler"
|
|
7
|
-
:class="classes"
|
|
7
|
+
:class="[classes, customClass]"
|
|
8
8
|
:style="[mergeStyle]"
|
|
9
9
|
>
|
|
10
10
|
<slot />
|
|
@@ -12,92 +12,85 @@
|
|
|
12
12
|
</template>
|
|
13
13
|
|
|
14
14
|
<script setup lang="ts">
|
|
15
|
-
import {
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
watch,
|
|
20
|
-
nextTick,
|
|
21
|
-
toRefs,
|
|
22
|
-
} from "vue";
|
|
23
|
-
import { sleep } from "../../utils";
|
|
24
|
-
import defaultProps from "./props";
|
|
25
|
-
import type IProps from "./typing";
|
|
15
|
+
import { computed, type CSSProperties, ref, watch, nextTick, toRefs } from 'vue'
|
|
16
|
+
import { sleep } from '../../utils'
|
|
17
|
+
import defaultProps from './props'
|
|
18
|
+
import type IProps from './typing'
|
|
26
19
|
|
|
27
|
-
const props = withDefaults(defineProps<IProps>(), defaultProps)
|
|
28
|
-
const { show, mode, duration } = toRefs(props)
|
|
20
|
+
const props = withDefaults(defineProps<IProps>(), defaultProps)
|
|
21
|
+
const { show, mode, duration, customStyle, timingFunction } = toRefs(props)
|
|
29
22
|
const emit = defineEmits([
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
])
|
|
23
|
+
'click',
|
|
24
|
+
'beforeEnter',
|
|
25
|
+
'enter',
|
|
26
|
+
'afterEnter',
|
|
27
|
+
'beforeLeave',
|
|
28
|
+
'leave',
|
|
29
|
+
'afterLeave',
|
|
30
|
+
])
|
|
38
31
|
|
|
39
|
-
const hasInit = ref<boolean>(false)
|
|
40
|
-
const viewStyle = ref<CSSProperties>({})
|
|
41
|
-
const status = ref<string>(
|
|
42
|
-
const transitionEnded = ref<boolean>(false)
|
|
43
|
-
const display = ref<boolean>(false)
|
|
44
|
-
const classes = ref<string>(
|
|
32
|
+
const hasInit = ref<boolean>(false) // 是否显示/隐藏组件
|
|
33
|
+
const viewStyle = ref<CSSProperties>({}) // 组件内部的样式
|
|
34
|
+
const status = ref<string>('') // 记录组件动画的状态
|
|
35
|
+
const transitionEnded = ref<boolean>(false) // 组件是否结束的标记
|
|
36
|
+
const display = ref<boolean>(false) // 组件是否展示
|
|
37
|
+
const classes = ref<string>('') // 应用的类名
|
|
45
38
|
|
|
46
39
|
// #ifndef APP-NVUE
|
|
47
40
|
// 定义类名,通过给元素动态切换类名,赋予元素一定的css动画样式
|
|
48
41
|
const getClassNames = (name: string) => ({
|
|
49
42
|
enter: `u-${name}-enter u-${name}-enter-active`,
|
|
50
|
-
|
|
43
|
+
'enter-to': `u-${name}-enter-to u-${name}-enter-active`,
|
|
51
44
|
leave: `u-${name}-leave u-${name}-leave-active`,
|
|
52
|
-
|
|
53
|
-
})
|
|
45
|
+
'leave-to': `u-${name}-leave-to u-${name}-leave-active`,
|
|
46
|
+
})
|
|
54
47
|
// #endif
|
|
55
48
|
|
|
56
49
|
// #ifndef APP-NVUE
|
|
57
50
|
// vue版本的组件进场处理
|
|
58
51
|
const vueEnter = async () => {
|
|
59
52
|
// 动画进入时的类名
|
|
60
|
-
const classNames = getClassNames(mode.value)
|
|
53
|
+
const classNames = getClassNames(mode.value)
|
|
61
54
|
// 定义状态和发出动画进入前事件
|
|
62
|
-
status.value =
|
|
63
|
-
emit(
|
|
64
|
-
hasInit.value = true
|
|
65
|
-
display.value = true
|
|
66
|
-
classes.value = classNames.enter
|
|
67
|
-
await nextTick()
|
|
55
|
+
status.value = 'enter'
|
|
56
|
+
emit('beforeEnter')
|
|
57
|
+
hasInit.value = true
|
|
58
|
+
display.value = true
|
|
59
|
+
classes.value = classNames.enter
|
|
60
|
+
await nextTick()
|
|
68
61
|
{
|
|
69
62
|
// https://github.com/umicro/uView2.0/issues/545
|
|
70
|
-
await sleep(20)
|
|
63
|
+
await sleep(20)
|
|
71
64
|
// 标识动画尚未结束
|
|
72
|
-
emit(
|
|
73
|
-
transitionEnded.value = false
|
|
65
|
+
emit('enter')
|
|
66
|
+
transitionEnded.value = false
|
|
74
67
|
// 组件动画进入后触发的事件
|
|
75
|
-
emit(
|
|
68
|
+
emit('afterEnter')
|
|
76
69
|
// 赋予组件enter-to类名
|
|
77
|
-
classes.value = classNames[
|
|
70
|
+
classes.value = classNames['enter-to']
|
|
78
71
|
}
|
|
79
|
-
}
|
|
72
|
+
}
|
|
80
73
|
// 动画离场处理
|
|
81
74
|
const vueLeave = async () => {
|
|
82
75
|
// 如果不是展示状态,无需执行逻辑
|
|
83
|
-
if (!display.value) return
|
|
84
|
-
const classNames = getClassNames(mode.value)
|
|
76
|
+
if (!display.value) return
|
|
77
|
+
const classNames = getClassNames(mode.value)
|
|
85
78
|
// 标记离开状态和发出事件
|
|
86
|
-
status.value =
|
|
87
|
-
emit(
|
|
79
|
+
status.value = 'leave'
|
|
80
|
+
emit('beforeLeave')
|
|
88
81
|
// 获得类名
|
|
89
|
-
classes.value = classNames.leave
|
|
82
|
+
classes.value = classNames.leave
|
|
90
83
|
|
|
91
|
-
await nextTick()
|
|
84
|
+
await nextTick()
|
|
92
85
|
{
|
|
93
86
|
// 动画正在离场的状态
|
|
94
|
-
transitionEnded.value = false
|
|
95
|
-
emit(
|
|
87
|
+
transitionEnded.value = false
|
|
88
|
+
emit('leave')
|
|
96
89
|
// 组件执行动画,到了执行的执行时间后,执行一些额外处理
|
|
97
|
-
setTimeout(() => onTransitionEnd(), duration.value)
|
|
98
|
-
classes.value = classNames[
|
|
90
|
+
setTimeout(() => onTransitionEnd(), duration.value)
|
|
91
|
+
classes.value = classNames['leave-to']
|
|
99
92
|
}
|
|
100
|
-
}
|
|
93
|
+
}
|
|
101
94
|
// #endif
|
|
102
95
|
|
|
103
96
|
watch(
|
|
@@ -108,50 +101,49 @@ watch(
|
|
|
108
101
|
// newVal ? nvueEnter() : nvueLeave()
|
|
109
102
|
// #endif
|
|
110
103
|
// #ifndef APP-NVUE
|
|
111
|
-
newVal ? vueEnter() : vueLeave()
|
|
104
|
+
newVal ? vueEnter() : vueLeave()
|
|
112
105
|
// #endif
|
|
113
106
|
},
|
|
114
107
|
{ immediate: true },
|
|
115
|
-
)
|
|
108
|
+
)
|
|
116
109
|
|
|
117
110
|
const mergeStyle = computed(() => {
|
|
118
|
-
const { duration, customStyle, timingFunction } = props;
|
|
119
111
|
return {
|
|
120
112
|
// #ifndef APP-NVUE
|
|
121
|
-
transitionDuration: `${duration}ms`,
|
|
113
|
+
transitionDuration: `${duration.value}ms`,
|
|
122
114
|
// display: `${this.display ? '' : 'none'}`,
|
|
123
|
-
transitionTimingFunction: timingFunction,
|
|
115
|
+
transitionTimingFunction: timingFunction.value,
|
|
124
116
|
// #endif
|
|
125
117
|
// 避免自定义样式影响到动画属性,所以写在viewStyle前面
|
|
126
|
-
...customStyle,
|
|
118
|
+
...customStyle.value,
|
|
127
119
|
...viewStyle,
|
|
128
|
-
}
|
|
129
|
-
})
|
|
120
|
+
}
|
|
121
|
+
})
|
|
130
122
|
|
|
131
123
|
/**
|
|
132
124
|
* @description 组件被点击发出事件
|
|
133
125
|
* */
|
|
134
126
|
const clickHandler = () => {
|
|
135
|
-
emit(
|
|
136
|
-
}
|
|
127
|
+
emit('click')
|
|
128
|
+
}
|
|
137
129
|
|
|
138
130
|
const onTransitionEnd = () => {
|
|
139
131
|
// 如果已经是结束的状态,无需再处理
|
|
140
|
-
if (transitionEnded.value) return
|
|
141
|
-
transitionEnded.value = true
|
|
132
|
+
if (transitionEnded.value) return
|
|
133
|
+
transitionEnded.value = true
|
|
142
134
|
// 发出组件动画执行后的事件
|
|
143
|
-
emit(status.value ===
|
|
135
|
+
emit(status.value === 'leave' ? 'afterLeave' : 'afterEnter')
|
|
144
136
|
if (!show.value && display.value) {
|
|
145
|
-
display.value = false
|
|
146
|
-
hasInit.value = false
|
|
137
|
+
display.value = false
|
|
138
|
+
hasInit.value = false
|
|
147
139
|
}
|
|
148
|
-
}
|
|
140
|
+
}
|
|
149
141
|
</script>
|
|
150
142
|
|
|
151
143
|
<style lang="scss" scoped>
|
|
152
144
|
/* #ifndef APP-NVUE */
|
|
153
145
|
// vue版本动画相关的样式抽离在外部文件
|
|
154
|
-
@import
|
|
146
|
+
@import './index.scss';
|
|
155
147
|
/* #endif */
|
|
156
148
|
|
|
157
149
|
.hy-transition {
|
|
@@ -1,24 +1,28 @@
|
|
|
1
|
-
import type { CSSProperties } from
|
|
1
|
+
import type { CSSProperties } from 'vue'
|
|
2
2
|
|
|
3
3
|
export default interface HyTransitionProps {
|
|
4
4
|
/**
|
|
5
5
|
* @description 是否展示组件
|
|
6
6
|
* */
|
|
7
|
-
show: boolean
|
|
7
|
+
show: boolean
|
|
8
8
|
/**
|
|
9
9
|
* @description 使用的动画模式(默认:fade)
|
|
10
10
|
* */
|
|
11
|
-
mode?: HyApp.TransitionMode
|
|
11
|
+
mode?: HyApp.TransitionMode
|
|
12
12
|
/**
|
|
13
13
|
* @description 动画的执行时间,单位ms
|
|
14
14
|
* */
|
|
15
|
-
duration?: number
|
|
15
|
+
duration?: number
|
|
16
16
|
/**
|
|
17
17
|
* @description 使用的动画过渡函数(默认:ease-out)
|
|
18
18
|
* */
|
|
19
|
-
timingFunction?: string
|
|
19
|
+
timingFunction?: string
|
|
20
20
|
/**
|
|
21
21
|
* @description 定义需要用到的外部样式
|
|
22
22
|
* */
|
|
23
|
-
customStyle?: CSSProperties
|
|
23
|
+
customStyle?: CSSProperties
|
|
24
|
+
/**
|
|
25
|
+
* @description 定义组件的类名
|
|
26
|
+
* */
|
|
27
|
+
customClass?: string
|
|
24
28
|
}
|
package/composables/index.ts
CHANGED
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
import { CSSProperties, getCurrentInstance, ref } from 'vue'
|
|
2
|
+
import { getRect, isObject } from '../utils'
|
|
3
|
+
import { IOffset, IPlacementVo } from '@/package/components/hy-popover/typing'
|
|
4
|
+
|
|
5
|
+
export function usePopover(visibleArrow = true) {
|
|
6
|
+
const { proxy } = getCurrentInstance() as any
|
|
7
|
+
const popStyle = ref<CSSProperties>()
|
|
8
|
+
const arrowStyle = ref<string>('')
|
|
9
|
+
const showStyle = ref<string>('')
|
|
10
|
+
const arrowClass = ref<string>('')
|
|
11
|
+
const popWidth = ref<number>(0)
|
|
12
|
+
const popHeight = ref<number>(0)
|
|
13
|
+
const left = ref<number>(0)
|
|
14
|
+
const bottom = ref<number>(0)
|
|
15
|
+
const width = ref<number>(0)
|
|
16
|
+
const height = ref<number>(0)
|
|
17
|
+
const top = ref<number>(0)
|
|
18
|
+
|
|
19
|
+
function noop() {}
|
|
20
|
+
|
|
21
|
+
function init(placement: IPlacementVo, visibleArrow: boolean, selector: string) {
|
|
22
|
+
// 初始化 class
|
|
23
|
+
if (visibleArrow) {
|
|
24
|
+
const arrowClassArr = [
|
|
25
|
+
`hy-${selector}__arrow`,
|
|
26
|
+
placement === 'bottom' || placement === 'bottom-start' || placement === 'bottom-end'
|
|
27
|
+
? `hy-${selector}__arrow-up`
|
|
28
|
+
: '',
|
|
29
|
+
placement === 'left' || placement === 'left-start' || placement === 'left-end'
|
|
30
|
+
? `hy-${selector}__arrow-right`
|
|
31
|
+
: '',
|
|
32
|
+
placement === 'right' || placement === 'right-start' || placement === 'right-end'
|
|
33
|
+
? `hy-${selector}__arrow-left`
|
|
34
|
+
: '',
|
|
35
|
+
placement === 'top' || placement === 'top-start' || placement === 'top-end'
|
|
36
|
+
? `hy-${selector}__arrow-down`
|
|
37
|
+
: '',
|
|
38
|
+
]
|
|
39
|
+
arrowClass.value = arrowClassArr.join(' ')
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// 初始化数据获取
|
|
43
|
+
getRect('#target', false, proxy).then((rect) => {
|
|
44
|
+
if (!rect) return
|
|
45
|
+
left.value = rect.left as number
|
|
46
|
+
bottom.value = rect.bottom as number
|
|
47
|
+
width.value = rect.width as number
|
|
48
|
+
height.value = rect.height as number
|
|
49
|
+
top.value = rect.top as number
|
|
50
|
+
})
|
|
51
|
+
// 用透明度可在初始化时获取到pop尺寸
|
|
52
|
+
getRect('#pos', false, proxy).then((rect) => {
|
|
53
|
+
if (!rect) return
|
|
54
|
+
popWidth.value = rect.width as number
|
|
55
|
+
popHeight.value = rect.height as number
|
|
56
|
+
})
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function control(placement: IPlacementVo, offset: IOffset) {
|
|
60
|
+
// arrow size
|
|
61
|
+
const arrowSize = visibleArrow ? 9 : 0
|
|
62
|
+
// 上下位(纵轴)对应的距离左边的距离
|
|
63
|
+
const verticalX = width.value / 2
|
|
64
|
+
// 上下位(纵轴)对应的距离底部的距离
|
|
65
|
+
const verticalY = arrowSize + height.value + 5
|
|
66
|
+
// 左右位(横轴)对应的距离左边的距离
|
|
67
|
+
const horizontalX = width.value + arrowSize + 5
|
|
68
|
+
// 左右位(横轴)对应的距离底部的距离
|
|
69
|
+
const horizontalY = height.value / 2
|
|
70
|
+
|
|
71
|
+
let offsetX = 0
|
|
72
|
+
let offsetY = 0
|
|
73
|
+
if (Array.isArray(offset)) {
|
|
74
|
+
offsetX = (verticalX - 17 > 0 ? 0 : verticalX - 25) + offset[0]
|
|
75
|
+
offsetY = (horizontalY - 17 > 0 ? 0 : horizontalY - 25) + (offset[1] ? offset[1] : offset[0])
|
|
76
|
+
} else if (isObject(offset)) {
|
|
77
|
+
offsetX = (verticalX - 17 > 0 ? 0 : verticalX - 25) + offset.x
|
|
78
|
+
offsetY = (horizontalY - 17 > 0 ? 0 : horizontalY - 25) + offset.y
|
|
79
|
+
} else {
|
|
80
|
+
offsetX = (verticalX - 17 > 0 ? 0 : verticalX - 25) + offset
|
|
81
|
+
offsetY = (horizontalY - 17 > 0 ? 0 : horizontalY - 25) + offset
|
|
82
|
+
}
|
|
83
|
+
// const offsetX = (verticalX - 17 > 0 ? 0 : verticalX - 25) + offset
|
|
84
|
+
// const offsetY = (horizontalY - 17 > 0 ? 0 : horizontalY - 25) + offset
|
|
85
|
+
|
|
86
|
+
const placements = new Map([
|
|
87
|
+
// 上
|
|
88
|
+
[
|
|
89
|
+
'top',
|
|
90
|
+
[
|
|
91
|
+
{
|
|
92
|
+
left: `${verticalX}px`,
|
|
93
|
+
bottom: `${verticalY}px`,
|
|
94
|
+
transform: 'translateX(-50%)',
|
|
95
|
+
},
|
|
96
|
+
'left: 50%;',
|
|
97
|
+
],
|
|
98
|
+
],
|
|
99
|
+
[
|
|
100
|
+
'top-start',
|
|
101
|
+
[
|
|
102
|
+
{
|
|
103
|
+
left: `${offsetX}px`,
|
|
104
|
+
bottom: `${verticalY}px`,
|
|
105
|
+
},
|
|
106
|
+
`left: ${(popWidth.value >= width.value ? width.value / 2 : popWidth.value - 25) - offsetX}px;`,
|
|
107
|
+
],
|
|
108
|
+
],
|
|
109
|
+
[
|
|
110
|
+
'top-end',
|
|
111
|
+
[
|
|
112
|
+
{
|
|
113
|
+
right: `${offsetX}px`,
|
|
114
|
+
bottom: `${verticalY}px`,
|
|
115
|
+
},
|
|
116
|
+
`right: ${(popWidth.value >= width.value ? width.value / 2 : popWidth.value - 25) - offsetX}px; transform: translateX(50%);`,
|
|
117
|
+
],
|
|
118
|
+
],
|
|
119
|
+
// 下
|
|
120
|
+
[
|
|
121
|
+
'bottom',
|
|
122
|
+
[
|
|
123
|
+
{
|
|
124
|
+
left: verticalX + 'px',
|
|
125
|
+
top: verticalY + 'px',
|
|
126
|
+
transform: 'translateX(-50%)',
|
|
127
|
+
},
|
|
128
|
+
'left: 50%;',
|
|
129
|
+
],
|
|
130
|
+
],
|
|
131
|
+
[
|
|
132
|
+
'bottom-start',
|
|
133
|
+
[
|
|
134
|
+
{
|
|
135
|
+
left: `${offsetX}px`,
|
|
136
|
+
top: `${verticalY}px`,
|
|
137
|
+
},
|
|
138
|
+
`left: ${(popWidth.value >= width.value ? width.value / 2 : popWidth.value - 25) - offsetX}px;`,
|
|
139
|
+
],
|
|
140
|
+
],
|
|
141
|
+
[
|
|
142
|
+
'bottom-end',
|
|
143
|
+
[
|
|
144
|
+
{
|
|
145
|
+
right: `${offsetX}px`,
|
|
146
|
+
top: `${verticalY}px`,
|
|
147
|
+
},
|
|
148
|
+
`right: ${(popWidth.value >= width.value ? width.value / 2 : popWidth.value - 25) - offsetX}px; transform: translateX(50%);`,
|
|
149
|
+
],
|
|
150
|
+
],
|
|
151
|
+
// 左
|
|
152
|
+
[
|
|
153
|
+
'left',
|
|
154
|
+
[
|
|
155
|
+
{
|
|
156
|
+
right: `${horizontalX}px`,
|
|
157
|
+
top: `${horizontalY}px`,
|
|
158
|
+
transform: 'translateY(-50%)',
|
|
159
|
+
},
|
|
160
|
+
'top: 50%',
|
|
161
|
+
],
|
|
162
|
+
],
|
|
163
|
+
[
|
|
164
|
+
'left-start',
|
|
165
|
+
[
|
|
166
|
+
{
|
|
167
|
+
right: `${horizontalX}px`,
|
|
168
|
+
top: `${offsetY}px`,
|
|
169
|
+
},
|
|
170
|
+
`top: ${(popHeight.value >= height.value ? height.value / 2 : popHeight.value - 20) - offsetY}px;`,
|
|
171
|
+
],
|
|
172
|
+
],
|
|
173
|
+
[
|
|
174
|
+
'left-end',
|
|
175
|
+
[
|
|
176
|
+
{
|
|
177
|
+
right: `${horizontalX}px`,
|
|
178
|
+
bottom: `${offsetY}px`,
|
|
179
|
+
},
|
|
180
|
+
`bottom: ${(popHeight.value >= height.value ? height.value / 2 : popHeight.value - 20) - offsetY}px; transform: translateY(50%);`,
|
|
181
|
+
],
|
|
182
|
+
],
|
|
183
|
+
// 右
|
|
184
|
+
[
|
|
185
|
+
'right',
|
|
186
|
+
[
|
|
187
|
+
{
|
|
188
|
+
left: `${horizontalX}px`,
|
|
189
|
+
top: `${horizontalY}px`,
|
|
190
|
+
transform: 'translateY(-50%)',
|
|
191
|
+
},
|
|
192
|
+
'top: 50%',
|
|
193
|
+
],
|
|
194
|
+
],
|
|
195
|
+
[
|
|
196
|
+
'right-start',
|
|
197
|
+
[
|
|
198
|
+
{
|
|
199
|
+
left: `${horizontalX}px`,
|
|
200
|
+
top: `${offsetY}px`,
|
|
201
|
+
},
|
|
202
|
+
`top: ${(popHeight.value >= height.value ? height.value / 2 : popHeight.value - 20) - offsetY}px;`,
|
|
203
|
+
],
|
|
204
|
+
],
|
|
205
|
+
[
|
|
206
|
+
'right-end',
|
|
207
|
+
[
|
|
208
|
+
{
|
|
209
|
+
left: `${horizontalX}px`,
|
|
210
|
+
bottom: `${offsetY}px`,
|
|
211
|
+
},
|
|
212
|
+
`bottom: ${(popHeight.value >= height.value ? height.value / 2 : popHeight.value - 20) - offsetY}px; transform: translateY(50%);`,
|
|
213
|
+
],
|
|
214
|
+
],
|
|
215
|
+
])
|
|
216
|
+
popStyle.value = placements.get(placement)![0] as CSSProperties
|
|
217
|
+
arrowStyle.value = placements.get(placement)![1] as string
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
return { popStyle, arrowStyle, showStyle, arrowClass, init, control, noop }
|
|
221
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { type Ref, provide, ref } from 'vue'
|
|
2
|
+
|
|
3
|
+
export const queueKey = '__QUEUE_KEY__'
|
|
4
|
+
|
|
5
|
+
export interface Queue {
|
|
6
|
+
queue: Ref<any[]>
|
|
7
|
+
pushToQueue: (comp: any) => void
|
|
8
|
+
removeFromQueue: (comp: any) => void
|
|
9
|
+
closeOther: (comp: any) => void
|
|
10
|
+
closeOutside: () => void
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export function useQueue() {
|
|
14
|
+
const queue = ref<any[]>([])
|
|
15
|
+
|
|
16
|
+
function pushToQueue(comp: any) {
|
|
17
|
+
queue.value.push(comp)
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function removeFromQueue(comp: any) {
|
|
21
|
+
queue.value = queue.value.filter((item) => {
|
|
22
|
+
return item.$.uid !== comp.$.uid
|
|
23
|
+
})
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function closeOther(comp: any) {
|
|
27
|
+
queue.value.forEach((item) => {
|
|
28
|
+
if (item.$.uid !== comp.$.uid) {
|
|
29
|
+
item.$.exposed.close()
|
|
30
|
+
}
|
|
31
|
+
})
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function closeOutside() {
|
|
35
|
+
queue.value.forEach((item) => {
|
|
36
|
+
item.$.exposed.close()
|
|
37
|
+
})
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
provide(queueKey, {
|
|
41
|
+
queue,
|
|
42
|
+
pushToQueue,
|
|
43
|
+
removeFromQueue,
|
|
44
|
+
closeOther,
|
|
45
|
+
closeOutside
|
|
46
|
+
})
|
|
47
|
+
|
|
48
|
+
return {
|
|
49
|
+
closeOther,
|
|
50
|
+
closeOutside
|
|
51
|
+
}
|
|
52
|
+
}
|
package/libs/css/mixin.scss
CHANGED
|
@@ -129,6 +129,10 @@
|
|
|
129
129
|
}
|
|
130
130
|
}
|
|
131
131
|
|
|
132
|
+
/**
|
|
133
|
+
* 圆角形状
|
|
134
|
+
* @param $shape circle-半圆形,square-方形带圆角
|
|
135
|
+
*/
|
|
132
136
|
@mixin borderRadio($shape) {
|
|
133
137
|
@include m($shape) {
|
|
134
138
|
@if $shape == circle {
|
|
@@ -140,6 +144,90 @@
|
|
|
140
144
|
}
|
|
141
145
|
}
|
|
142
146
|
|
|
147
|
+
/**
|
|
148
|
+
* 正方形实现尖角样式,适用于背景不透明情况
|
|
149
|
+
* @param $size 正方形边长
|
|
150
|
+
* @param $bg 正方形背景颜色
|
|
151
|
+
* @param $z-index z-index属性值,不得大于外部包裹器
|
|
152
|
+
* @param $box-shadow 阴影
|
|
153
|
+
*/
|
|
154
|
+
@mixin squareArrow($size, $bg, $z-index, $box-shadow) {
|
|
155
|
+
@include e(arrow) {
|
|
156
|
+
position: absolute;
|
|
157
|
+
width: $size;
|
|
158
|
+
height: $size;
|
|
159
|
+
z-index: $z-index;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
@include e(arrow-down) {
|
|
163
|
+
transform: translateX(-50%);
|
|
164
|
+
bottom: 0;
|
|
165
|
+
|
|
166
|
+
&:after {
|
|
167
|
+
content: "";
|
|
168
|
+
width: $size;
|
|
169
|
+
height: $size;
|
|
170
|
+
background-color: $bg;
|
|
171
|
+
position: absolute;
|
|
172
|
+
left: 0;
|
|
173
|
+
bottom: calc(-1 * $size / 2);
|
|
174
|
+
transform: rotateZ(45deg);
|
|
175
|
+
box-shadow: $box-shadow;
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
@include e(arrow-up) {
|
|
180
|
+
transform: translateX(-50%);
|
|
181
|
+
top: 0;
|
|
182
|
+
|
|
183
|
+
&:after {
|
|
184
|
+
content: "";
|
|
185
|
+
width: $size;
|
|
186
|
+
height: $size;
|
|
187
|
+
background-color: $bg;
|
|
188
|
+
position: absolute;
|
|
189
|
+
left: 0;
|
|
190
|
+
top: calc(-1 * $size / 2);
|
|
191
|
+
transform: rotateZ(45deg);
|
|
192
|
+
box-shadow: $box-shadow;
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
@include e(arrow-left) {
|
|
197
|
+
transform: translateY(-50%);
|
|
198
|
+
left: 0;
|
|
199
|
+
|
|
200
|
+
&:after {
|
|
201
|
+
content: "";
|
|
202
|
+
width: $size;
|
|
203
|
+
height: $size;
|
|
204
|
+
background-color: $bg;
|
|
205
|
+
position: absolute;
|
|
206
|
+
left: calc(-1 * $size / 2);
|
|
207
|
+
top: 0;
|
|
208
|
+
transform: rotateZ(45deg);
|
|
209
|
+
box-shadow: $box-shadow;
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
@include e(arrow-right) {
|
|
214
|
+
transform: translateY(-50%);
|
|
215
|
+
right: 0;
|
|
216
|
+
|
|
217
|
+
&:after {
|
|
218
|
+
content: "";
|
|
219
|
+
width: $size;
|
|
220
|
+
height: $size;
|
|
221
|
+
background-color: $bg;
|
|
222
|
+
position: absolute;
|
|
223
|
+
right: calc(-1 * $size / 2);
|
|
224
|
+
top: 0;
|
|
225
|
+
transform: rotateZ(45deg);
|
|
226
|
+
box-shadow: $box-shadow;
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
|
|
143
231
|
|
|
144
232
|
/* flex布局 */
|
|
145
233
|
@mixin flex($direction: row) {
|