iOS如何通过HTML字符串在WKWebView中展示手风琴组件
解决方案:在WKWebView中实现手风琴组件展示API数据
问题核心
你当前的错误在于直接把API返回的JSON字符串当作HTML加载,而实际上该JSON包含的是手风琴的标题和描述数组,需要先解析数据,再生成对应的手风琴HTML结构,并添加样式与交互逻辑。
现有代码
let fullDesc = responseDict?["description_middle"]?.string ?? "" let htmlString:String! = fullDesc // self.detailWeb.customUserAgent = "Mozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.135 Safari/537.36 Edge/12.10136" self.detailWeb.loadHTMLString("<html><body><style>p{align-items:justify;justify-content:justify} h1, h2, h3, h4, h5, h6{font-size:20px; font-weight:bold;} </style><meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0,Proxima Nova-Regular\">\(htmlString!)</body></html>", baseURL: nil)
API返回数据
"description_middle": "{\"ac_title\":[\"When Should I take this Service?\",\"What benefits will I get by taking this onsite styling consultation service?\",\"Can I select a Fashion Stylist of my choice for this consultation?\",\"What Happens after I make the Payment?\"],\"ac_description\":[\"<p>You should take this Wardrobe Consultation Service if you are facing any of the following situations:</p>\\r\\n\\r\\n<ul>\\r\\n\\t<li>You are struggling to find clothes that fit and flatter your body type</li>\\r\\n\\t<li>You have a big event coming up and need help putting together the perfect outfit</li>\\r\\n\\t<li>you want to update your professional image and make a great first impression</li>\\r\\n\\t<li>you have a closet full of clothes but nothing to wear</li>\\r\\n\\t<li>you want to build a sustainable wardrobe that is both stylish and environmentally friendly</li>\\r\\n</ul>\\r\\n\",\"<p>Taking a Wardrobe Consultation Service brings you several benefits. Some of those benefits are given below:</p>\\r\\n\\r\\n<ul>\\r\\n\\t<li>Time and Convenience: A personal stylist saves your time and effort by doing the shopping, research and curating outfits for you, freeing up your own time to focus on other things.</li>\\r\\n\\t<li>Increased Confidence: A stylist can help you develop your personal style, which can lead to increased confidence in your appearance and self-esteem.</li>\\r\\n\\t<li>Expertise: Personal stylists have expertise in fashion, body shapes, color analysis and current trends, allowing you to benefit from their professional knowledge and advice.</li>\\r\\n\\t<li>Maximizing Wardrobe: A stylist can help you to get the most out of your existing wardrobe, by creating new outfits and suggesting key pieces to purchase, making the most of your investment.</li>\\r\\n\\t<li>Cost Savings: By investing in a personal stylist, you may save money in the long run by avoiding costly fashion mistakes, and making informed purchases that add value to your wardrobe.</li>\\r\\n</ul>\\r\\n\",\"<p>We would be introducing this feature in future. Until then, StyleBuddy will assign you the best available stylist at the time of your booking.</p>\\r\\n\",\"<p>Our Client Support Team will reach out to you to initiate your service sessions. You will be asked to update a Client Information Form, which is required for the Stylist to prepare for your Service. You can also call or WhatsAPP us on +91-00 to enquire about your appointment. This service is available from 10 AM to 7 PM India time except on Sundays.</p>\\r\\n\"]}"
完整实现方案
步骤说明
- 解析API返回的JSON字符串,提取手风琴的标题与描述数组
- 动态生成手风琴的HTML结构
- 内嵌CSS实现手风琴的视觉样式,添加JavaScript处理展开/收起交互
- 将完整HTML加载到WKWebView
代码示例
import UIKit import WebKit class ViewController: UIViewController, WKNavigationDelegate { @IBOutlet weak var detailWeb: WKWebView! override func viewDidLoad() { super.viewDidLoad() detailWeb.navigationDelegate = self // 替换为你的实际API响应数据 guard let fullDesc = responseDict?["description_middle"] as? String, let data = fullDesc.data(using: .utf8), let accordionData = try? JSONSerialization.jsonObject(with: data) as? [String: [String]], let titles = accordionData["ac_title"], let descriptions = accordionData["ac_description"], titles.count == descriptions.count else { detailWeb.loadHTMLString("<html><body><p>加载失败</p></body></html>", baseURL: nil) return } // 生成手风琴面板HTML var accordionHTML = "" for index in 0..<titles.count { accordionHTML += """ <div class="accordion-item"> <button class="accordion-title" onclick="toggleAccordion(this)">\(titles[index])</button> <div class="accordion-content"> \(descriptions[index]) </div> </div> """ } // 完整HTML模板 let finalHTML = """ <html> <head> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <style> body { font-family: 'Proxima Nova-Regular', sans-serif; margin: 16px; } p { text-align: justify; } ul { padding-left: 20px; } /* 手风琴核心样式 */ .accordion-item { margin-bottom: 8px; border: 1px solid #e0e0e0; border-radius: 4px; } .accordion-title { width: 100%; padding: 12px 16px; text-align: left; background-color: #f5f5f5; border: none; border-radius: 4px; font-size: 16px; font-weight: bold; cursor: pointer; display: flex; justify-content: space-between; align-items: center; } .accordion-title::after { content: "+"; font-size: 20px; transition: transform 0.3s; } .accordion-title.active::after { transform: rotate(45deg); } .accordion-content { max-height: 0; overflow: hidden; transition: max-height 0.3s ease-out; padding: 0 16px; } .accordion-content.active { max-height: 1000px; padding: 12px 16px; } </style> </head> <body> \(accordionHTML) <script> function toggleAccordion(button) { button.classList.toggle('active'); const content = button.nextElementSibling; content.classList.toggle('active'); } // 默认展开第一个面板(可选) document.addEventListener('DOMContentLoaded', () => { const firstTitle = document.querySelector('.accordion-title'); firstTitle && toggleAccordion(firstTitle); }); </script> </body> </html> """ detailWeb.loadHTMLString(finalHTML, baseURL: nil) } }
关键说明
- JSON解析:确保将API返回的字符串转成可操作的数组,避免直接加载原始JSON文本
- 动态生成结构:通过循环生成每个手风琴面板,保证数据与UI的对应
- 样式与交互:用CSS实现折叠/展开的过渡动画,JavaScript处理点击事件,实现手风琴核心功能
- 响应式适配:通过viewport标签确保在移动端屏幕上正常显示
内容的提问来源于stack exchange,提问作者Abhinandan Pratap
相关产品推荐
相关产品推荐

