提交 bd2039ac 作者: Vben

refactor: remove useExpose

上级 3b2c40be
## Wip ## Wip
### ✨ Refactor
- 移除`useExpose`,使用组件自身提供的`expose`代替
### ✨ Features ### ✨ Features
- **CropperImage** `Cropper` 头像裁剪新增圆形裁剪功能 - **CropperImage** `Cropper` 头像裁剪新增圆形裁剪功能
......
...@@ -59,7 +59,6 @@ ...@@ -59,7 +59,6 @@
import { createTableContext } from './hooks/useTableContext'; import { createTableContext } from './hooks/useTableContext';
import { useTableFooter } from './hooks/useTableFooter'; import { useTableFooter } from './hooks/useTableFooter';
import { useTableForm } from './hooks/useTableForm'; import { useTableForm } from './hooks/useTableForm';
import { useExpose } from '/@/hooks/core/useExpose';
import { useDesign } from '/@/hooks/web/useDesign'; import { useDesign } from '/@/hooks/web/useDesign';
import { omit } from 'lodash-es'; import { omit } from 'lodash-es';
...@@ -91,7 +90,7 @@ ...@@ -91,7 +90,7 @@
'change', 'change',
'columns-change', 'columns-change',
], ],
setup(props, { attrs, emit, slots }) { setup(props, { attrs, emit, slots, expose }) {
const tableElRef = ref<ComponentRef>(null); const tableElRef = ref<ComponentRef>(null);
const tableData = ref<Recordable[]>([]); const tableData = ref<Recordable[]>([]);
...@@ -290,7 +289,7 @@ ...@@ -290,7 +289,7 @@
}; };
createTableContext({ ...tableAction, wrapRef, getBindValues }); createTableContext({ ...tableAction, wrapRef, getBindValues });
useExpose<TableActionType>(tableAction); expose(tableAction);
emit('register', tableAction, formActions); emit('register', tableAction, formActions);
......
...@@ -25,7 +25,6 @@ ...@@ -25,7 +25,6 @@
import { useTree } from './useTree'; import { useTree } from './useTree';
import { useContextMenu } from '/@/hooks/web/useContextMenu'; import { useContextMenu } from '/@/hooks/web/useContextMenu';
import { useExpose } from '/@/hooks/core/useExpose';
import { useDesign } from '/@/hooks/web/useDesign'; import { useDesign } from '/@/hooks/web/useDesign';
import { basicProps } from './props'; import { basicProps } from './props';
...@@ -44,7 +43,7 @@ ...@@ -44,7 +43,7 @@
inheritAttrs: false, inheritAttrs: false,
props: basicProps, props: basicProps,
emits: ['update:expandedKeys', 'update:selectedKeys', 'update:value', 'change', 'check'], emits: ['update:expandedKeys', 'update:selectedKeys', 'update:value', 'change', 'check'],
setup(props, { attrs, slots, emit }) { setup(props, { attrs, slots, emit, expose }) {
const state = reactive<State>({ const state = reactive<State>({
checkStrictly: props.checkStrictly, checkStrictly: props.checkStrictly,
expandedKeys: props.expandedKeys || [], expandedKeys: props.expandedKeys || [],
...@@ -277,7 +276,7 @@ ...@@ -277,7 +276,7 @@
}, },
}; };
useExpose<TreeActionType>(instance); expose(instance);
function renderAction(node: TreeItem) { function renderAction(node: TreeItem) {
const { actionList } = props; const { actionList } = props;
......
import { createAsyncComponent } from '/@/utils/factory/createAsyncComponent'; import { withInstall } from '/@/utils/index';
import basicDragVerify from './src/DragVerify.vue';
import rotateDragVerify from './src/ImgRotate.vue';
export const BasicDragVerify = createAsyncComponent(() => import('./src/DragVerify')); export const BasicDragVerify = withInstall(basicDragVerify);
export const RotateDragVerify = createAsyncComponent(() => import('./src/ImgRotate')); export const RotateDragVerify = withInstall(rotateDragVerify);
export * from './src/typing';
export * from './src/types';
@radius: 4px;
.darg-verify {
position: relative;
overflow: hidden;
text-align: center;
background-color: rgb(238, 238, 238);
border: 1px solid #ddd;
border-radius: @radius;
&-bar {
position: absolute;
width: 0;
height: 36px;
background-color: @success-color;
border-radius: @radius;
&.to-left {
width: 0 !important;
transition: width 0.3s;
}
}
&-content {
position: absolute;
top: 0;
font-size: 12px;
-webkit-text-size-adjust: none;
background-color: -webkit-gradient(
linear,
left top,
right top,
color-stop(0, #333),
color-stop(0.4, #333),
color-stop(0.5, #fff),
color-stop(0.6, #333),
color-stop(1, #333)
);
animation: slidetounlock 3s infinite;
-webkit-background-clip: text;
-moz-user-select: none;
-webkit-user-select: none;
-o-user-select: none;
-ms-user-select: none;
user-select: none;
-webkit-text-fill-color: transparent;
&.success {
-webkit-text-fill-color: @white;
}
& > * {
-webkit-text-fill-color: #333;
}
}
&-action {
position: absolute;
top: 0;
left: 0;
display: flex;
cursor: move;
background-color: @white;
border-radius: @radius;
justify-content: center;
align-items: center;
&__icon {
cursor: inherit;
}
&.to-left {
left: 0 !important;
transition: left 0.3s;
}
}
}
@-webkit-keyframes slidetounlock {
0% {
background-position: -120px 0;
}
100% {
background-position: 120px 0;
}
}
import { defineComponent, ref, computed, unref, reactive, watch, watchEffect } from 'vue'; <script lang="tsx">
import { useTimeoutFn } from '/@/hooks/core/useTimeout'; import { defineComponent, ref, computed, unref, reactive, watch, watchEffect } from 'vue';
import { useEventListener } from '/@/hooks/event/useEventListener'; import { useTimeoutFn } from '/@/hooks/core/useTimeout';
import { basicProps } from './props'; import { useEventListener } from '/@/hooks/event/useEventListener';
import { getSlot } from '/@/utils/helper/tsxHelper'; import { basicProps } from './props';
import './DragVerify.less'; import { getSlot } from '/@/utils/helper/tsxHelper';
import { CheckOutlined, DoubleRightOutlined } from '@ant-design/icons-vue'; import { CheckOutlined, DoubleRightOutlined } from '@ant-design/icons-vue';
import type { DragVerifyActionType } from './types';
import { useExpose } from '/@/hooks/core/useExpose';
export default defineComponent({
name: 'BaseDargVerify',
props: basicProps,
emits: ['success', 'update:value', 'change', 'start', 'move', 'end'],
setup(props, { emit, slots }) {
const state = reactive({
isMoving: false,
isPassing: false,
moveDistance: 0,
toLeft: false,
startTime: 0,
endTime: 0,
});
const wrapElRef = ref<HTMLDivElement | null>(null);
const barElRef = ref<HTMLDivElement | null>(null);
const contentElRef = ref<HTMLDivElement | null>(null);
const actionElRef = ref<HTMLDivElement | null>(null);
watch(
() => state.isPassing,
(isPassing) => {
if (isPassing) {
const { startTime, endTime } = state;
const time = (endTime - startTime) / 1000;
emit('success', { isPassing, time: time.toFixed(1) });
emit('update:value', isPassing);
emit('change', isPassing);
}
}
);
watchEffect(() => {
state.isPassing = !!props.value;
});
const getActionStyleRef = computed(() => {
const { height, actionStyle } = props;
const h = `${parseInt(height as string)}px`;
return {
left: 0,
width: h,
height: h,
...actionStyle,
};
});
const getWrapStyleRef = computed(() => {
const { height, width, circle, wrapStyle } = props;
const h = parseInt(height as string);
const w = `${parseInt(width as string)}px`;
return {
width: w,
height: `${h}px`,
lineHeight: `${h}px`,
borderRadius: circle ? h / 2 + 'px' : 0,
...wrapStyle,
};
});
const getBarStyleRef = computed(() => {
const { height, circle, barStyle } = props;
const h = parseInt(height as string);
return {
height: `${h}px`,
borderRadius: circle ? h / 2 + 'px 0 0 ' + h / 2 + 'px' : 0,
...barStyle,
};
});
const getContentStyleRef = computed(() => { export default defineComponent({
const { height, width, contentStyle } = props; name: 'BaseDargVerify',
const h = `${parseInt(height as string)}px`; props: basicProps,
const w = `${parseInt(width as string)}px`; emits: ['success', 'update:value', 'change', 'start', 'move', 'end'],
setup(props, { emit, slots, expose }) {
const state = reactive({
isMoving: false,
isPassing: false,
moveDistance: 0,
toLeft: false,
startTime: 0,
endTime: 0,
});
return { const wrapElRef = ref<HTMLDivElement | null>(null);
height: h, const barElRef = ref<HTMLDivElement | null>(null);
width: w, const contentElRef = ref<HTMLDivElement | null>(null);
...contentStyle, const actionElRef = ref<HTMLDivElement | null>(null);
};
});
function getEventPageX(e: MouseEvent | TouchEvent) { useEventListener({
return (e as MouseEvent).pageX || (e as TouchEvent).touches[0].pageX; el: document,
} name: 'mouseup',
listener: () => {
if (state.isMoving) {
resume();
}
},
});
useEventListener({ const getActionStyleRef = computed(() => {
el: document, const { height, actionStyle } = props;
name: 'mouseup', const h = `${parseInt(height as string)}px`;
listener: () => { return {
if (state.isMoving) { left: 0,
resume(); width: h,
height: h,
...actionStyle,
};
});
const getWrapStyleRef = computed(() => {
const { height, width, circle, wrapStyle } = props;
const h = parseInt(height as string);
const w = `${parseInt(width as string)}px`;
return {
width: w,
height: `${h}px`,
lineHeight: `${h}px`,
borderRadius: circle ? h / 2 + 'px' : 0,
...wrapStyle,
};
});
const getBarStyleRef = computed(() => {
const { height, circle, barStyle } = props;
const h = parseInt(height as string);
return {
height: `${h}px`,
borderRadius: circle ? h / 2 + 'px 0 0 ' + h / 2 + 'px' : 0,
...barStyle,
};
});
const getContentStyleRef = computed(() => {
const { height, width, contentStyle } = props;
const h = `${parseInt(height as string)}px`;
const w = `${parseInt(width as string)}px`;
return {
height: h,
width: w,
...contentStyle,
};
});
watch(
() => state.isPassing,
(isPassing) => {
if (isPassing) {
const { startTime, endTime } = state;
const time = (endTime - startTime) / 1000;
emit('success', { isPassing, time: time.toFixed(1) });
emit('update:value', isPassing);
emit('change', isPassing);
}
} }
}, );
});
function handleDragStart(e: MouseEvent | TouchEvent) { watchEffect(() => {
if (state.isPassing) { state.isPassing = !!props.value;
return; });
function getEventPageX(e: MouseEvent | TouchEvent) {
return (e as MouseEvent).pageX || (e as TouchEvent).touches[0].pageX;
} }
const actionEl = unref(actionElRef); function handleDragStart(e: MouseEvent | TouchEvent) {
if (!actionEl) return; if (state.isPassing) {
emit('start', e); return;
state.moveDistance = getEventPageX(e) - parseInt(actionEl.style.left.replace('px', ''), 10); }
state.startTime = new Date().getTime();
state.isMoving = true;
}
function getOffset(el: HTMLDivElement) {
const actionWidth = parseInt(el.style.width);
const { width } = props;
const widthNum = parseInt(width as string);
const offset = widthNum - actionWidth - 6;
return { offset, widthNum, actionWidth };
}
function handleDragMoving(e: MouseEvent | TouchEvent) {
const { isMoving, moveDistance } = state;
if (isMoving) {
const actionEl = unref(actionElRef); const actionEl = unref(actionElRef);
const barEl = unref(barElRef); if (!actionEl) return;
if (!actionEl || !barEl) return; emit('start', e);
const { offset, widthNum, actionWidth } = getOffset(actionEl); state.moveDistance = getEventPageX(e) - parseInt(actionEl.style.left.replace('px', ''), 10);
const moveX = getEventPageX(e) - moveDistance; state.startTime = new Date().getTime();
state.isMoving = true;
emit('move', { }
event: e,
moveDistance, function getOffset(el: HTMLDivElement) {
moveX, const actionWidth = parseInt(el.style.width);
}); const { width } = props;
if (moveX > 0 && moveX <= offset) { const widthNum = parseInt(width as string);
actionEl.style.left = `${moveX}px`; const offset = widthNum - actionWidth - 6;
barEl.style.width = `${moveX + actionWidth / 2}px`; return { offset, widthNum, actionWidth };
} else if (moveX > offset) { }
actionEl.style.left = `${widthNum - actionWidth}px`;
barEl.style.width = `${widthNum - actionWidth / 2}px`; function handleDragMoving(e: MouseEvent | TouchEvent) {
if (!props.isSlot) { const { isMoving, moveDistance } = state;
checkPass(); if (isMoving) {
const actionEl = unref(actionElRef);
const barEl = unref(barElRef);
if (!actionEl || !barEl) return;
const { offset, widthNum, actionWidth } = getOffset(actionEl);
const moveX = getEventPageX(e) - moveDistance;
emit('move', {
event: e,
moveDistance,
moveX,
});
if (moveX > 0 && moveX <= offset) {
actionEl.style.left = `${moveX}px`;
barEl.style.width = `${moveX + actionWidth / 2}px`;
} else if (moveX > offset) {
actionEl.style.left = `${widthNum - actionWidth}px`;
barEl.style.width = `${widthNum - actionWidth / 2}px`;
if (!props.isSlot) {
checkPass();
}
} }
} }
} }
}
function handleDragOver(e: MouseEvent | TouchEvent) { function handleDragOver(e: MouseEvent | TouchEvent) {
const { isMoving, isPassing, moveDistance } = state; const { isMoving, isPassing, moveDistance } = state;
if (isMoving && !isPassing) { if (isMoving && !isPassing) {
emit('end', e); emit('end', e);
const actionEl = unref(actionElRef); const actionEl = unref(actionElRef);
const barEl = unref(barElRef); const barEl = unref(barElRef);
if (!actionEl || !barEl) return; if (!actionEl || !barEl) return;
const moveX = getEventPageX(e) - moveDistance; const moveX = getEventPageX(e) - moveDistance;
const { offset, widthNum, actionWidth } = getOffset(actionEl); const { offset, widthNum, actionWidth } = getOffset(actionEl);
if (moveX < offset) { if (moveX < offset) {
if (!props.isSlot) { if (!props.isSlot) {
resume(); resume();
} else { } else {
setTimeout(() => { setTimeout(() => {
if (!props.value) { if (!props.value) {
resume(); resume();
} else { } else {
const contentEl = unref(contentElRef); const contentEl = unref(contentElRef);
if (contentEl) { if (contentEl) {
contentEl.style.width = `${parseInt(barEl.style.width)}px`; contentEl.style.width = `${parseInt(barEl.style.width)}px`;
}
} }
} }, 0);
}, 0); }
} else {
actionEl.style.left = `${widthNum - actionWidth}px`;
barEl.style.width = `${widthNum - actionWidth / 2}px`;
checkPass();
} }
} else { state.isMoving = false;
actionEl.style.left = `${widthNum - actionWidth}px`;
barEl.style.width = `${widthNum - actionWidth / 2}px`;
checkPass();
} }
state.isMoving = false;
} }
}
function checkPass() { function checkPass() {
if (props.isSlot) { if (props.isSlot) {
resume(); resume();
return; return;
}
state.endTime = new Date().getTime();
state.isPassing = true;
state.isMoving = false;
} }
state.endTime = new Date().getTime();
state.isPassing = true;
state.isMoving = false;
}
function resume() { function resume() {
state.isMoving = false; state.isMoving = false;
state.isPassing = false; state.isPassing = false;
state.moveDistance = 0; state.moveDistance = 0;
state.toLeft = false;
state.startTime = 0;
state.endTime = 0;
const actionEl = unref(actionElRef);
const barEl = unref(barElRef);
const contentEl = unref(contentElRef);
if (!actionEl || !barEl || !contentEl) return;
state.toLeft = true;
useTimeoutFn(() => {
state.toLeft = false; state.toLeft = false;
actionEl.style.left = '0'; state.startTime = 0;
barEl.style.width = '0'; state.endTime = 0;
// The time is consistent with the animation time const actionEl = unref(actionElRef);
}, 300); const barEl = unref(barElRef);
contentEl.style.width = unref(getContentStyleRef).width; const contentEl = unref(contentElRef);
} if (!actionEl || !barEl || !contentEl) return;
state.toLeft = true;
useTimeoutFn(() => {
state.toLeft = false;
actionEl.style.left = '0';
barEl.style.width = '0';
// The time is consistent with the animation time
}, 300);
contentEl.style.width = unref(getContentStyleRef).width;
}
useExpose<DragVerifyActionType>({ expose({
resume, resume,
}); });
return () => { return () => {
const renderBar = () => { const renderBar = () => {
const cls = [`darg-verify-bar`]; const cls = [`darg-verify-bar`];
if (state.toLeft) { if (state.toLeft) {
cls.push('to-left'); cls.push('to-left');
} }
return <div class={cls} ref={barElRef} style={unref(getBarStyleRef)} />; return <div class={cls} ref={barElRef} style={unref(getBarStyleRef)} />;
}; };
const renderContent = () => { const renderContent = () => {
const cls = [`darg-verify-content`]; const cls = [`darg-verify-content`];
const { isPassing } = state; const { isPassing } = state;
const { text, successText } = props; const { text, successText } = props;
isPassing && cls.push('success'); isPassing && cls.push('success');
return ( return (
<div class={cls} ref={contentElRef} style={unref(getContentStyleRef)}> <div class={cls} ref={contentElRef} style={unref(getContentStyleRef)}>
{getSlot(slots, 'text', isPassing) || (isPassing ? successText : text)} {getSlot(slots, 'text', isPassing) || (isPassing ? successText : text)}
</div> </div>
); );
}; };
const renderAction = () => {
const cls = [`darg-verify-action`];
const { toLeft, isPassing } = state;
if (toLeft) {
cls.push('to-left');
}
return (
<div
class={cls}
onMousedown={handleDragStart}
onTouchstart={handleDragStart}
style={unref(getActionStyleRef)}
ref={actionElRef}
>
{getSlot(slots, 'actionIcon', isPassing) ||
(isPassing ? (
<CheckOutlined class={`darg-verify-action__icon`} />
) : (
<DoubleRightOutlined class={`darg-verify-action__icon`} />
))}
</div>
);
};
const renderAction = () => {
const cls = [`darg-verify-action`];
const { toLeft, isPassing } = state;
if (toLeft) {
cls.push('to-left');
}
return ( return (
<div <div
class={cls} class="darg-verify"
onMousedown={handleDragStart} ref={wrapElRef}
onTouchstart={handleDragStart} style={unref(getWrapStyleRef)}
style={unref(getActionStyleRef)} onMousemove={handleDragMoving}
ref={actionElRef} onTouchmove={handleDragMoving}
onMouseleave={handleDragOver}
onMouseup={handleDragOver}
onTouchend={handleDragOver}
> >
{getSlot(slots, 'actionIcon', isPassing) || {renderBar()}
(isPassing ? ( {renderContent()}
<CheckOutlined class={`darg-verify-action__icon`} /> {renderAction()}
) : (
<DoubleRightOutlined class={`darg-verify-action__icon`} />
))}
</div> </div>
); );
}; };
},
});
</script>
<style lang="less">
@radius: 4px;
.darg-verify {
position: relative;
overflow: hidden;
text-align: center;
background-color: rgb(238, 238, 238);
border: 1px solid #ddd;
border-radius: @radius;
return ( &-bar {
<div position: absolute;
class="darg-verify" width: 0;
ref={wrapElRef} height: 36px;
style={unref(getWrapStyleRef)} background-color: @success-color;
onMousemove={handleDragMoving} border-radius: @radius;
onTouchmove={handleDragMoving}
onMouseleave={handleDragOver} &.to-left {
onMouseup={handleDragOver} width: 0 !important;
onTouchend={handleDragOver} transition: width 0.3s;
> }
{renderBar()} }
{renderContent()}
{renderAction()} &-content {
</div> position: absolute;
top: 0;
font-size: 12px;
-webkit-text-size-adjust: none;
background-color: -webkit-gradient(
linear,
left top,
right top,
color-stop(0, #333),
color-stop(0.4, #333),
color-stop(0.5, #fff),
color-stop(0.6, #333),
color-stop(1, #333)
); );
}; animation: slidetounlock 3s infinite;
}, -webkit-background-clip: text;
}); -moz-user-select: none;
-webkit-user-select: none;
-o-user-select: none;
-ms-user-select: none;
user-select: none;
-webkit-text-fill-color: transparent;
&.success {
-webkit-text-fill-color: @white;
}
& > * {
-webkit-text-fill-color: #333;
}
}
&-action {
position: absolute;
top: 0;
left: 0;
display: flex;
cursor: move;
background-color: @white;
border-radius: @radius;
justify-content: center;
align-items: center;
&__icon {
cursor: inherit;
}
&.to-left {
left: 0 !important;
transition: left 0.3s;
}
}
}
@-webkit-keyframes slidetounlock {
0% {
background-position: -120px 0;
}
100% {
background-position: 120px 0;
}
}
</style>
.ir-dv {
position: relative;
display: flex;
flex-direction: column;
align-items: center;
&-img__wrap {
position: relative;
overflow: hidden;
border-radius: 50%;
img {
width: 100%;
border-radius: 50%;
&.to-origin {
transition: transform 0.3s;
}
}
}
&-img__tip {
position: absolute;
bottom: 10px;
left: 0;
z-index: 1;
display: block;
width: 100%;
height: 30px;
font-size: 12px;
line-height: 30px;
color: @white;
text-align: center;
&.success {
background-color: fade(@success-color, 60%);
}
&.error {
background-color: fade(@error-color, 60%);
}
&.normal {
background-color: rgba(0, 0, 0, 0.3);
}
}
&-drag__bar {
margin-top: 20px;
}
}
import './ImgRotate.less'; <script lang="tsx">
import type { MoveData, DragVerifyActionType } from './typing';
import type { MoveData, DragVerifyActionType } from './types'; import { defineComponent, computed, unref, reactive, watch, ref, getCurrentInstance } from 'vue';
import { useTimeoutFn } from '/@/hooks/core/useTimeout';
import { defineComponent, computed, unref, reactive, watch, ref, getCurrentInstance } from 'vue'; import BasicDragVerify from './DragVerify.vue';
import { useTimeoutFn } from '/@/hooks/core/useTimeout'; import { hackCss } from '/@/utils/domUtils';
import { rotateProps } from './props';
import BasicDragVerify from './DragVerify'; import { useI18n } from '/@/hooks/web/useI18n';
import { hackCss } from '/@/utils/domUtils'; export default defineComponent({
name: 'ImgRotateDargVerify',
import { rotateProps } from './props'; inheritAttrs: false,
import { useI18n } from '/@/hooks/web/useI18n'; props: rotateProps,
emits: ['success', 'change', 'update:value'],
export default defineComponent({ setup(props, { emit, attrs }) {
name: 'ImgRotateDargVerify', const basicRef = ref<Nullable<DragVerifyActionType>>(null);
inheritAttrs: false, const state = reactive({
props: rotateProps, showTip: false,
emits: ['success', 'change', 'update:value'], isPassing: false,
setup(props, { emit, attrs }) { imgStyle: {},
const basicRef = ref<Nullable<DragVerifyActionType>>(null); randomRotate: 0,
const state = reactive({ currentRotate: 0,
showTip: false, toOrigin: false,
isPassing: false, startTime: 0,
imgStyle: {}, endTime: 0,
randomRotate: 0, draged: false,
currentRotate: 0, });
toOrigin: false, const { t } = useI18n();
startTime: 0,
endTime: 0, watch(
draged: false, () => state.isPassing,
}); (isPassing) => {
const { t } = useI18n(); if (isPassing) {
const { startTime, endTime } = state;
watch( const time = (endTime - startTime) / 1000;
() => state.isPassing, emit('success', { isPassing, time: time.toFixed(1) });
(isPassing) => { emit('change', isPassing);
if (isPassing) { emit('update:value', isPassing);
const { startTime, endTime } = state; }
const time = (endTime - startTime) / 1000;
emit('success', { isPassing, time: time.toFixed(1) });
emit('change', isPassing);
emit('update:value', isPassing);
} }
);
const getImgWrapStyleRef = computed(() => {
const { imgWrapStyle, imgWidth } = props;
return {
width: `${imgWidth}px`,
height: `${imgWidth}px`,
...imgWrapStyle,
};
});
const getFactorRef = computed(() => {
const { minDegree, maxDegree } = props;
if (minDegree === maxDegree) {
return Math.floor(1 + Math.random() * 1) / 10 + 1;
}
return 1;
});
function handleStart() {
state.startTime = new Date().getTime();
} }
);
const getImgWrapStyleRef = computed(() => {
const { imgWrapStyle, imgWidth } = props;
return {
width: `${imgWidth}px`,
height: `${imgWidth}px`,
...imgWrapStyle,
};
});
const getFactorRef = computed(() => { function handleDragBarMove(data: MoveData) {
const { minDegree, maxDegree } = props; state.draged = true;
if (minDegree === maxDegree) { const { imgWidth, height, maxDegree } = props;
return Math.floor(1 + Math.random() * 1) / 10 + 1; const { moveX } = data;
const currentRotate = Math.ceil(
(moveX / (imgWidth! - parseInt(height as string))) * maxDegree! * unref(getFactorRef)
);
state.currentRotate = currentRotate;
state.imgStyle = hackCss('transform', `rotateZ(${state.randomRotate - currentRotate}deg)`);
} }
return 1;
});
function handleStart() {
state.startTime = new Date().getTime();
}
function handleDragBarMove(data: MoveData) { function handleImgOnLoad() {
state.draged = true; const { minDegree, maxDegree } = props;
const { imgWidth, height, maxDegree } = props; const ranRotate = Math.floor(minDegree! + Math.random() * (maxDegree! - minDegree!)); // 生成随机角度
const { moveX } = data; state.randomRotate = ranRotate;
const currentRotate = Math.ceil( state.imgStyle = hackCss('transform', `rotateZ(${ranRotate}deg)`);
(moveX / (imgWidth! - parseInt(height as string))) * maxDegree! * unref(getFactorRef) }
);
state.currentRotate = currentRotate;
state.imgStyle = hackCss('transform', `rotateZ(${state.randomRotate - currentRotate}deg)`);
}
function handleImgOnLoad() { function handleDragEnd() {
const { minDegree, maxDegree } = props; const { randomRotate, currentRotate } = state;
const ranRotate = Math.floor(minDegree! + Math.random() * (maxDegree! - minDegree!)); // 生成随机角度 const { diffDegree } = props;
state.randomRotate = ranRotate;
state.imgStyle = hackCss('transform', `rotateZ(${ranRotate}deg)`); if (Math.abs(randomRotate - currentRotate) >= (diffDegree || 20)) {
} state.imgStyle = hackCss('transform', `rotateZ(${randomRotate}deg)`);
state.toOrigin = true;
useTimeoutFn(() => {
state.toOrigin = false;
state.showTip = true;
// 时间与动画时间保持一致
}, 300);
} else {
checkPass();
}
state.showTip = true;
}
function checkPass() {
state.isPassing = true;
state.endTime = new Date().getTime();
}
function handleDragEnd() { function resume() {
const { randomRotate, currentRotate } = state; state.showTip = false;
const { diffDegree } = props; const basicEl = unref(basicRef);
if (!basicEl) {
if (Math.abs(randomRotate - currentRotate) >= (diffDegree || 20)) { return;
state.imgStyle = hackCss('transform', `rotateZ(${randomRotate}deg)`); }
state.toOrigin = true; state.isPassing = false;
useTimeoutFn(() => {
state.toOrigin = false; basicEl.resume();
state.showTip = true; handleImgOnLoad();
// 时间与动画时间保持一致 }
}, 300);
} else { const instance = getCurrentInstance() as any;
checkPass(); if (instance) {
instance.resume = resume;
}
// handleImgOnLoad();
return () => {
const { src } = props;
const { toOrigin, isPassing, startTime, endTime } = state;
const imgCls: string[] = [];
if (toOrigin) {
imgCls.push('to-origin');
}
const time = (endTime - startTime) / 1000;
return (
<div class="ir-dv">
<div class={`ir-dv-img__wrap`} style={unref(getImgWrapStyleRef)}>
<img
src={src}
onLoad={handleImgOnLoad}
width={parseInt(props.width as string)}
class={imgCls}
style={state.imgStyle}
onClick={() => {
resume();
}}
/>
{state.showTip && (
<span class={[`ir-dv-img__tip`, state.isPassing ? 'success' : 'error']}>
{state.isPassing
? t('component.verify.time', { time: time.toFixed(1) })
: t('component.verify.error')}
</span>
)}
{!state.showTip && !state.draged && (
<span class={[`ir-dv-img__tip`, 'normal']}>{t('component.verify.redoTip')}</span>
)}
</div>
<BasicDragVerify
class={`ir-dv-drag__bar`}
onMove={handleDragBarMove}
onEnd={handleDragEnd}
onStart={handleStart}
ref={basicRef}
{...{ ...attrs, ...props }}
value={isPassing}
isSlot={true}
/>
</div>
);
};
},
});
</script>
<style lang="less">
.ir-dv {
position: relative;
display: flex;
flex-direction: column;
align-items: center;
&-img__wrap {
position: relative;
overflow: hidden;
border-radius: 50%;
img {
width: 100%;
border-radius: 50%;
&.to-origin {
transition: transform 0.3s;
}
} }
state.showTip = true;
}
function checkPass() {
state.isPassing = true;
state.endTime = new Date().getTime();
} }
function resume() { &-img__tip {
state.showTip = false; position: absolute;
const basicEl = unref(basicRef); bottom: 10px;
if (!basicEl) { left: 0;
return; z-index: 1;
display: block;
width: 100%;
height: 30px;
font-size: 12px;
line-height: 30px;
color: @white;
text-align: center;
&.success {
background-color: fade(@success-color, 60%);
} }
state.isPassing = false;
basicEl.resume(); &.error {
handleImgOnLoad(); background-color: fade(@error-color, 60%);
}
&.normal {
background-color: rgba(0, 0, 0, 0.3);
}
} }
const instance = getCurrentInstance() as any; &-drag__bar {
if (instance) { margin-top: 20px;
instance.resume = resume;
} }
// handleImgOnLoad(); }
return () => { </style>
const { src } = props;
const { toOrigin, isPassing, startTime, endTime } = state;
const imgCls: string[] = [];
if (toOrigin) {
imgCls.push('to-origin');
}
const time = (endTime - startTime) / 1000;
return (
<div class="ir-dv">
<div class={`ir-dv-img__wrap`} style={unref(getImgWrapStyleRef)}>
<img
src={src}
onLoad={handleImgOnLoad}
width={parseInt(props.width as string)}
class={imgCls}
style={state.imgStyle}
onClick={() => {
resume();
}}
/>
{state.showTip && (
<span class={[`ir-dv-img__tip`, state.isPassing ? 'success' : 'error']}>
{state.isPassing
? t('component.verify.time', { time: time.toFixed(1) })
: t('component.verify.error')}
</span>
)}
{!state.showTip && !state.draged && (
<span class={[`ir-dv-img__tip`, 'normal']}>{t('component.verify.redoTip')}</span>
)}
</div>
<BasicDragVerify
class={`ir-dv-drag__bar`}
onMove={handleDragBarMove}
onEnd={handleDragEnd}
onStart={handleStart}
ref={basicRef}
{...{ ...attrs, ...props }}
value={isPassing}
isSlot={true}
/>
</div>
);
};
},
});
import { getCurrentInstance } from 'vue';
// expose public api
export function useExpose<T>(apis: T) {
const instance = getCurrentInstance();
if (instance) {
Object.assign(instance.proxy, apis);
}
}
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论