完成70%
This commit is contained in:
@@ -2,59 +2,20 @@
|
||||
<view
|
||||
v-show="visible"
|
||||
class="tac-layer"
|
||||
:class="{ 'tac-layer--visible': visible }"
|
||||
:aria-hidden="visible ? 'false' : 'true'"
|
||||
@click.stop="requestCancel"
|
||||
@click.stop
|
||||
>
|
||||
<view
|
||||
id="jiapu-tac-dialog"
|
||||
class="tac-panel"
|
||||
role="dialog"
|
||||
aria-modal="true"
|
||||
tabindex="-1"
|
||||
aria-labelledby="jiapu-tac-title"
|
||||
aria-describedby="jiapu-tac-description"
|
||||
@click.stop
|
||||
@keydown.esc.stop.prevent="requestCancel"
|
||||
>
|
||||
<view class="tac-heading">
|
||||
<view class="tac-heading__copy">
|
||||
<text id="jiapu-tac-title" class="tac-title">安全验证</text>
|
||||
<text id="jiapu-tac-description" class="tac-description"
|
||||
>拖动滑块完成验证;可刷新当前挑战或关闭返回。</text
|
||||
>
|
||||
</view>
|
||||
<view class="tac-tools" role="group" aria-label="安全验证操作">
|
||||
<button
|
||||
class="tac-tool tac-tool--refresh"
|
||||
aria-label="刷新安全验证"
|
||||
@click.stop="requestRefresh"
|
||||
>↻</button>
|
||||
<button
|
||||
class="tac-tool tac-tool--close"
|
||||
aria-label="关闭安全验证"
|
||||
@click.stop="requestCancel"
|
||||
>×</button>
|
||||
</view>
|
||||
</view>
|
||||
<view
|
||||
id="jiapu-tac-host"
|
||||
class="tac-host"
|
||||
:prop="renderContext"
|
||||
:change:prop="tacRenderer.onContextChange"
|
||||
/>
|
||||
</view>
|
||||
id="jiapu-tac-host"
|
||||
:prop="renderContext"
|
||||
:change:prop="tacRenderer.onContextChange"
|
||||
/>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: "TacVerification",
|
||||
data() {
|
||||
return {
|
||||
refreshSequence: 0,
|
||||
};
|
||||
},
|
||||
props: {
|
||||
visible: {
|
||||
type: Boolean,
|
||||
@@ -71,17 +32,10 @@ export default {
|
||||
return {
|
||||
...(this.context || {}),
|
||||
visible: this.visible,
|
||||
refreshSequence: this.refreshSequence,
|
||||
};
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
requestCancel() {
|
||||
if (this.visible) this.$emit("cancel");
|
||||
},
|
||||
requestRefresh() {
|
||||
if (this.visible) this.refreshSequence += 1;
|
||||
},
|
||||
handleTacSuccess(payload) {
|
||||
this.$emit("success", payload);
|
||||
},
|
||||
@@ -186,19 +140,14 @@ export default {
|
||||
activeXhr: null,
|
||||
fatalSent: false,
|
||||
completionSent: false,
|
||||
previousFocus: null,
|
||||
focusTrapTarget: null,
|
||||
focusTrapHandler: null,
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
async onContextChange(nextContext) {
|
||||
const wasVisible = Boolean(this.context && this.context.visible === true);
|
||||
const nextVisible = Boolean(nextContext && nextContext.visible === true);
|
||||
this.generation += 1;
|
||||
const generation = this.generation;
|
||||
if (nextVisible && !wasVisible) this.capturePreviousFocus();
|
||||
this.destroyTac(!nextVisible);
|
||||
this.destroyTac();
|
||||
this.context = nextContext || null;
|
||||
this.challenge = null;
|
||||
this.fatalSent = false;
|
||||
@@ -283,19 +232,8 @@ export default {
|
||||
preRequest: (type, request) => this.beforeRequest(type, request),
|
||||
postRequest: (type, request, response) => this.afterRequest(type, response),
|
||||
});
|
||||
this.tac = new window.TAC(config, {
|
||||
logoUrl: null,
|
||||
i18n: {
|
||||
tips_success: "验证成功",
|
||||
tips_error: "验证失败,请重新尝试",
|
||||
slider_title: "拖动滑块完成安全验证",
|
||||
rotate_title: "拖动滑块完成安全验证",
|
||||
concat_title: "拖动滑块完成拼图",
|
||||
image_click_title: "请依次点击",
|
||||
},
|
||||
});
|
||||
this.tac = new window.TAC(config);
|
||||
this.tac.init();
|
||||
this.activateFocusTrap();
|
||||
},
|
||||
beforeRequest(type, request) {
|
||||
if (type === "requestCaptchaData") {
|
||||
@@ -392,60 +330,12 @@ export default {
|
||||
message: (error && error.message) || "安全验证暂不可用",
|
||||
});
|
||||
},
|
||||
capturePreviousFocus() {
|
||||
const previousFocus = document.activeElement;
|
||||
this.previousFocus = previousFocus && typeof previousFocus.focus === "function"
|
||||
? previousFocus
|
||||
: null;
|
||||
},
|
||||
activateFocusTrap() {
|
||||
this.deactivateFocusTrap(false);
|
||||
const panel = document.querySelector("#jiapu-tac-dialog");
|
||||
if (!panel) return;
|
||||
const getFocusable = () => Array.from(panel.querySelectorAll(
|
||||
'button:not([disabled]), [href], input:not([disabled]), [tabindex]:not([tabindex="-1"])',
|
||||
)).filter((element) => element.offsetParent !== null);
|
||||
this.focusTrapHandler = (event) => {
|
||||
if (event.key !== "Tab") return;
|
||||
const focusable = getFocusable();
|
||||
if (focusable.length === 0) {
|
||||
event.preventDefault();
|
||||
panel.focus();
|
||||
return;
|
||||
}
|
||||
const first = focusable[0];
|
||||
const last = focusable[focusable.length - 1];
|
||||
if (event.shiftKey && (document.activeElement === first || document.activeElement === panel)) {
|
||||
event.preventDefault();
|
||||
last.focus();
|
||||
} else if (!event.shiftKey && document.activeElement === last) {
|
||||
event.preventDefault();
|
||||
first.focus();
|
||||
}
|
||||
};
|
||||
this.focusTrapTarget = panel;
|
||||
panel.addEventListener("keydown", this.focusTrapHandler);
|
||||
const initialFocus = panel.querySelector(".tac-tool--refresh") || panel;
|
||||
setTimeout(() => initialFocus.focus?.(), 0);
|
||||
},
|
||||
deactivateFocusTrap(restoreFocus = false) {
|
||||
if (this.focusTrapTarget && this.focusTrapHandler) {
|
||||
this.focusTrapTarget.removeEventListener("keydown", this.focusTrapHandler);
|
||||
}
|
||||
this.focusTrapTarget = null;
|
||||
this.focusTrapHandler = null;
|
||||
if (!restoreFocus) return;
|
||||
const previousFocus = this.previousFocus;
|
||||
this.previousFocus = null;
|
||||
setTimeout(() => previousFocus?.focus?.(), 0);
|
||||
},
|
||||
destroyTac(restoreFocus = true) {
|
||||
destroyTac() {
|
||||
this.abortActiveRequest();
|
||||
if (this.tac) this.tac.destroyWindow();
|
||||
this.tac = null;
|
||||
const host = document.querySelector("#jiapu-tac-host");
|
||||
if (host) host.innerHTML = "";
|
||||
this.deactivateFocusTrap(restoreFocus);
|
||||
},
|
||||
},
|
||||
};
|
||||
@@ -459,106 +349,5 @@ export default {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
box-sizing: border-box;
|
||||
padding: 32rpx;
|
||||
background: rgba(34, 19, 12, 0.62);
|
||||
opacity: 0;
|
||||
pointer-events: none;
|
||||
transition: opacity 160ms ease;
|
||||
}
|
||||
|
||||
.tac-layer--visible {
|
||||
opacity: 1;
|
||||
pointer-events: auto;
|
||||
}
|
||||
|
||||
.tac-panel {
|
||||
box-sizing: border-box;
|
||||
width: 318px;
|
||||
max-width: 100%;
|
||||
max-height: calc(var(--app-viewport-height) - 2px);
|
||||
min-height: 318px;
|
||||
border: 2rpx solid rgba(117, 25, 19, 0.48);
|
||||
border-radius: 12rpx;
|
||||
background: #f7f0e5;
|
||||
box-shadow: 0 16rpx 52rpx rgba(39, 18, 10, 0.28);
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.tac-heading {
|
||||
display: flex;
|
||||
min-height: 58px;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
box-sizing: border-box;
|
||||
padding: 6px 4px 6px 12px;
|
||||
border-bottom: 1px solid rgba(117, 25, 19, 0.18);
|
||||
}
|
||||
|
||||
.tac-heading__copy {
|
||||
display: flex;
|
||||
min-width: 0;
|
||||
flex: 1;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.tac-title {
|
||||
color: #8f160f;
|
||||
font-size: 16px;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.tac-description {
|
||||
margin-top: 2px;
|
||||
color: #5c4330;
|
||||
font-size: 12px;
|
||||
line-height: 1.35;
|
||||
}
|
||||
|
||||
.tac-tools {
|
||||
display: flex;
|
||||
flex: 0 0 auto;
|
||||
gap: 2px;
|
||||
}
|
||||
|
||||
.tac-tool {
|
||||
display: inline-flex;
|
||||
min-width: 48px;
|
||||
min-height: 48px;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
box-sizing: border-box;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
border: 0;
|
||||
background: transparent;
|
||||
color: #8f160f;
|
||||
font-size: 25px;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.tac-tool::after {
|
||||
border: 0;
|
||||
}
|
||||
|
||||
:deep(.slider-bottom .close-btn),
|
||||
:deep(.slider-bottom .refresh-btn) {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
.tac-host {
|
||||
width: 318px;
|
||||
max-width: 100%;
|
||||
min-height: 318px;
|
||||
}
|
||||
|
||||
@media (max-width: 340px) {
|
||||
.tac-layer {
|
||||
padding: 1px;
|
||||
}
|
||||
|
||||
.tac-panel {
|
||||
border: 0;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user