IOS内嵌H5页面实现(JS实现图片正常显示,并正确返回文档的高度)

本文介绍了一种iOS应用中使用H5页面渲染文章详情的技术方案,通过ObjC与JavaScript交互实现动态加载并适配图片,同时确保文档高度正确返回。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1、需求

由于IOS原生开发对含有html标签的数据处理很麻烦,所以在做文章详情时,采用内嵌H5页面形式混合开发。

2、流程

ObjC将字符串类型的数据,通过Window上的JS方法将数据传递给JS。JS拿到数据渲染H5页面,并通知ObjC H5文档高度(JS实现图片正常显示,并正确返回文档的高度)。

这里写图片描述

3、实现
  • JS方法定义

index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no">
    <title>文章详情</title>
</head>
<body>
<div class="article-wrapper">
    <div class="article-content" id="content">
        <p>数据加载中...</p>
    </div>
</div>
<script src="app.js"></script>
<script>
// 原生App中,通过调用articleDetail()方法,将数据传递到该页面,
// js实现页面渲染
function articleDetail(content) {
    cap.init('#content', content);
}
</script>
</body>
</html>

app.js

/*
 * Create by Capricorncd 2017
*/
// 方法封装
var cap = function () {
    // 预加载图片
    var LOADING_IMG = 'http://xmqvip1-1253933147.picgz.myqcloud.com/backend/2017/08/28/1503890004850.gif?imageView2'

    // 图片id前缀
    var idPrefix = 'IMG' + new Date().getTime() + '_';

    // 替换预加载图片
    var showPreloadImages = function (str) {
        var arr = str.match(/<img.*?>/ig);
        var images = {};
        var count = 0;
        if (arr) {
            for (var i = 0; i < arr.length; i++) {
                if (/src=(?:'|")(.+?)(?:'|")/ig.test(arr[i])) {
                    images[i] = RegExp.$1;
                    count++;
                }
                var tmp = '<img id="'+ (idPrefix + i) +'" src="'+ LOADING_IMG +'" width="200" height="200">';
                str = str.replace(arr[i], tmp);
            }
            preloadImages(images, count);
        }
        return str;
    }

    // 预加载图片
    var preloadImages = function (images, len) {
        if (!len) return;
        var count = 0;
        var newImages = {};
        for (var key in images) {
            imgLoading(images[key], key, function (data, index) {
                newImages[index] = data;
                count++;
                if (count == len) {
                    reloadDocument(newImages);
                }
            })
        }
    }

    // 加载图片
    var imgLoading = function (img, index, callback) {
        var image = new Image();
        image.src = img;
        image.onload = function () {
            callback && callback(image, index);
        }
        image.onerror = function () {
            callback && callback(image, index);
        }
    }

    // 重新渲染页面
    var reloadDocument = function (images) {
        // console.log(images);
        for (var key in images) {
            var img = images[key];
            var elem = getElm('#' + idPrefix + key);
            elem.src = img.src;
            var wh = resizeToImage(elem, img);
            elem.setAttribute('width', wh.w);
            elem.setAttribute('height', wh.h);
        }
        callbackDocHeight();
    }

    // 重新计算图片尺寸
    var resizeToImage = function (elem, img) {
        // 父级容器宽度
        var parentNodeWidth = elem.parentNode ? elem.parentNode.offsetWidth : el.offsetWidth;
        var w = img.width, h = img.height;
        if (img.width > parentNodeWidth) {
            w = parentNodeWidth;
            h = Math.ceil(img.height*(parentNodeWidth/img.width));
        }
        return {w: w, h: h};
    }

    // 清除content文档数据中的换行
    var clearLineBreak = function (content) {
        return content.replace(/[\n\r]|<p>\0*?<\/p>/ig, '');
    }

    // 获取文档高度
    var callbackDocHeight = function () {
        setTimeout(function () {
            var oh = document.body.offsetHeight + 24;
            try {
                // 调用ObjC的方法
                window.webkit.messageHandlers.webViewActualHeight.postMessage(oh);
            } catch (e) {}
        }, 0);
    }

    // 获取DOM元素
    var getElm = function (selector) {
        return document.querySelector(selector);
    }

    return {
        init: function (selector, content) {
            var el = getElm(selector);
            var timer = setTimeout(function () {
                el.innerHTML = '<p>ERROR: 数据加载超时...</p>';
                callbackDocHeight();
                if (timer) clearTimeout(timer);
            }, 3000);

            content = showPreloadImages(clearLineBreak(content));
            if (timer) clearTimeout(timer);
            el.innerHTML = content || '<p>ERROR: 获取数据失败!</p>';
            callbackDocHeight();
        },
        // 拼接纯文本数据使用
        // 将纯文本转换为html代码
        textHandler: function (text) {
            if (!text) return '';
            // 将换行符/回车转换为p标签
            return '<p>' + text.replace(/[\r\n]/ig, '</p><p>') + '</p>';
        },
        // 拼接图片数组使用
        // 将图片转换为html代码
        imgHandle: function (imgs) {
            if (!imgs instanceof Array) return '';
            var content = '';
            for (var i = 0; i < imgs.length; i++) {
                content += '<p><img src="'+ imgs[i] +'"></p>';
            }
            return content;
        }
    }
}();
  • ObjC方法定义
[configuration.userContentController addScriptMessageHandler:self name:@"webViewActualHeight"];
- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message
{
    NSLog(@"body:%@", message.body);
    if ([message.name isEqualToString:@"webViewActualHeight"]) {
        CGFloat height = [message.body doubleValue];
        self.myWebView.frame = CGRectMake(20, CGRectGetMaxY(self.topicCreateTimeL.frame), SCREEN_W-40, height);
        self.bottomLine.frame = CGRectMake(20, CGRectGetMaxY(self.myWebView.frame)+20, 50, 2);
        if(self.headerHeight) {
            self.headerHeight(CGRectGetMaxY(self.bottomLine.frame));
        }
    }
}

至此,就实现了与原生App的一种交互模式,并正确返回文档的高度。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值