根据项目需求,需要多个webview和自定义的组件根据 API 返回数据动态混排。
并且需要针对css以及图片懒加载优化。
一、添加css
这一点比较简单,webview所显示的内容是通过接口返回获得的字符串。
做一个简单的拼接就可以。
1 2 3 4 5 6 7 8 9 10
| let link = "<link rel=\"stylesheet\" href=\"\(String(describing: Bundle.main.url(forResource: "RichStyle", withExtension: "css")!))\">" let htmlContent = """ <header> <meta name='viewport' content='width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, user-scalable=no' /> \(link) </header> <div class='richtext-container'> \(newContent) </div> """
|
newContent 是内容正文
link 是css样式
其中由于显示问题,需要在头部添加 meta 这一段。
由于css比较多,放在一起不太合适。可以写在另一个文件中,通过 Bundle 形式加载。
这里有个需要注意的地方,css文件存放的位置。
此刻RichStyle.css 存放在/Classes/Utils/ 下。
要在加载html 时,指定在 file:///Classes/Utils/ 目录下。
1
| webView.loadHTMLString(htmlContent, baseURL: URL(string: "file:///Classes/Utils/") )
|
二、图片懒加载
如果是单个webview,且视窗大小固定。可以使用 lazysizes,纯js原生,不依赖任何其他库。
lazysizes 的逻辑是webview 视窗之外的图片懒加载,滑动到视窗的img 才会加载。
但项目中是多个webview 及其他组件 全展开显示在scrollview里面。
webview 视窗高度根据内容高度来的。导致 lazysizes依旧还是在加载同时把所有页面图片加载完,不过加载图片是在 didFinish之后。
目前的解决办法就是:
- 拿到数据后对其中img标签作调整,将src 的值替换到 data-src中,这样没有src 则图片不会加载。或者给src设置一个占位图片的值也可以,并设置好大小。
- 在scrollview 中针对滚动代理方法优化,让页面停止下来时才开始触发加载图片的方法。
- 触发的方法 会让scrollview中 所有的webview 调用 判断是否加载图片的js脚本。并且会传入当前scrollview的contentOffset 和 webview的frame.minY
- js脚本拿到当前webview 当中所有的imgs,遍历每一个img,并根据img的topoff 和webview 的偏移参数计算这个img 是否是在scrollview的视窗内。
- 然后判断修改img的src 加载图片。
- 还有点就是要刷新webview的高度, 可以在加载图片后 js 调swift 刷新高度,或者弄个定时器执行js脚本刷新高度
一、停止滚动触发监测加载图片的方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) { if !decelerate { let dragTpDragStop = scrollView.isTracking && !scrollView.isDragging && !scrollView.isDecelerating if dragTpDragStop { scrollViewDidEndScroll() } } }
func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) { let scrollToScrollStop = !scrollView.isTracking && !scrollView.isDragging && !scrollView.isDecelerating if scrollToScrollStop { scrollViewDidEndScroll() } }
func scrollViewDidEndScroll() { let scrollOffset = scrollView.contentOffset.y for rh in allRichText.enumerated() { rh.element.loadImgsScript(offset:scrollOffset, wkTop: rh.element.frame.minY) } }
|
二、执行每个webview的JS脚本
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| func loadImgsScript(offset: CGFloat, wkTop: CGFloat) { let minOffset = offset let maxOffset = offset + bmy_screenHeight let script = """ var imgs = document.getElementsByTagName('img'); var minOffset = \(minOffset) var maxOffset = \(maxOffset) var wkTop = \(wkTop) function lazyload(){ for(var i=0; i<imgs.length; i++) { var img = imgs[i] var top = img.offsetTop + wkTop var isDisplay = false if((top > minOffset - 300) && top < maxOffset + 300) { isDisplay = true } if(isDisplay){ img.src = img.getAttribute('data-src'); img.setAttribute('class','lazyloaded'); } } } lazyload() """ webView.evaluateJavaScript(script) { (res, error) in if let e = error { print(error) } } }
|
刷新webview 的高度
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| @objc func reloadWebviewHeight() { webView.evaluateJavaScript("document.body.scrollHeight") { (value, error) in guard let safeValue = value else { return } let height = CGFloat(safeValue as! CGFloat)
if height > self.contentHeight { self.contentHeight = height self.webView.snp.updateConstraints({ (make) in make.height.equalTo(height) }) } } }
|