1 <!DOCTYPE html> 2 <html lang="zh-CN"> 3 <head> 4 <meta charset="UTF-8"> 5 <meta name="viewport" content="width=device-width, initial-scale=1.0"> 6 <title>iframe浠g爜楠岃瘉鍣?- 涓撲笟娴嬭瘯宸ュ叿</title> 7 <style> 8 * { 9 margin: 0; 10 padding: 0; 11 box-sizing: border-box; 12 } 13 14 body { 15 font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; 16 background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); 17 min-height: 100vh; 18 padding: 20px; 19 } 20 21 .container { 22 max-width: 1200px; 23 margin: 0 auto; 24 background: white; 25 border-radius: 15px; 26 box-shadow: 0 20px 40px rgba(0,0,0,0.1); 27 overflow: hidden; 28 } 29 30 .header { 31 background: linear-gradient(135deg, #2c3e50 0%, #34495e 100%); 32 color: white; 33 padding: 30px; 34 text-align: center; 35 } 36 37 .header h1 { 38 font-size: 2.5rem; 39 margin-bottom: 10px; 40 font-weight: 300; 41 } 42 43 .header p { 44 opacity: 0.9; 45 font-size: 1.1rem; 46 } 47 48 .main-content { 49 padding: 40px; 50 } 51 52 .input-section { 53 margin-bottom: 40px; 54 } 55 56 .input-label { 57 display: block; 58 margin-bottom: 15px; 59 font-weight: 600; 60 color: #2c3e50; 61 font-size: 1.1rem; 62 } 63 64 .code-input { 65 width: 100%; 66 min-height: 200px; 67 padding: 20px; 68 border: 2px solid #e1e8ed; 69 border-radius: 10px; 70 font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace; 71 font-size: 14px; 72 resize: vertical; 73 transition: border-color 0.3s ease; 74 } 75 76 .code-input:focus { 77 outline: none; 78 border-color: #667eea; 79 box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.1); 80 } 81 82 .button-group { 83 display: flex; 84 gap: 15px; 85 margin-top: 20px; 86 flex-wrap: wrap; 87 } 88 89 .btn { 90 padding: 12px 30px; 91 border: none; 92 border-radius: 8px; 93 font-size: 16px; 94 font-weight: 600; 95 cursor: pointer; 96 transition: all 0.3s ease; 97 display: flex; 98 align-items: center; 99 gap: 8px; 100 } 101 102 .btn-primary { 103 background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); 104 color: white; 105 } 106 107 .btn-primary:hover { 108 transform: translateY(-2px); 109 box-shadow: 0 10px 20px rgba(102, 126, 234, 0.3); 110 } 111 112 .btn-secondary { 113 background: #e1e8ed; 114 color: #2c3e50; 115 } 116 117 .btn-secondary:hover { 118 background: #d1d8dd; 119 } 120 121 .results-section { 122 margin-top: 40px; 123 } 124 125 .result-card { 126 background: #f8f9fa; 127 border-radius: 10px; 128 padding: 25px; 129 margin-bottom: 20px; 130 border-left: 4px solid #667eea; 131 } 132 133 .result-card.error { 134 border-left-color: #e74c3c; 135 background: #fdf2f2; 136 } 137 138 .result-card.warning { 139 border-left-color: #f39c12; 140 background: #fef9e7; 141 } 142 143 .result-card.success { 144 border-left-color: #27ae60; 145 background: #f2fdf2; 146 } 147 148 .result-title { 149 font-size: 1.2rem; 150 font-weight: 600; 151 margin-bottom: 15px; 152 display: flex; 153 align-items: center; 154 gap: 10px; 155 } 156 157 .result-list { 158 list-style: none; 159 } 160 161 .result-list li { 162 padding: 10px 0; 163 border-bottom: 1px solid #e1e8ed; 164 display: flex; 165 align-items: flex-start; 166 gap: 10px; 167 } 168 169 .result-list li:last-child { 170 border-bottom: none; 171 } 172 173 .severity-badge { 174 padding: 3px 8px; 175 border-radius: 4px; 176 font-size: 12px; 177 font-weight: 600; 178 text-transform: uppercase; 179 } 180 181 .severity-high { 182 background: #e74c3c; 183 color: white; 184 } 185 186 .severity-medium { 187 background: #f39c12; 188 color: white; 189 } 190 191 .severity-low { 192 background: #3498db; 193 color: white; 194 } 195 196 .severity-info { 197 background: #95a5a6; 198 color: white; 199 } 200 201 .icon { 202 width: 20px; 203 height: 20px; 204 display: inline-block; 205 } 206 207 .statistics { 208 display: grid; 209 grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); 210 gap: 20px; 211 margin: 30px 0; 212 } 213 214 .stat-card { 215 background: white; 216 padding: 20px; 217 border-radius: 10px; 218 text-align: center; 219 box-shadow: 0 5px 15px rgba(0,0,0,0.08); 220 border: 2px solid #e1e8ed; 221 } 222 223 .stat-number { 224 font-size: 2rem; 225 font-weight: 700; 226 margin-bottom: 5px; 227 } 228 229 .stat-label { 230 color: #7f8c8d; 231 font-size: 0.9rem; 232 } 233 234 .preview-section { 235 margin-top: 30px; 236 padding: 20px; 237 background: #f8f9fa; 238 border-radius: 10px; 239 } 240 241 .preview-frame { 242 width: 100%; 243 height: 300px; 244 border: 2px solid #e1e8ed; 245 border-radius: 8px; 246 background: white; 247 } 248 249 .hidden { 250 display: none; 251 } 252 253 .loading { 254 display: inline-block; 255 width: 20px; 256 height: 20px; 257 border: 3px solid rgba(255,255,255,.3); 258 border-radius: 50%; 259 border-top-color: white; 260 animation: spin 1s ease-in-out infinite; 261 } 262 263 @keyframes spin { 264 to { transform: rotate(360deg); } 265 } 266 267 .tabs { 268 display: flex; 269 gap: 10px; 270 margin-bottom: 20px; 271 border-bottom: 2px solid #e1e8ed; 272 } 273 274 .tab { 275 padding: 12px 20px; 276 background: none; 277 border: none; 278 border-bottom: 3px solid transparent; 279 cursor: pointer; 280 font-weight: 600; 281 color: #7f8c8d; 282 transition: all 0.3s ease; 283 } 284 285 .tab.active { 286 color: #667eea; 287 border-bottom-color: #667eea; 288 } 289 290 .tab-content { 291 display: none; 292 } 293 294 .tab-content.active { 295 display: block; 296 } 297 </style> 298 </head> 299 <body> 300 <div class="container"> 301 <header class="header"> 302 <h1>馃攳 iframe浠g爜楠岃瘉鍣?/h1> 303 <p>涓撲笟鐨刬frame瀹夊叏鎬у拰鏈€浣冲疄璺垫鏌ュ伐鍏?/p> 304 </header> 305 306 <main class="main-content"> 307 <section class="input-section"> 308 <label class="input-label">璇疯緭鍏ヨ楠岃瘉鐨刬frame浠g爜锛?/label> 309 <textarea 310 id="codeInput" 311 class="code-input" 312 placeholder="璇风矘璐存偍鐨刬frame浠g爜锛屼緥濡傦細 313 <iframe src="https://example.com" width="600" height="400"></iframe>"></textarea> 314 315 <div class="button-group"> 316 <button class="btn btn-primary" onclick="validateCode()"> 317 <span>馃攳</span> 楠岃瘉浠g爜 318 </button> 319 <button class="btn btn-secondary" onclick="clearInput()"> 320 <span>馃棏锔?/span> 娓呯┖ 321 </button> 322 <button class="btn btn-secondary" onclick="loadExample()"> 323 <span>馃摑</span> 鍔犺浇绀轰緥 324 </button> 325 </div> 326 </section> 327 328 <div class="statistics hidden" id="statistics"> 329 <div class="stat-card"> 330 <div class="stat-number" id="totalIssues">0</div> 331 <div class="stat-label">鎬婚棶棰樻暟</div> 332 </div> 333 <div class="stat-card"> 334 <div class="stat-number" id="highIssues" style="color: #e74c3c;">0</div> 335 <div class="stat-label">楂樺嵄闂</div> 336 </div> 337 <div class="stat-card"> 338 <div class="stat-number" id="mediumIssues" style="color: #f39c12;">0</div> 339 <div class="stat-label">涓嵄闂</div> 340 </div> 341 <div class="stat-card"> 342 <div class="stat-number" id="score" style="color: #27ae60;">0</div> 343 <div class="stat-label">瀹夊叏璇勫垎</div> 344 </div> 345 </div> 346 347 <div class="tabs hidden" id="resultTabs"> 348 <button class="tab active" onclick="switchTab('security')">瀹夊叏妫€鏌?/button> 349 <button class="tab" onclick="switchTab('bestPractices')">鏈€浣冲疄璺?/button> 350 <button class="tab" onclick="switchTab('preview')">棰勮鏁堟灉</button> 351 </div> 352 353 <section class="results-section hidden" id="results"> 354 <div id="securityTab" class="tab-content active"> 355 <div id="securityResults"></div> 356 </div> 357 <div id="bestPracticesTab" class="tab-content"> 358 <div id="bestPracticesResults"></div> 359 </div> 360 <div id="previewTab" class="tab-content"> 361 <div class="preview-section"> 362 <h3 style="margin-bottom: 15px;">iframe棰勮</h3> 363 <iframe id="previewFrame" class="preview-frame"></iframe> 364 </div> 365 </div> 366 </section> 367 </main> 368 </div> 369 370 <script> 371 // 楠岃瘉瑙勫垯瀹氫箟 372 const validationRules = { 373 security: [ 374 { 375 name: 'src灞炴€ф鏌?, 376 severity: 'high', 377 check: (iframe) => { 378 if (!iframe.src || iframe.src === '') { 379 return { 380 status: 'error', 381 message: 'iframe缂哄皯src灞炴€э紝杩欐槸蹇呴渶鐨勫睘鎬? 382 }; 383 } 384 if (iframe.src === 'about:blank') { 385 return { 386 status: 'warning', 387 message: '浣跨敤about:blank浣滀负src锛岃纭杩欐槸棰勬湡琛屼负' 388 }; 389 } 390 return { status: 'success' }; 391 } 392 }, 393 { 394 name: 'HTTPS鍗忚妫€鏌?, 395 severity: 'high', 396 check: (iframe) => { 397 if (iframe.src && iframe.src.startsWith('http://')) { 398 return { 399 status: 'error', 400 message: '浣跨敤HTTP鍗忚涓嶅畨鍏紝寤鸿浣跨敤HTTPS' 401 }; 402 } 403 return { status: 'success' }; 404 } 405 }, 406 { 407 name: 'sandbox灞炴€ф鏌?, 408 severity: 'medium', 409 check: (iframe) => { 410 if (!iframe.sandbox) { 411 return { 412 status: 'warning', 413 message: '缂哄皯sandbox灞炴€э紝寤鸿娣诲姞浠ュ寮哄畨鍏ㄦ€? 414 }; 415 } 416 return { status: 'success' }; 417 } 418 }, 419 { 420 name: 'X-Frame-Options闃叉姢', 421 severity: 'medium', 422 check: (iframe) => { 423 return { 424 status: 'info', 425 message: '寤鸿鍦ㄦ湇鍔″櫒璁剧疆X-Frame-Options澶撮儴浠ラ槻姝㈢偣鍑诲姭鎸? 426 }; 427 } 428 }, 429 { 430 name: 'CSP绛栫暐妫€鏌?, 431 severity: 'low', 432 check: (iframe) => { 433 return { 434 status: 'info', 435 message: '寤鸿浣跨敤Content Security Policy (CSP)鏉ユ帶鍒秈frame鍐呭鏉ユ簮' 436 }; 437 } 438 } 439 ], 440 bestPractices: [ 441 { 442 name: 'title灞炴€ф鏌?, 443 severity: 'low', 444 check: (iframe) => { 445 if (!iframe.title) { 446 return { 447 status: 'warning', 448 message: '缂哄皯title灞炴€э紝褰卞搷鍙闂€у拰SEO' 449 }; 450 } 451 return { status: 'success' }; 452 } 453 }, 454 { 455 name: '灏哄灞炴€ф鏌?, 456 severity: 'low', 457 check: (iframe) => { 458 const hasWidth = iframe.width || iframe.style?.width; 459 const hasHeight = iframe.height || iframe.style?.height; 460 461 if (!hasWidth || !hasHeight) { 462 return { 463 status: 'warning', 464 message: '寤鸿璁剧疆width鍜宧eight灞炴€т互閬垮厤甯冨眬鍋忕Щ' 465 }; 466 } 467 return { status: 'success' }; 468 } 469 }, 470 { 471 name: 'loading灞炴€ф鏌?, 472 severity: 'info', 473 check: (iframe) => { 474 if (!iframe.loading) { 475 return { 476 status: 'info', 477 message: '寤鸿娣诲姞loading="lazy"灞炴€т互鎻愬崌椤甸潰鍔犺浇鎬ц兘' 478 }; 479 } 480 return { status: 'success' }; 481 } 482 }, 483 { 484 name: 'allowfullscreen灞炴€?, 485 severity: 'info', 486 check: (iframe) => { 487 if (iframe.allowfullscreen) { 488 return { 489 status: 'info', 490 message: '宸插惎鐢ㄥ叏灞忓姛鑳斤紝璇风‘淇濆唴瀹规敮鎸佸叏灞忔樉绀? 491 }; 492 } 493 return { status: 'success' }; 494 } 495 }, 496 { 497 name: 'referrerpolicy灞炴€?, 498 severity: 'low', 499 check: (iframe) => { 500 if (!iframe.referrerpolicy) { 501 return { 502 status: 'info', 503 message: '寤鸿璁剧疆referrerpolicy灞炴€т互鎺у埗referrer淇℃伅鍙戦€? 504 }; 505 } 506 return { status: 'success' }; 507 } 508 } 509 ] 510 }; 511 512 function validateCode() { 513 const codeInput = document.getElementById('codeInput').value; 514 if (!codeInput.trim()) { 515 alert('璇疯緭鍏ヨ楠岃瘉鐨刬frame浠g爜'); 516 return; 517 } 518 519 try { 520 // 瑙f瀽iframe浠g爜 521 const parser = new DOMParser(); 522 const doc = parser.parseFromString(codeInput, 'text/html'); 523 const iframe = doc.querySelector('iframe'); 524 525 if (!iframe) { 526 showError('鏈壘鍒版湁鏁堢殑iframe鏍囩'); 527 return; 528 } 529 530 // 鎻愬彇iframe灞炴€? const iframeData = extractIframeData(iframe); 531 532 // 鎵ц楠岃瘉 533 const results = performValidation(iframeData); 534 535 // 鏄剧ず缁撴灉 536 displayResults(results, iframeData); 537 538 // 鏄剧ず缁熻 539 displayStatistics(results); 540 541 // 鏄剧ず棰勮 542 displayPreview(iframe); 543 544 } catch (error) { 545 showError('浠g爜瑙f瀽閿欒锛? + error.message); 546 } 547 } 548 549 function extractIframeData(iframe) { 550 const data = {}; 551 for (let attr of iframe.attributes) { 552 data[attr.name] = attr.value; 553 } 554 return data; 555 } 556 557 function performValidation(iframeData) { 558 const results = { 559 security: [], 560 bestPractices: [] 561 }; 562 563 // 鎵ц瀹夊叏妫€鏌? validationRules.security.forEach(rule => { 564 const result = rule.check(iframeData); 565 results.security.push({ 566 ...rule, 567 ...result, 568 iframeData 569 }); 570 }); 571 572 // 鎵ц鏈€浣冲疄璺垫鏌? validationRules.bestPractices.forEach(rule => { 573 const result = rule.check(iframeData); 574 results.bestPractices.push({ 575 ...rule, 576 ...result, 577 iframeData 578 }); 579 }); 580 581 return results; 582 } 583 584 function displayResults(results, iframeData) { 585 // 鏄剧ず缁撴灉鍖哄煙 586 document.getElementById('resultTabs').classList.remove('hidden'); 587 document.getElementById('results').classList.remove('hidden'); 588 589 // 鏄剧ず瀹夊叏妫€鏌ョ粨鏋? const securityResults = document.getElementById('securityResults'); 590 securityResults.innerHTML = generateResultHTML(results.security); 591 592 // 鏄剧ず鏈€浣冲疄璺电粨鏋? const bestPracticesResults = document.getElementById('bestPracticesResults'); 593 bestPracticesResults.innerHTML = generateResultHTML(results.bestPractices); 594 } 595 596 function generateResultHTML(results) { 597 if (results.length === 0) { 598 return '<div class="result-card success"><div class="result-title">鉁?鎵€鏈夋鏌ラ€氳繃</div></div>'; 599 } 600 601 return results.map(result => { 602 const cardClass = result.status === 'error' ? 'error' : 603 result.status === 'warning' ? 'warning' : 604 result.status === 'info' ? 'success' : 'success'; 605 606 const icon = result.status === 'error' ? '鉂? : 607 result.status === 'warning' ? '鈿狅笍' : 608 result.status === 'info' ? '鈩癸笍' : '鉁?; 609 610 return ` 611 <div class="result-card ${cardClass}"> 612 <div class="result-title"> 613 <span class="icon">${icon}</span> 614 ${result.name} 615 <span class="severity-badge severity-${result.severity}">${result.severity}</span> 616 </div> 617 <div class="result-message">${result.message}</div> 618 </div> 619 `; 620 }).join(''); 621 } 622 623 function displayStatistics(results) { 624 const allResults = [...results.security, ...results.bestPractices]; 625 const highIssues = allResults.filter(r => r.severity === 'high' && r.status !== 'success').length; 626 const mediumIssues = allResults.filter(r => r.severity === 'medium' && r.status !== 'success').length; 627 const totalIssues = allResults.filter(r => r.status !== 'success').length; 628 629 // 璁$畻瀹夊叏璇勫垎 (100鍒嗗埗) 630 const maxScore = 100; 631 const deduction = highIssues * 20 + mediumIssues * 10; 632 const score = Math.max(0, maxScore - deduction); 633 634 document.getElementById('statistics').classList.remove('hidden'); 635 document.getElementById('totalIssues').textContent = totalIssues; 636 document.getElementById('highIssues').textContent = highIssues; 637 document.getElementById('mediumIssues').textContent = mediumIssues; 638 document.getElementById('score').textContent = score; 639 } 640 641 function displayPreview(iframe) { 642 const previewFrame = document.getElementById('previewFrame'); 643 previewFrame.srcdoc = iframe.outerHTML; 644 } 645 646 function switchTab(tabName) { 647 // 鍒囨崲鏍囩鐘舵€? document.querySelectorAll('.tab').forEach(tab => { 648 tab.classList.remove('active'); 649 }); 650 event.target.classList.add('active'); 651 652 // 鍒囨崲鍐呭鏄剧ず 653 document.querySelectorAll('.tab-content').forEach(content => { 654 content.classList.remove('active'); 655 }); 656 document.getElementById(tabName + 'Tab').classList.add('active'); 657 } 658 659 function clearInput() { 660 document.getElementById('codeInput').value = ''; 661 document.getElementById('results').classList.add('hidden'); 662 document.getElementById('resultTabs').classList.add('hidden'); 663 document.getElementById('statistics').classList.add('hidden'); 664 } 665 666 function loadExample() { 667 const exampleCode = `<iframe 668 src="https://www.example.com" 669 width="600" 670 height="400" 671 title="绀轰緥iframe鍐呭" 672 sandbox="allow-scripts allow-same-origin" 673 loading="lazy" 674 referrerpolicy="strict-origin-when-cross-origin"> 675 </iframe>`; 676 document.getElementById('codeInput').value = exampleCode; 677 } 678 679 function showError(message) { 680 const resultsDiv = document.getElementById('results'); 681 resultsDiv.classList.remove('hidden'); 682 resultsDiv.innerHTML = ` 683 <div class="result-card error"> 684 <div class="result-title"> 685 <span class="icon">鉂?/span> 686 楠岃瘉澶辫触 687 </div> 688 <div class="result-message">${message}</div> 689 </div> 690 `; 691 } 692 693 // 椤甸潰鍔犺浇鏃剁殑鍒濆鍖? document.addEventListener('DOMContentLoaded', function() { 694 // 鍙互娣诲姞鏇村鍒濆鍖栦唬鐮? }); 695 </script> 696 </body> 697 </html>
iframe代码验证器-专业测试工具