'use strict' // 等待初始化完毕 document.addEventListener('UniAppJSBridgeReady', () => { document.body.onclick = function () { return uni.postMessage({ data: { action: 'onClick' } }) } uni.postMessage({ data: { action: 'onJSBridgeReady' } }) }) let options let medias = [] /** * @description 获取标签的所有属性 * @param {Element} ele */ function getAttrs(ele) { const attrs = Object.create(null) for (let i = ele.attributes.length; i--;) { attrs[ele.attributes[i].name] = ele.attributes[i].value } return attrs } /** * @description 图片加载出错 */ function onImgError() { if (options[1]) { this.src = options[1] this.onerror = null } // 取消监听点击 this.onclick = null this.ontouchstart = null uni.postMessage({ data: { action: 'onError', source: 'img', attrs: getAttrs(this) } }) } /** * @description 创建 dom 结构 * @param {object[]} nodes 节点数组 * @param {Element} parent 父节点 * @param {string} namespace 命名空间 */ function createDom(nodes, parent, namespace) { const _loop = function _loop(i) { const node = nodes[i] let ele = void 0 if (!node.type || node.type == 'node') { let { name } = node // svg 需要设置 namespace if (name == 'svg') namespace = 'http://www.w3.org/2000/svg' if (name == 'html' || name == 'body') name = 'div' // 创建标签 if (!namespace) ele = document.createElement(name); else ele = document.createElementNS(namespace, name) // 设置属性 for (const item in node.attrs) { ele.setAttribute(item, node.attrs[item]) } // 递归创建子节点 if (node.children) createDom(node.children, ele, namespace) // 处理图片 if (name == 'img') { if (!ele.src && ele.getAttribute('data-src')) ele.src = ele.getAttribute('data-src') if (!node.attrs.ignore) { // 监听图片点击事件 ele.onclick = function (e) { e.stopPropagation() uni.postMessage({ data: { action: 'onImgTap', attrs: getAttrs(this) } }) } } if (options[2]) { image = new Image() image.src = ele.src ele.src = options[2] image.onload = function () { ele.src = this.src } image.onerror = function () { ele.onerror() } } ele.onerror = onImgError } // 处理链接 else if (name == 'a') { ele.addEventListener('click', function (e) { e.stopPropagation() e.preventDefault() // 阻止默认跳转 const href = this.getAttribute('href') let offset if (href && href[0] == '#') offset = (document.getElementById(href.substr(1)) || {}).offsetTop uni.postMessage({ data: { action: 'onLinkTap', attrs: getAttrs(this), offset } }) }, true) } // 处理音视频 else if (name == 'video' || name == 'audio') { medias.push(ele) if (!node.attrs.autoplay) { if (!node.attrs.controls) ele.setAttribute('controls', 'true') // 空白图占位 if (!node.attrs.poster) ele.setAttribute('poster', "data:image/svg+xml;utf8,") } if (options[3]) { ele.onplay = function () { for (let _i = 0; _i < medias.length; _i++) { if (medias[_i] != this) medias[_i].pause() } } } ele.onerror = function () { uni.postMessage({ data: { action: 'onError', source: name, attrs: getAttrs(this) } }) } } // 处理表格 else if (name == 'table' && options[4] && !ele.style.cssText.includes('inline')) { const div = document.createElement('div') div.style.overflow = 'auto' div.appendChild(ele) ele = div } else if (name == 'svg') namespace = void 0 } else ele = document.createTextNode(node.text.replace(/&/g, '&')) parent.appendChild(ele) } for (let i = 0; i < nodes.length; i++) { var image _loop(i) } } // 设置 html 内容 window.setContent = function (nodes, opts, append) { const ele = document.getElementById('content') // 背景颜色 if (opts[0]) document.body.bgColor = opts[0] // 长按复制 if (!opts[5]) ele.style.userSelect = 'none' if (!append) { ele.innerHTML = '' // 不追加则先清空 medias = [] } options = opts const fragment = document.createDocumentFragment() createDom(nodes, fragment) ele.appendChild(fragment) // 触发事件 let height = ele.scrollHeight uni.postMessage({ data: { action: 'onLoad', height } }) clearInterval(window.timer) let ready = false window.timer = setInterval(() => { if (ele.scrollHeight != height) { height = ele.scrollHeight uni.postMessage({ data: { action: 'onHeightChange', height } }) } else if (!ready) { ready = true uni.postMessage({ data: { action: 'onReady' } }) } }, 350) } // 回收计时器 window.onunload = function () { clearInterval(window.timer) }