@rxdrag/website-lib-core 0.0.50 → 0.0.52
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/package.json +10 -9
- package/src/astro/README.md +1 -0
- package/src/astro/animation.ts +146 -0
- package/src/astro/background.ts +53 -0
- package/src/astro/grid/consts.ts +80 -0
- package/src/astro/grid/index.ts +2 -0
- package/src/astro/grid/types.ts +35 -0
- package/src/astro/index.ts +7 -0
- package/src/astro/media.ts +109 -0
- package/src/astro/section/index.ts +12 -0
- package/src/entify/Entify.ts +32 -2
- package/src/entify/IEntify.ts +30 -6
- package/src/entify/lib/createUploadCredentials.ts +56 -0
- package/src/entify/lib/index.ts +30 -29
- package/src/entify/lib/newQueryProductOptions.ts +1 -0
- package/src/entify/lib/queryLangs.ts +5 -5
- package/src/entify/lib/queryOneTheme.ts +14 -13
- package/src/index.ts +1 -0
- package/src/react/components/Analytics/eventHandlers.ts +173 -0
- package/src/react/components/Analytics/index.tsx +21 -0
- package/src/react/components/Analytics/singleton.ts +214 -0
- package/src/react/components/Analytics/tracking.ts +221 -0
- package/src/react/components/Analytics/types.ts +60 -0
- package/src/react/components/Analytics/utils.ts +95 -0
- package/src/react/components/BackgroundHlsVideoPlayer.tsx +68 -0
- package/src/react/components/BackgroundVideoPlayer.tsx +32 -0
- package/src/react/components/ContactForm/ContactForm.tsx +286 -0
- package/src/react/components/ContactForm/FileUpload.tsx +430 -0
- package/src/react/components/ContactForm/Input.tsx +6 -10
- package/src/react/components/ContactForm/Input2.tsx +64 -0
- package/src/react/components/ContactForm/Submit.tsx +25 -10
- package/src/react/components/ContactForm/Textarea.tsx +7 -10
- package/src/react/components/ContactForm/Textarea2.tsx +64 -0
- package/src/react/components/ContactForm/factory.tsx +49 -0
- package/src/react/components/ContactForm/funcs.ts +64 -0
- package/src/react/components/ContactForm/index.ts +7 -0
- package/src/react/components/ContactForm/types.ts +67 -0
- package/src/react/components/ContactForm/useVisitorInfo.ts +31 -0
- package/src/react/components/index.ts +3 -0
- package/src/react/components/ContactForm/index.tsx +0 -351
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
// Analytics 跟踪相关函数
|
|
2
|
+
import type { AnalyticsState, PageData, TrackingData } from './types';
|
|
3
|
+
import {
|
|
4
|
+
getDeviceInfo,
|
|
5
|
+
getPlatform,
|
|
6
|
+
getBrowserLanguage,
|
|
7
|
+
detectPageType,
|
|
8
|
+
getCookie
|
|
9
|
+
} from './utils';
|
|
10
|
+
|
|
11
|
+
// 更新活跃时间
|
|
12
|
+
export function updateActiveTime(state: AnalyticsState): void {
|
|
13
|
+
if (state.isPageVisible) {
|
|
14
|
+
const now = Date.now();
|
|
15
|
+
state.activeTime += now - state.lastActiveTime;
|
|
16
|
+
state.lastActiveTime = now;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// 重置页面跟踪(用于页面切换)
|
|
21
|
+
export function resetPageTracking(state: AnalyticsState, pageData: PageData): void {
|
|
22
|
+
const newUrl = window.location.href;
|
|
23
|
+
// 只有当 URL 真正改变时才重置
|
|
24
|
+
if (newUrl !== state.currentPageUrl) {
|
|
25
|
+
state.currentPageUrl = newUrl;
|
|
26
|
+
pageData.start_time = Date.now();
|
|
27
|
+
state.pageLoadTime = Date.now();
|
|
28
|
+
state.isPageTracked = false;
|
|
29
|
+
// 重置活跃时间追踪
|
|
30
|
+
state.activeTime = 0;
|
|
31
|
+
state.lastActiveTime = Date.now();
|
|
32
|
+
state.isPageVisible = !document.hidden;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// 检查是否为真正的页面访问(简化版)
|
|
37
|
+
export function isRealPageVisit(state: AnalyticsState): boolean {
|
|
38
|
+
const now = Date.now();
|
|
39
|
+
|
|
40
|
+
// 如果页面已经被跟踪过,则不是新访问
|
|
41
|
+
if (state.isPageTracked) {
|
|
42
|
+
return false;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// 检查是否在短时间内重复跟踪(全局防重复)
|
|
46
|
+
if (state.lastTrackTime > 0 && now - state.lastTrackTime < 1000) {
|
|
47
|
+
return false;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// 检查页面是否可见(避免在后台标签页中统计)
|
|
51
|
+
if (document.hidden || document.visibilityState === "hidden") {
|
|
52
|
+
return false;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
return true;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// 处理队列中的下一个请求
|
|
59
|
+
export function processQueue(state: AnalyticsState, apiEndpoint: string): void {
|
|
60
|
+
state.isRequestPending = false;
|
|
61
|
+
|
|
62
|
+
if (state.requestQueue.length > 0) {
|
|
63
|
+
const { data, eventType } = state.requestQueue.shift()!;
|
|
64
|
+
// 小延迟避免请求过于频繁
|
|
65
|
+
setTimeout(() => {
|
|
66
|
+
sendImmediately(data, eventType, state, apiEndpoint);
|
|
67
|
+
}, 100);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// 立即发送数据
|
|
72
|
+
export function sendImmediately(
|
|
73
|
+
data: TrackingData,
|
|
74
|
+
eventType: string,
|
|
75
|
+
state: AnalyticsState,
|
|
76
|
+
apiEndpoint: string
|
|
77
|
+
): void {
|
|
78
|
+
state.isRequestPending = true;
|
|
79
|
+
|
|
80
|
+
fetch(apiEndpoint, {
|
|
81
|
+
method: "POST",
|
|
82
|
+
headers: {
|
|
83
|
+
"Content-Type": "application/json",
|
|
84
|
+
"X-Requested-With": "XMLHttpRequest",
|
|
85
|
+
},
|
|
86
|
+
body: JSON.stringify(data),
|
|
87
|
+
keepalive: true,
|
|
88
|
+
})
|
|
89
|
+
.then(() => {
|
|
90
|
+
if (eventType === "pageView") {
|
|
91
|
+
state.isPageTracked = true;
|
|
92
|
+
state.lastTrackTime = Date.now();
|
|
93
|
+
|
|
94
|
+
// 更新全局状态(用于跨组件实例共享)
|
|
95
|
+
if (typeof window !== 'undefined') {
|
|
96
|
+
(window as any).__analyticsGlobalState = {
|
|
97
|
+
lastPageUrl: window.location.href,
|
|
98
|
+
lastTrackTime: Date.now(),
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// 处理队列中的下一个请求
|
|
104
|
+
processQueue(state, apiEndpoint);
|
|
105
|
+
})
|
|
106
|
+
.catch(() => {
|
|
107
|
+
processQueue(state, apiEndpoint);
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// 优化的网络请求函数
|
|
112
|
+
export function sendTrackingData(
|
|
113
|
+
data: TrackingData,
|
|
114
|
+
eventType: string,
|
|
115
|
+
state: AnalyticsState,
|
|
116
|
+
apiEndpoint: string
|
|
117
|
+
): void {
|
|
118
|
+
// 对于 pageLeave 事件,立即发送(用户可能马上离开)
|
|
119
|
+
if (eventType === "pageLeave") {
|
|
120
|
+
sendImmediately(data, eventType, state, apiEndpoint);
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// 对于 pageView 事件,可以稍微延迟或批量处理
|
|
125
|
+
if (state.isRequestPending) {
|
|
126
|
+
// 如果有请求正在进行,加入队列
|
|
127
|
+
state.requestQueue.push({ data, eventType });
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
sendImmediately(data, eventType, state, apiEndpoint);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
// 创建跟踪数据
|
|
135
|
+
export function createTrackingData(
|
|
136
|
+
pageData: PageData,
|
|
137
|
+
state: AnalyticsState,
|
|
138
|
+
eventType: string,
|
|
139
|
+
effectiveDuration: number
|
|
140
|
+
): TrackingData {
|
|
141
|
+
return {
|
|
142
|
+
visitor_id: pageData.visitor_id,
|
|
143
|
+
session_id: pageData.session_id,
|
|
144
|
+
url: window.location.href,
|
|
145
|
+
path: window.location.pathname,
|
|
146
|
+
referrer: state.currentReferrer,
|
|
147
|
+
user_agent: pageData.user_agent,
|
|
148
|
+
duration_ms: effectiveDuration, // 使用活跃时间
|
|
149
|
+
timestamp: Date.now(),
|
|
150
|
+
type: eventType, // 添加事件类型
|
|
151
|
+
// 设备和平台信息
|
|
152
|
+
device: getDeviceInfo(),
|
|
153
|
+
platform: getPlatform(),
|
|
154
|
+
browser_language: getBrowserLanguage(),
|
|
155
|
+
// 页面信息
|
|
156
|
+
page_title: document.title || null,
|
|
157
|
+
// 屏幕信息
|
|
158
|
+
screen_width: screen.width,
|
|
159
|
+
screen_height: screen.height,
|
|
160
|
+
viewport_width: window.innerWidth,
|
|
161
|
+
viewport_height: window.innerHeight,
|
|
162
|
+
// 时区信息
|
|
163
|
+
timezone: Intl.DateTimeFormat().resolvedOptions().timeZone,
|
|
164
|
+
// 是否新用户(简单判断:第一次访问该域名)
|
|
165
|
+
is_new_user:
|
|
166
|
+
!getCookie("visitor_id") ||
|
|
167
|
+
getCookie("visitor_id") === pageData.visitor_id,
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
// 发送访客数据(支持不同类型)
|
|
172
|
+
export function trackPageEvent(
|
|
173
|
+
eventType: string,
|
|
174
|
+
pageData: PageData,
|
|
175
|
+
state: AnalyticsState,
|
|
176
|
+
apiEndpoint: string,
|
|
177
|
+
debugLog: (...args: any[]) => void
|
|
178
|
+
): void {
|
|
179
|
+
// 对于 pageView 事件,检测页面类型
|
|
180
|
+
if (eventType === "pageView") {
|
|
181
|
+
eventType = detectPageType(eventType);
|
|
182
|
+
debugLog("Detected page type:", eventType);
|
|
183
|
+
|
|
184
|
+
// 检查是否为真正的页面访问
|
|
185
|
+
if (!isRealPageVisit(state)) {
|
|
186
|
+
return;
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
// 计算活跃时间
|
|
191
|
+
let effectiveDuration = 0;
|
|
192
|
+
if (eventType === "pageLeave") {
|
|
193
|
+
updateActiveTime(state); // 更新到当前时间
|
|
194
|
+
effectiveDuration = state.activeTime;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
debugLog("Using referrer:", state.currentReferrer, "for event:", eventType);
|
|
198
|
+
|
|
199
|
+
const data = createTrackingData(pageData, state, eventType, effectiveDuration);
|
|
200
|
+
|
|
201
|
+
// 优化的网络请求处理
|
|
202
|
+
sendTrackingData(data, eventType, state, apiEndpoint);
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
// 兼容性函数,保持向后兼容
|
|
206
|
+
export function trackPageVisit(
|
|
207
|
+
pageData: PageData,
|
|
208
|
+
state: AnalyticsState,
|
|
209
|
+
apiEndpoint: string,
|
|
210
|
+
debugLog: (...args: any[]) => void
|
|
211
|
+
): void {
|
|
212
|
+
// 检查是否在短时间内(200ms)重复调用同一个 URL 的 pageView
|
|
213
|
+
const currentUrl = window.location.href;
|
|
214
|
+
const now = Date.now();
|
|
215
|
+
|
|
216
|
+
if (state.isPageTracked && state.currentPageUrl === currentUrl && now - state.lastTrackTime < 200) {
|
|
217
|
+
return;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
trackPageEvent("pageView", pageData, state, apiEndpoint, debugLog);
|
|
221
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
// Analytics 相关的类型定义
|
|
2
|
+
|
|
3
|
+
export interface AnalyticsProps {
|
|
4
|
+
apiEndpoint?: string;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export interface PageData {
|
|
8
|
+
visitor_id: string;
|
|
9
|
+
session_id: string;
|
|
10
|
+
url: string;
|
|
11
|
+
path: string;
|
|
12
|
+
referrer: string | null;
|
|
13
|
+
user_agent: string;
|
|
14
|
+
start_time: number;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export interface TrackingData {
|
|
18
|
+
visitor_id: string;
|
|
19
|
+
session_id: string;
|
|
20
|
+
url: string;
|
|
21
|
+
path: string;
|
|
22
|
+
referrer: string | null;
|
|
23
|
+
user_agent: string;
|
|
24
|
+
duration_ms: number;
|
|
25
|
+
timestamp: number;
|
|
26
|
+
type: string;
|
|
27
|
+
device: string;
|
|
28
|
+
platform: string;
|
|
29
|
+
browser_language: string;
|
|
30
|
+
page_title: string | null;
|
|
31
|
+
screen_width: number;
|
|
32
|
+
screen_height: number;
|
|
33
|
+
viewport_width: number;
|
|
34
|
+
viewport_height: number;
|
|
35
|
+
timezone: string;
|
|
36
|
+
is_new_user: boolean;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export interface RequestQueueItem {
|
|
40
|
+
data: TrackingData;
|
|
41
|
+
eventType: string;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export interface AnalyticsState {
|
|
45
|
+
isPageTracked: boolean;
|
|
46
|
+
currentPageUrl: string;
|
|
47
|
+
pageLoadTime: number;
|
|
48
|
+
lastTrackTime: number;
|
|
49
|
+
currentReferrer: string | null;
|
|
50
|
+
activeTime: number;
|
|
51
|
+
lastActiveTime: number;
|
|
52
|
+
isPageVisible: boolean;
|
|
53
|
+
requestQueue: RequestQueueItem[];
|
|
54
|
+
isRequestPending: boolean;
|
|
55
|
+
isAstroEnvironment: boolean;
|
|
56
|
+
pageLeaveTracked: boolean;
|
|
57
|
+
initialLoadHandled: boolean;
|
|
58
|
+
interactionThrottled: boolean;
|
|
59
|
+
lastInteractionTime: number;
|
|
60
|
+
}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
// Analytics 工具函数
|
|
2
|
+
|
|
3
|
+
// 检查是否为开发环境
|
|
4
|
+
export function isDevelopmentEnvironment(): boolean {
|
|
5
|
+
return (
|
|
6
|
+
window.location.hostname === "localhost" ||
|
|
7
|
+
window.location.hostname.startsWith("192.168.") ||
|
|
8
|
+
window.location.hostname === "127.0.0.1"
|
|
9
|
+
);
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
// 调试日志函数
|
|
13
|
+
export function createDebugLogger() {
|
|
14
|
+
const isDev = isDevelopmentEnvironment();
|
|
15
|
+
return function debugLog(...args: unknown[]) {
|
|
16
|
+
if (isDev) {
|
|
17
|
+
console.log("[Analytics]", ...args);
|
|
18
|
+
}
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
// 生成唯一 ID(简单版)
|
|
23
|
+
export function generateId(prefix = "v"): string {
|
|
24
|
+
return (
|
|
25
|
+
prefix +
|
|
26
|
+
Date.now().toString(36) +
|
|
27
|
+
Math.random().toString(36).substring(2, 8)
|
|
28
|
+
);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// 设置 cookie
|
|
32
|
+
export function setCookie(name: string, value: string, days: number): void {
|
|
33
|
+
const expires = new Date();
|
|
34
|
+
expires.setTime(expires.getTime() + days * 24 * 60 * 60 * 1000);
|
|
35
|
+
document.cookie = `${name}=${value};expires=${expires.toUTCString()};path=/;SameSite=Lax`;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// 获取 cookie
|
|
39
|
+
export function getCookie(name: string): string | null {
|
|
40
|
+
const match = document.cookie.match(
|
|
41
|
+
new RegExp("(^| )" + name + "=([^;]+)")
|
|
42
|
+
);
|
|
43
|
+
return match ? match[2] : null;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// 获取或生成 visitor_id(长期存储)
|
|
47
|
+
export function getVisitorId(): string {
|
|
48
|
+
let visitorId = getCookie("visitor_id");
|
|
49
|
+
if (!visitorId) {
|
|
50
|
+
visitorId = generateId("v");
|
|
51
|
+
setCookie("visitor_id", visitorId, 365); // 365天有效
|
|
52
|
+
}
|
|
53
|
+
return visitorId;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// 获取设备信息
|
|
57
|
+
export function getDeviceInfo(): string {
|
|
58
|
+
const ua = navigator.userAgent;
|
|
59
|
+
if (/Mobile|Android|iPhone|iPad/.test(ua)) {
|
|
60
|
+
return /iPad/.test(ua) ? "tablet" : "mobile";
|
|
61
|
+
}
|
|
62
|
+
return "desktop";
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// 获取平台信息
|
|
66
|
+
export function getPlatform(): string {
|
|
67
|
+
const ua = navigator.userAgent;
|
|
68
|
+
if (/Windows/.test(ua)) return "Windows";
|
|
69
|
+
if (/Mac/.test(ua)) return "macOS";
|
|
70
|
+
if (/Linux/.test(ua)) return "Linux";
|
|
71
|
+
if (/Android/.test(ua)) return "Android";
|
|
72
|
+
if (/iPhone|iPad/.test(ua)) return "iOS";
|
|
73
|
+
return "Unknown";
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// 获取浏览器语言
|
|
77
|
+
export function getBrowserLanguage(): string {
|
|
78
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
79
|
+
return navigator.language || (navigator as any).userLanguage || "en";
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// 检测页面类型
|
|
83
|
+
export function detectPageType(defaultType = "pageView"): string {
|
|
84
|
+
const currentPath = window.location.pathname.toLowerCase();
|
|
85
|
+
|
|
86
|
+
// 检测是否为 thanks 页面
|
|
87
|
+
if (
|
|
88
|
+
currentPath.includes("/thanks") ||
|
|
89
|
+
currentPath.includes("/thank-you")
|
|
90
|
+
) {
|
|
91
|
+
return "enquiry";
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
return defaultType;
|
|
95
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { useEffect, useRef, type VideoHTMLAttributes } from "react";
|
|
2
|
+
import Hls from "hls.js";
|
|
3
|
+
|
|
4
|
+
export function BackgroundHlsVideoPlayer(
|
|
5
|
+
props: VideoHTMLAttributes<HTMLVideoElement>
|
|
6
|
+
) {
|
|
7
|
+
const { poster, src, className, ...restProps } = props;
|
|
8
|
+
const videoRef = useRef<HTMLVideoElement>(null);
|
|
9
|
+
|
|
10
|
+
useEffect(() => {
|
|
11
|
+
if (!videoRef.current || !src) return;
|
|
12
|
+
|
|
13
|
+
const video = videoRef.current;
|
|
14
|
+
|
|
15
|
+
if (!Hls.isSupported()) {
|
|
16
|
+
if (video.canPlayType("application/vnd.apple.mpegurl")) {
|
|
17
|
+
video.src = src;
|
|
18
|
+
video.play().catch(() => {});
|
|
19
|
+
}
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const hls = new Hls({
|
|
24
|
+
enableWorker: true,
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
hls.on(Hls.Events.MANIFEST_PARSED, () => {
|
|
28
|
+
video.play().catch(() => {});
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
hls.on(Hls.Events.ERROR, (event, data) => {
|
|
32
|
+
if (data.fatal) {
|
|
33
|
+
switch (data.type) {
|
|
34
|
+
case Hls.ErrorTypes.NETWORK_ERROR:
|
|
35
|
+
hls.startLoad();
|
|
36
|
+
break;
|
|
37
|
+
case Hls.ErrorTypes.MEDIA_ERROR:
|
|
38
|
+
hls.recoverMediaError();
|
|
39
|
+
break;
|
|
40
|
+
default:
|
|
41
|
+
hls.destroy();
|
|
42
|
+
break;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
hls.loadSource(src);
|
|
48
|
+
hls.attachMedia(video);
|
|
49
|
+
|
|
50
|
+
return () => {
|
|
51
|
+
hls.destroy();
|
|
52
|
+
};
|
|
53
|
+
}, [src]);
|
|
54
|
+
|
|
55
|
+
return (
|
|
56
|
+
<video
|
|
57
|
+
ref={videoRef}
|
|
58
|
+
autoPlay
|
|
59
|
+
loop
|
|
60
|
+
muted
|
|
61
|
+
playsInline
|
|
62
|
+
poster={poster}
|
|
63
|
+
className={className}
|
|
64
|
+
preload="metadata"
|
|
65
|
+
{...restProps}
|
|
66
|
+
></video>
|
|
67
|
+
);
|
|
68
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { useEffect, useRef, type VideoHTMLAttributes } from "react";
|
|
2
|
+
|
|
3
|
+
export function VideoPlayer(props: VideoHTMLAttributes<HTMLVideoElement>) {
|
|
4
|
+
const { poster, src, className, ...restProps } = props;
|
|
5
|
+
const videoRef = useRef<HTMLVideoElement>(null);
|
|
6
|
+
|
|
7
|
+
useEffect(() => {
|
|
8
|
+
if (videoRef.current) {
|
|
9
|
+
const video = videoRef.current;
|
|
10
|
+
|
|
11
|
+
// 确保视频可以自动播放
|
|
12
|
+
video.play().catch((error) => {
|
|
13
|
+
console.log("自动播放失败:", error);
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
}, []);
|
|
17
|
+
|
|
18
|
+
return (
|
|
19
|
+
<video
|
|
20
|
+
ref={videoRef}
|
|
21
|
+
autoPlay
|
|
22
|
+
loop
|
|
23
|
+
muted
|
|
24
|
+
playsInline
|
|
25
|
+
poster={poster}
|
|
26
|
+
className={className}
|
|
27
|
+
preload="metadata"
|
|
28
|
+
src={src}
|
|
29
|
+
{...restProps}
|
|
30
|
+
></video>
|
|
31
|
+
);
|
|
32
|
+
}
|