From 2e0175751944df5069993de7ee0424042fc5622f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=B6=85=E7=BA=A7=E8=80=81=E7=99=BD=E5=85=94?= Date: Sat, 2 Aug 2025 11:32:04 +0800 Subject: [PATCH] =?UTF-8?q?FEAT=20=3D>=20=E6=9C=AC=E6=AC=A1=E6=9B=B4?= =?UTF-8?q?=E6=96=B0=E9=A1=B9=E7=9B=AE=E4=B8=BA=EF=BC=9A=20=E5=AE=9A?= =?UTF-8?q?=E7=89=88=E6=9C=ACapp=E9=80=9A=E4=BF=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ckApp/pages/index/index.vue | 281 +++++++++++++++++++++- nkebao/src/pages/iframe/index.module.scss | 59 +++++ nkebao/src/pages/iframe/index.tsx | 89 ++++++- 3 files changed, 418 insertions(+), 11 deletions(-) diff --git a/ckApp/pages/index/index.vue b/ckApp/pages/index/index.vue index 5756d34f..41543154 100644 --- a/ckApp/pages/index/index.vue +++ b/ckApp/pages/index/index.vue @@ -11,6 +11,11 @@ :src="iframeUrl" @message="handleMessage" :fullscreen="false" + :webview-styles="{ + width:'100%', + height:'260px' + }" + > @@ -18,6 +23,22 @@ + + + + + + URL 参数控制: + + + + + + + + 当前URL: + {{iframeUrl}} + @@ -38,17 +59,125 @@ return { title: 'iframe 通信示例', // iframeUrl: 'http://localhost:3000/iframe', - iframeUrl: 'https://kr-op.quwanzhi.com/iframe', + baseUrl: 'https://kr-op.quwanzhi.com/iframe', + iframeUrl: '', // 动态构建的 URL receivedMessages: [], messageId: 0, - iframeSize: 'medium' // 控制 iframe 大小:small, medium, large + iframeSize: 'medium', // 控制 iframe 大小:small, medium, large + // URL 参数配置 + urlParams: { + userId: '12345', + token: 'abc123', + theme: 'dark', + language: 'zh-CN', + timestamp: Date.now() + } } }, onLoad() { // 页面加载时的初始化 console.log('页面加载完成'); + this.buildIframeUrl(); }, methods: { + // 构建 iframe URL,包含参数 + buildIframeUrl() { + // 使用兼容的方式构建 URL 参数 + const params = []; + + // 添加所有参数 + Object.keys(this.urlParams).forEach(key => { + const value = this.urlParams[key]; + if (value !== null && value !== undefined) { + // 对参数进行 URL 编码 + const encodedKey = encodeURIComponent(key); + const encodedValue = encodeURIComponent(String(value)); + params.push(`${encodedKey}=${encodedValue}`); + } + }); + + // 构建完整 URL + const queryString = params.join('&'); + this.iframeUrl = queryString ? `${this.baseUrl}?${queryString}` : this.baseUrl; + console.log('构建的 iframe URL:', this.iframeUrl); + }, + + // 更新 URL 参数 + updateUrlParams(newParams) { + this.urlParams = { ...this.urlParams, ...newParams }; + this.buildIframeUrl(); + console.log('URL 参数已更新:', this.urlParams); + }, + + // 添加新的 URL 参数 + addUrlParam(key, value) { + this.urlParams[key] = value; + this.buildIframeUrl(); + console.log(`添加参数: ${key} = ${value}`); + }, + + // 移除 URL 参数 + removeUrlParam(key) { + if (this.urlParams.hasOwnProperty(key)) { + delete this.urlParams[key]; + this.buildIframeUrl(); + console.log(`移除参数: ${key}`); + } + }, + + // 刷新 iframe(重新加载页面) + refreshIframe() { + this.buildIframeUrl(); + console.log('iframe 已刷新,新 URL:', this.iframeUrl); + }, + + // 演示 URL 参数传递 + demoUrlParams() { + // 模拟不同的参数组合 + const demos = [ + { + name: '用户登录', + params: { + userId: 'user123', + token: 'auth_token_456', + theme: 'light', + language: 'zh-CN' + } + }, + { + name: '管理员模式', + params: { + userId: 'admin001', + token: 'admin_token_789', + theme: 'dark', + language: 'en-US', + role: 'admin', + permissions: 'all' + } + }, + { + name: '测试模式', + params: { + userId: 'test_user', + token: 'test_token', + theme: 'blue', + language: 'zh-CN', + debug: 'true', + version: '1.0.0' + } + } + ]; + + // 随机选择一个演示 + const demo = demos[Math.floor(Math.random() * demos.length)]; + this.updateUrlParams(demo.params); + + uni.showToast({ + title: `已切换到${demo.name}`, + icon: 'success' + }); + }, + // 接收 web-view 发送的消息 handleMessage(event) { // 消息在 event.detail.data 中(是一个数组,取最后一条) @@ -92,11 +221,36 @@ // App 向 web-view 发送消息 sendMessageToWebView(message) { // 通过 ref 获取 web-view 实例,调用 evalJS 执行 web-view 中的函数 - // 注意:需将数据转为字符串(避免语法错误) + + // 验证 message 参数 + if (!message) { + console.error('message 参数为空'); + return; + } + + // 安全地序列化消息 + let safeMessage; + try { + safeMessage = JSON.parse(JSON.stringify(message)); + } catch (e) { + console.error('消息序列化失败:', e); + // 如果序列化失败,创建一个简单的消息对象 + safeMessage = { + id: message.id || 0, + type: message.type || 'fromApp', + content: String(message.content || ''), + timestamp: message.timestamp || Date.now() + }; + } + + console.log('webviewRef:', this.$refs.webviewRef); + if (this.$refs.webviewRef && this.$refs.webviewRef.evalJS) { try { - this.$refs.webviewRef.evalJS(`receiveFromApp(${JSON.stringify(message)})`); - console.log('App 发送消息到 web-view:', message); + const jsCode = `receiveFromApp(${JSON.stringify(safeMessage)})`; + console.log('要执行的 JS 代码:', jsCode); + this.$refs.webviewRef.evalJS(jsCode); + console.log('App 发送消息到 web-view:', safeMessage); } catch (e) { console.error('evalJS 执行失败:', e); } @@ -214,6 +368,123 @@ } } + .btn-secondary { + background: linear-gradient(135deg, #6c757d 0%, #5a6268 100%); + box-shadow: 0 4rpx 12rpx rgba(108, 117, 125, 0.3); + + &:active { + transform: translateY(2rpx); + box-shadow: 0 2rpx 8rpx rgba(108, 117, 125, 0.4); + } + + &:hover { + background: linear-gradient(135deg, #5a6268 0%, #495057 100%); + } + } + + .btn-refresh { + background: linear-gradient(135deg, #ff9800 0%, #f57c00 100%); + box-shadow: 0 4rpx 12rpx rgba(255, 152, 0, 0.3); + + &:hover { + background: linear-gradient(135deg, #f57c00 0%, #ef6c00 100%); + } + } + + // URL 参数控制区域 + .url-controls { + padding: 20rpx; + background: #f0f0f0; + border-bottom: 2rpx solid #e0e0e0; + display: flex; + flex-direction: column; + gap: 16rpx; + } + + .url-title { + font-size: 28rpx; + color: #333; + font-weight: 600; + margin-bottom: 16rpx; + padding-bottom: 16rpx; + border-bottom: 2rpx solid #d0d0d0; + } + + .param-buttons { + display: flex; + gap: 16rpx; + flex-wrap: wrap; + } + + .btn-param { + flex: 1; + background: linear-gradient(135deg, #4caf50 0%, #388e3c 100%); + color: white; + border: none; + border-radius: 20rpx; + padding: 20rpx 16rpx; + font-size: 26rpx; + font-weight: 600; + cursor: pointer; + transition: all 0.3s ease; + box-shadow: 0 4rpx 12rpx rgba(76, 175, 80, 0.3); + + &:active { + transform: translateY(2rpx); + box-shadow: 0 2rpx 8rpx rgba(76, 175, 80, 0.4); + } + + &:hover { + background: linear-gradient(135deg, #388e3c 0%, #2e7d32 100%); + } + } + + .btn-danger { + background: linear-gradient(135deg, #f44336 0%, #d32f2f 100%); + box-shadow: 0 4rpx 12rpx rgba(244, 67, 54, 0.3); + + &:active { + transform: translateY(2rpx); + box-shadow: 0 2rpx 8rpx rgba(244, 67, 54, 0.4); + } + + &:hover { + background: linear-gradient(135deg, #d32f2f 0%, #c62828 100%); + } + } + + .btn-demo { + background: linear-gradient(135deg, #007bff 0%, #0056b3 100%); + box-shadow: 0 4rpx 12rpx rgba(0, 123, 255, 0.3); + + &:active { + transform: translateY(2rpx); + box-shadow: 0 2rpx 8rpx rgba(0, 123, 255, 0.4); + } + + &:hover { + background: linear-gradient(135deg, #0056b3 0%, #004085 100%); + } + } + + .current-url { + display: flex; + align-items: center; + gap: 16rpx; + font-size: 24rpx; + color: #555; + } + + .url-label { + font-weight: 600; + } + + .url-text { + font-family: "Courier New", monospace; + word-break: break-all; + line-height: 1.5; + } + // 消息显示区域 .message-area { flex: 1; diff --git a/nkebao/src/pages/iframe/index.module.scss b/nkebao/src/pages/iframe/index.module.scss index e18c1633..3d092f63 100644 --- a/nkebao/src/pages/iframe/index.module.scss +++ b/nkebao/src/pages/iframe/index.module.scss @@ -276,3 +276,62 @@ width: 100%; } } + +// URL 参数区域样式 +.url-params-section { + margin-top: 20px; + padding-top: 20px; + border-top: 2px solid #e1e5e9; + + h4 { + margin: 0 0 15px 0; + color: #333; + font-size: 1.1rem; + font-weight: 600; + } +} + +.no-params { + color: #666; + font-style: italic; + text-align: center; + padding: 20px; + background: #f8f9fa; + border-radius: 8px; + border: 2px dashed #dee2e6; +} + +.params-list { + display: flex; + flex-direction: column; + gap: 8px; +} + +.param-item { + display: flex; + align-items: center; + padding: 10px 15px; + background: #f8f9fa; + border-radius: 8px; + border-left: 4px solid var(--primary-color); + transition: all 0.3s ease; + + &:hover { + background: #e9ecef; + transform: translateX(5px); + } +} + +.param-key { + font-weight: 600; + color: #333; + min-width: 80px; + margin-right: 10px; +} + +.param-value { + color: #666; + font-family: "Courier New", monospace; + word-break: break-all; + flex: 1; +} diff --git a/nkebao/src/pages/iframe/index.tsx b/nkebao/src/pages/iframe/index.tsx index c3c4c358..8b576add 100644 --- a/nkebao/src/pages/iframe/index.tsx +++ b/nkebao/src/pages/iframe/index.tsx @@ -19,18 +19,50 @@ const IframeDebugPage: React.FC = () => { const [receivedMessages, setReceivedMessages] = useState([]); const [messageId, setMessageId] = useState(0); const [inputMessage, setInputMessage] = useState(""); + const [urlParams, setUrlParams] = useState>({}); + const [processedMessages] = useState(new Set()); // 用于防止重复处理消息 useEffect(() => { + // 解析 URL 参数 + const parseUrlParams = () => { + // 使用兼容的方式解析 URL 参数 + const search = window.location.search.substring(1); // 移除开头的 '?' + const params: Record = {}; + + if (search) { + const pairs = search.split("&"); + pairs.forEach(pair => { + const [key, value] = pair.split("="); + if (key) { + params[decodeURIComponent(key)] = decodeURIComponent(value || ""); + } + }); + } + + setUrlParams(params); + console.log("解析到的 URL 参数:", JSON.stringify(params)); + + // 将 URL 参数作为消息添加到列表 + if (Object.keys(params).length > 0) { + const paramMessage = `[${new Date().toLocaleTimeString()}] URL参数: ${JSON.stringify(params)}`; + setReceivedMessages(prev => [paramMessage, ...prev]); + } + }; + // 初始化 uni-app web-view SDK const initUniSDK = () => { console.log("web-view SDK 初始化完成"); - // 页面加载完成后发送准备就绪消息 + // 页面加载完成后发送准备就绪消息,包含 URL 参数 setTimeout(() => { sendMessageToParent({ id: 0, type: "ready", - data: { status: "loaded", url: window.location.href }, + data: { + status: "loaded", + url: window.location.href, + urlParams: urlParams, + }, timestamp: Date.now(), }); }, 500); @@ -39,6 +71,9 @@ const IframeDebugPage: React.FC = () => { // 监听 SDK 初始化完成事件 document.addEventListener("UniAppJSBridgeReady", initUniSDK); + // 解析 URL 参数 + parseUrlParams(); + // 检查URL参数中的消息 checkUrlMessage(); @@ -64,15 +99,28 @@ const IframeDebugPage: React.FC = () => { document.removeEventListener("UniAppJSBridgeReady", initUniSDK); window.removeEventListener("message", handlePostMessage); }; - }, []); + }, []); // 移除 urlParams 依赖,避免无限循环 // 检查URL参数中的消息 const checkUrlMessage = () => { - const urlParams = new URLSearchParams(window.location.search); - const messageParam = urlParams.get("message"); + // 使用兼容的方式解析 URL 参数 + const search = window.location.search.substring(1); + let messageParam = null; + + if (search) { + const pairs = search.split("&"); + for (const pair of pairs) { + const [key, value] = pair.split("="); + if (key === "message" && value) { + messageParam = decodeURIComponent(value); + break; + } + } + } + if (messageParam) { try { - const message = JSON.parse(decodeURIComponent(messageParam)); + const message = JSON.parse(messageParam); handleParentMessage(message); // 清除URL参数 const newUrl = window.location.pathname; @@ -102,6 +150,18 @@ const IframeDebugPage: React.FC = () => { // 接收 App 发送的消息 const handleParentMessage = (message: Message) => { + // 生成消息的唯一标识,用于防重复处理 + const messageKey = `${message.id}-${message.timestamp}-${JSON.stringify(message.data)}`; + + // 检查是否已经处理过这个消息 + if (processedMessages.has(messageKey)) { + console.log("消息已处理过,跳过:", message); + return; + } + + // 添加到已处理集合 + processedMessages.add(messageKey); + console.log("web-view 收到 App 消息:", message); const messageText = `[${new Date().toLocaleTimeString()}] 收到: ${JSON.stringify(message)}`; setReceivedMessages(prev => [...prev, messageText]); @@ -256,6 +316,23 @@ const IframeDebugPage: React.FC = () => {
消息ID: {messageId}
+ + {/* URL 参数显示区域 */} +
+

URL 参数

+ {Object.keys(urlParams).length === 0 ? ( +
暂无 URL 参数
+ ) : ( +
+ {Object.entries(urlParams).map(([key, value]) => ( +
+ {key}: + {value} +
+ ))} +
+ )} +
);