perf(layer): 初步集成 layer 弹层, 新增 useMove 拖拽 hooks

This commit is contained in:
就眠仪式
2021-11-01 01:02:21 +08:00
parent 5aa3544914
commit 32a2500d67
53 changed files with 925 additions and 210 deletions

View File

Before

Width:  |  Height:  |  Size: 5.8 KiB

After

Width:  |  Height:  |  Size: 5.8 KiB

View File

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 11 KiB

View File

@@ -462,16 +462,16 @@ html #layuicss-layer {
.layui-layer-btn {
text-align: right;
padding: 0 15px 12px;
padding: 8px 15px 12px;
pointer-events: auto;
user-select: none;
-webkit-user-select: none;
}
.layui-layer-btn a {
height: 28px;
line-height: 28px;
margin: 5px 5px 0;
height: 33px;
line-height: 33px;
margin: 0px 5px 0;
padding: 0 15px;
border: 1px solid #dedede;
background-color: #fff;

View File

Before

Width:  |  Height:  |  Size: 5.7 KiB

After

Width:  |  Height:  |  Size: 5.7 KiB

View File

Before

Width:  |  Height:  |  Size: 701 B

After

Width:  |  Height:  |  Size: 701 B

View File

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB

View File

@@ -1,5 +1,6 @@
import { ref, onMounted, onUnmounted, Ref } from 'vue'
const x = undefined
// 案例详见 dropdown.vue
const useClickOutside = (elementRef: Ref<HTMLElement | null>) => {
// 设置一个导出值

View File

@@ -0,0 +1,25 @@
import { ref, onMounted, onUnmounted, Ref } from 'vue'
const useFullScreen = () => {
const isFullScreen = ref(false)
const fullScreen = function () {
var docElm = document.documentElement
switch (!isFullScreen.value) {
case true:
if (docElm.requestFullscreen) {
docElm.requestFullscreen()
}
break
case false:
if (document.exitFullscreen) {
document.exitFullscreen()
}
break
}
isFullScreen.value = !isFullScreen.value
}
return { isFullScreen, fullScreen }
}
export default useFullScreen

103
src/hooks/useMove.ts Normal file
View File

@@ -0,0 +1,103 @@
function useMove(el: any) {
el.style.position = 'fixed'
let offsetX: number,
offsetY: number,
oL: number,
oT: number,
oLeft: number,
oTop: number
const browser = {
versions: (function () {
const u = navigator.userAgent
return {
mobile: !!u.match(/AppleWebKit.*Mobile.*/), //判断设备
// ..... 其他设备信息
}
})(),
}
if (!browser.versions.mobile) {
//Pc
if (el != null) {
el.addEventListener('mousedown', function (event: any) {
if (event.button == 0 && el != null) {
const lexObj: any = getComputedStyle(el)
offsetX =
event.pageX - el.offsetLeft + parseInt(lexObj['margin-left'])
offsetY =
event.pageY - el.offsetTop + parseInt(lexObj['margin-right'])
const move = function (event: any) {
if (el != null) {
let x = event.pageX - offsetX
let y = event.pageY - offsetY
if (x < 0) {
x = 0
} else if (
x >
document.documentElement.clientWidth - el.offsetWidth
) {
x = document.documentElement.clientWidth - el.offsetWidth
}
if (y < 0) {
y = 0
} else if (
y >
document.documentElement.clientHeight - el.offsetHeight
) {
y = document.documentElement.clientHeight - el.offsetHeight
}
el.style.left = x + 'px'
el.style.top = y + 'px'
}
return false
}
document.addEventListener('mousemove', move)
const stop = function () {
document.removeEventListener('mousemove', move)
document.removeEventListener('mouseup', stop)
}
document.addEventListener('mouseup', stop)
}
return false
})
}
} else {
//Mobile
if (el != null) {
const maxW = document.body.clientWidth - el.offsetWidth
const maxH = document.body.clientHeight - el.offsetHeight
const defaultEvent = function (e: any) {
e.preventDefault()
}
el.addEventListener('touchstart', function (e: any) {
const ev = e || window.event
const touch = ev.targetTouches[0]
oL = touch.clientX - el.offsetLeft
oT = touch.clientY - el.offsetTop
document.addEventListener('touchmove', defaultEvent, false)
el.addEventListener('touchmove', function (e: any) {
const ev = e || window.event
const touch = ev.targetTouches[0]
oLeft = touch.clientX - oL
oTop = touch.clientY - oT
if (oLeft < 0) {
oLeft = 0
} else if (oLeft >= maxW) {
oLeft = maxW
}
if (oTop < 0) {
oTop = 0
} else if (oTop >= maxH) {
oTop = maxH
}
el.style.left = oLeft + 'px'
el.style.top = oTop + 'px'
})
el.addEventListener('touchend', function () {
document.removeEventListener('touchmove', defaultEvent)
})
})
}
}
}
export default useMove

View File

@@ -59,6 +59,7 @@ import LaySlider from './module/slider/index'
import LayCarousel from './module/carousel/index'
import LayCarouselItem from './module/carouselItem/index'
import LayColorPicker from './module/colorPicker/index'
import LayLayer from './module/layer/index'
const components: Record<string, IDefineComponent> = {
LayRadio,
@@ -117,6 +118,7 @@ const components: Record<string, IDefineComponent> = {
LayCarousel,
LayCarouselItem,
LayColorPicker,
LayLayer,
}
const install = (app: App, options?: InstallOptions): void => {
@@ -186,6 +188,7 @@ export {
LayCarousel,
LayCarouselItem,
LayColorPicker,
LayLayer,
install,
}

View File

@@ -25,18 +25,23 @@
</button>
</template>
<script setup name="LayButton" lang="ts">
<script lang="ts">
export default {
name: 'LayButton',
}
</script>
<script setup lang="ts">
import { defineProps } from 'vue'
const props =
defineProps<{
type?: string
size?: string
fluid?: boolean
radius?: boolean
border?: string
disabled?: boolean
loading?: boolean
nativeType?: string
}>()
const props = defineProps<{
type?: string
size?: string
fluid?: boolean
radius?: boolean
border?: string
disabled?: boolean
loading?: boolean
nativeType?: string
}>()
</script>

View File

@@ -0,0 +1,9 @@
import type { App } from 'vue'
import Component from './index.vue'
import type { IDefineComponent } from '../type/index'
Component.install = (app: App) => {
app.component(Component.name || 'LayLayer', Component)
}
export default Component as IDefineComponent

159
src/module/layer/index.vue Normal file
View File

@@ -0,0 +1,159 @@
<template>
<div
v-if="visible"
:id="id"
class="layui-layer"
style="z-index: 19891021; position: fixed"
:style="{
top: top,
left: left,
width: width,
height: height,
}"
>
<div class="layui-layer-title" style="cursor: move">
{{ title }}
</div>
<div class="layui-layer-content">
<div :style="{ height: contentHeight }" v-if="type === 1">
<slot v-if="slot.default"></slot>
<template v-else>
{{ content }}
</template>
</div>
<iframe
v-if="type === 2"
scrolling="auto"
allowtransparency="true"
frameborder="0"
:src="content"
style="width: 100%"
:style="{ height: contentHeight }"
></iframe>
</div>
<span class="layui-layer-setwin"
><a
v-if="maxmin"
class="layui-layer-min"
href="javascript:;"
@click="minHandle"
><cite></cite></a
><a
class="layui-layer-ico layui-layer-max"
:class="[max ? 'layui-layer-maxmin' : '']"
href="javascript:;"
v-if="maxmin"
@click="maxHandle"
></a>
<a
class="layui-layer-ico layui-layer-close layui-layer-close1"
href="javascript:;"
@click="closeHandle"
></a
></span>
<div class="layui-layer-btn" v-if="btn && btn.length > 0">
<template v-for="(b, index) in btn" :key="index">
<a :class="['layui-layer-btn' + index]" @click="b.callback">{{
b.text
}}</a>
</template>
</div>
</div>
</template>
<script lang="ts">
export default {
name: 'LayLayer',
}
</script>
<script lang="ts" setup>
import { onMounted, onUpdated, ref, useSlots } from 'vue'
import useMove from '../../hooks/useMove'
const slot = useSlots()
onMounted(() => {
if (props.move) {
const el = document.getElementById(props.id)
if (el != null) {
useMove(el)
}
}
})
onUpdated(() => {
if (props.move) {
const el = document.getElementById(props.id)
if (el != null) {
useMove(el)
}
}
})
const props = withDefaults(
defineProps<{
id?: string
title?: string
offset?: string[]
width?: string
height?: string
visible?: boolean
maxmin?: boolean
btn: Record<string, unknown>[]
move?: boolean
type?: number
content?: string
}>(),
{
id: 'layer',
title: '标题',
offset: () => ['50%', '50%'],
width: '390px',
height: '330px',
visible: true,
maxmin: false,
move: false,
type: 1,
btn: () => [],
}
)
const top = ref(props.offset[0])
const left = ref(props.offset[1])
const width = ref(props.width)
const height = ref(props.height)
const max = ref(false)
const contentHeight = ref(
props.btn.length > 0
? 'calc(' + props.height + ' - 100px)'
: 'calc(' + props.height + ' - 50px)'
)
const emit = defineEmits(['close', 'update:visible'])
const closeHandle = function () {
emit('close')
emit('update:visible', false)
}
const minHandle = function () {
emit('close')
emit('update:visible', false)
}
const maxHandle = function () {
if (max.value) {
width.value = props.width
height.value = props.height
top.value = props.offset[0]
left.value = props.offset[1]
} else {
width.value = '100%'
height.value = '100%'
top.value = '0px'
left.value = '0px'
}
max.value = !max.value
}
</script>

View File

@@ -6,7 +6,9 @@
:disabled="disabled"
class="layui-textarea"
:class="{ 'layui-disabled': disabled }"
@input="updateValue"
@input="onInput"
@focus="onFocus"
@blur="onBlur"
/>
</template>
@@ -20,11 +22,19 @@ const props = defineProps<{
disabled?: boolean
}>()
const emit = defineEmits(['update:modelValue', 'input'])
const emit = defineEmits(['update:modelValue', 'input', 'focus', 'blur'])
const updateValue = function (event: InputEvent) {
const onInput = function (event: InputEvent) {
const inputElement = event.target as HTMLInputElement
emit('update:modelValue', inputElement.value)
emit('input', inputElement.value)
}
const onFocus = function (event: FocusEvent) {
emit('focus', event)
}
const onBlur = function () {
emit('blur')
}
</script>