style(frontend): 优化 Components 代码风格和结构
- 统一移除语句末尾分号,规范代码格式 - 优化组件类型定义和 props 声明 - 改进组件文档和示例代码 - 提升代码可读性和一致性
This commit is contained in:
@@ -5,158 +5,164 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, onMounted, onUnmounted, watch } from 'vue';
|
||||
import { ref, onMounted, onUnmounted, watch } from 'vue'
|
||||
|
||||
interface TurnstileRenderOptions {
|
||||
sitekey: string;
|
||||
callback: (token: string) => void;
|
||||
'expired-callback'?: () => void;
|
||||
'error-callback'?: () => void;
|
||||
theme?: 'light' | 'dark' | 'auto';
|
||||
size?: 'normal' | 'compact' | 'flexible';
|
||||
sitekey: string
|
||||
callback: (token: string) => void
|
||||
'expired-callback'?: () => void
|
||||
'error-callback'?: () => void
|
||||
theme?: 'light' | 'dark' | 'auto'
|
||||
size?: 'normal' | 'compact' | 'flexible'
|
||||
}
|
||||
|
||||
interface TurnstileAPI {
|
||||
render: (container: HTMLElement, options: TurnstileRenderOptions) => string;
|
||||
reset: (widgetId?: string) => void;
|
||||
remove: (widgetId?: string) => void;
|
||||
render: (container: HTMLElement, options: TurnstileRenderOptions) => string
|
||||
reset: (widgetId?: string) => void
|
||||
remove: (widgetId?: string) => void
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface Window {
|
||||
turnstile?: TurnstileAPI;
|
||||
onTurnstileLoad?: () => void;
|
||||
turnstile?: TurnstileAPI
|
||||
onTurnstileLoad?: () => void
|
||||
}
|
||||
}
|
||||
|
||||
const props = withDefaults(defineProps<{
|
||||
siteKey: string;
|
||||
theme?: 'light' | 'dark' | 'auto';
|
||||
size?: 'normal' | 'compact' | 'flexible';
|
||||
}>(), {
|
||||
theme: 'auto',
|
||||
size: 'flexible',
|
||||
});
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
siteKey: string
|
||||
theme?: 'light' | 'dark' | 'auto'
|
||||
size?: 'normal' | 'compact' | 'flexible'
|
||||
}>(),
|
||||
{
|
||||
theme: 'auto',
|
||||
size: 'flexible'
|
||||
}
|
||||
)
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: 'verify', token: string): void;
|
||||
(e: 'expire'): void;
|
||||
(e: 'error'): void;
|
||||
}>();
|
||||
(e: 'verify', token: string): void
|
||||
(e: 'expire'): void
|
||||
(e: 'error'): void
|
||||
}>()
|
||||
|
||||
const containerRef = ref<HTMLElement | null>(null);
|
||||
const widgetId = ref<string | null>(null);
|
||||
const scriptLoaded = ref(false);
|
||||
const containerRef = ref<HTMLElement | null>(null)
|
||||
const widgetId = ref<string | null>(null)
|
||||
const scriptLoaded = ref(false)
|
||||
|
||||
const loadScript = (): Promise<void> => {
|
||||
return new Promise((resolve, reject) => {
|
||||
if (window.turnstile) {
|
||||
scriptLoaded.value = true;
|
||||
resolve();
|
||||
return;
|
||||
scriptLoaded.value = true
|
||||
resolve()
|
||||
return
|
||||
}
|
||||
|
||||
// Check if script is already loading
|
||||
const existingScript = document.querySelector('script[src*="turnstile"]');
|
||||
const existingScript = document.querySelector('script[src*="turnstile"]')
|
||||
if (existingScript) {
|
||||
window.onTurnstileLoad = () => {
|
||||
scriptLoaded.value = true;
|
||||
resolve();
|
||||
};
|
||||
return;
|
||||
scriptLoaded.value = true
|
||||
resolve()
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
const script = document.createElement('script');
|
||||
script.src = 'https://challenges.cloudflare.com/turnstile/v0/api.js?onload=onTurnstileLoad';
|
||||
script.async = true;
|
||||
script.defer = true;
|
||||
const script = document.createElement('script')
|
||||
script.src = 'https://challenges.cloudflare.com/turnstile/v0/api.js?onload=onTurnstileLoad'
|
||||
script.async = true
|
||||
script.defer = true
|
||||
|
||||
window.onTurnstileLoad = () => {
|
||||
scriptLoaded.value = true;
|
||||
resolve();
|
||||
};
|
||||
scriptLoaded.value = true
|
||||
resolve()
|
||||
}
|
||||
|
||||
script.onerror = () => {
|
||||
reject(new Error('Failed to load Turnstile script'));
|
||||
};
|
||||
reject(new Error('Failed to load Turnstile script'))
|
||||
}
|
||||
|
||||
document.head.appendChild(script);
|
||||
});
|
||||
};
|
||||
document.head.appendChild(script)
|
||||
})
|
||||
}
|
||||
|
||||
const renderWidget = () => {
|
||||
if (!window.turnstile || !containerRef.value || !props.siteKey) {
|
||||
return;
|
||||
return
|
||||
}
|
||||
|
||||
// Remove existing widget if any
|
||||
if (widgetId.value) {
|
||||
try {
|
||||
window.turnstile.remove(widgetId.value);
|
||||
window.turnstile.remove(widgetId.value)
|
||||
} catch {
|
||||
// Ignore errors when removing
|
||||
}
|
||||
widgetId.value = null;
|
||||
widgetId.value = null
|
||||
}
|
||||
|
||||
// Clear container
|
||||
containerRef.value.innerHTML = '';
|
||||
containerRef.value.innerHTML = ''
|
||||
|
||||
widgetId.value = window.turnstile.render(containerRef.value, {
|
||||
sitekey: props.siteKey,
|
||||
callback: (token: string) => {
|
||||
emit('verify', token);
|
||||
emit('verify', token)
|
||||
},
|
||||
'expired-callback': () => {
|
||||
emit('expire');
|
||||
emit('expire')
|
||||
},
|
||||
'error-callback': () => {
|
||||
emit('error');
|
||||
emit('error')
|
||||
},
|
||||
theme: props.theme,
|
||||
size: props.size,
|
||||
});
|
||||
};
|
||||
size: props.size
|
||||
})
|
||||
}
|
||||
|
||||
const reset = () => {
|
||||
if (window.turnstile && widgetId.value) {
|
||||
window.turnstile.reset(widgetId.value);
|
||||
window.turnstile.reset(widgetId.value)
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// Expose reset method to parent
|
||||
defineExpose({ reset });
|
||||
defineExpose({ reset })
|
||||
|
||||
onMounted(async () => {
|
||||
if (!props.siteKey) {
|
||||
return;
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
await loadScript();
|
||||
renderWidget();
|
||||
await loadScript()
|
||||
renderWidget()
|
||||
} catch (error) {
|
||||
console.error('Failed to initialize Turnstile:', error);
|
||||
emit('error');
|
||||
console.error('Failed to initialize Turnstile:', error)
|
||||
emit('error')
|
||||
}
|
||||
});
|
||||
})
|
||||
|
||||
onUnmounted(() => {
|
||||
if (window.turnstile && widgetId.value) {
|
||||
try {
|
||||
window.turnstile.remove(widgetId.value);
|
||||
window.turnstile.remove(widgetId.value)
|
||||
} catch {
|
||||
// Ignore errors when removing
|
||||
}
|
||||
}
|
||||
});
|
||||
})
|
||||
|
||||
// Re-render when siteKey changes
|
||||
watch(() => props.siteKey, (newKey) => {
|
||||
if (newKey && scriptLoaded.value) {
|
||||
renderWidget();
|
||||
watch(
|
||||
() => props.siteKey,
|
||||
(newKey) => {
|
||||
if (newKey && scriptLoaded.value) {
|
||||
renderWidget()
|
||||
}
|
||||
}
|
||||
});
|
||||
)
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
Reference in New Issue
Block a user