handler.js 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224
  1. 'use strict'
  2. // 等待初始化完毕
  3. document.addEventListener('UniAppJSBridgeReady', () => {
  4. document.body.onclick = function () {
  5. return uni.postMessage({
  6. data: {
  7. action: 'onClick'
  8. }
  9. })
  10. }
  11. uni.postMessage({
  12. data: {
  13. action: 'onJSBridgeReady'
  14. }
  15. })
  16. })
  17. let options
  18. let medias = []
  19. /**
  20. * @description 获取标签的所有属性
  21. * @param {Element} ele
  22. */
  23. function getAttrs(ele) {
  24. const attrs = Object.create(null)
  25. for (let i = ele.attributes.length; i--;) {
  26. attrs[ele.attributes[i].name] = ele.attributes[i].value
  27. }
  28. return attrs
  29. }
  30. /**
  31. * @description 图片加载出错
  32. */
  33. function onImgError() {
  34. if (options[1]) {
  35. this.src = options[1]
  36. this.onerror = null
  37. } // 取消监听点击
  38. this.onclick = null
  39. this.ontouchstart = null
  40. uni.postMessage({
  41. data: {
  42. action: 'onError',
  43. source: 'img',
  44. attrs: getAttrs(this)
  45. }
  46. })
  47. }
  48. /**
  49. * @description 创建 dom 结构
  50. * @param {object[]} nodes 节点数组
  51. * @param {Element} parent 父节点
  52. * @param {string} namespace 命名空间
  53. */
  54. function createDom(nodes, parent, namespace) {
  55. const _loop = function _loop(i) {
  56. const node = nodes[i]
  57. let ele = void 0
  58. if (!node.type || node.type == 'node') {
  59. let { name } = node // svg 需要设置 namespace
  60. if (name == 'svg') namespace = 'http://www.w3.org/2000/svg'
  61. if (name == 'html' || name == 'body') name = 'div' // 创建标签
  62. if (!namespace) ele = document.createElement(name); else ele = document.createElementNS(namespace, name) // 设置属性
  63. for (const item in node.attrs) {
  64. ele.setAttribute(item, node.attrs[item])
  65. } // 递归创建子节点
  66. if (node.children) createDom(node.children, ele, namespace) // 处理图片
  67. if (name == 'img') {
  68. if (!ele.src && ele.getAttribute('data-src')) ele.src = ele.getAttribute('data-src')
  69. if (!node.attrs.ignore) {
  70. // 监听图片点击事件
  71. ele.onclick = function (e) {
  72. e.stopPropagation()
  73. uni.postMessage({
  74. data: {
  75. action: 'onImgTap',
  76. attrs: getAttrs(this)
  77. }
  78. })
  79. }
  80. }
  81. if (options[2]) {
  82. image = new Image()
  83. image.src = ele.src
  84. ele.src = options[2]
  85. image.onload = function () {
  86. ele.src = this.src
  87. }
  88. image.onerror = function () {
  89. ele.onerror()
  90. }
  91. }
  92. ele.onerror = onImgError
  93. } // 处理链接
  94. else if (name == 'a') {
  95. ele.addEventListener('click', function (e) {
  96. e.stopPropagation()
  97. e.preventDefault() // 阻止默认跳转
  98. const href = this.getAttribute('href')
  99. let offset
  100. if (href && href[0] == '#') offset = (document.getElementById(href.substr(1)) || {}).offsetTop
  101. uni.postMessage({
  102. data: {
  103. action: 'onLinkTap',
  104. attrs: getAttrs(this),
  105. offset
  106. }
  107. })
  108. }, true)
  109. } // 处理音视频
  110. else if (name == 'video' || name == 'audio') {
  111. medias.push(ele)
  112. if (!node.attrs.autoplay) {
  113. if (!node.attrs.controls) ele.setAttribute('controls', 'true') // 空白图占位
  114. if (!node.attrs.poster) ele.setAttribute('poster', "data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg'/>")
  115. }
  116. if (options[3]) {
  117. ele.onplay = function () {
  118. for (let _i = 0; _i < medias.length; _i++) {
  119. if (medias[_i] != this) medias[_i].pause()
  120. }
  121. }
  122. }
  123. ele.onerror = function () {
  124. uni.postMessage({
  125. data: {
  126. action: 'onError',
  127. source: name,
  128. attrs: getAttrs(this)
  129. }
  130. })
  131. }
  132. } // 处理表格
  133. else if (name == 'table' && options[4] && !ele.style.cssText.includes('inline')) {
  134. const div = document.createElement('div')
  135. div.style.overflow = 'auto'
  136. div.appendChild(ele)
  137. ele = div
  138. } else if (name == 'svg') namespace = void 0
  139. } else ele = document.createTextNode(node.text.replace(/&amp;/g, '&'))
  140. parent.appendChild(ele)
  141. }
  142. for (let i = 0; i < nodes.length; i++) {
  143. var image
  144. _loop(i)
  145. }
  146. } // 设置 html 内容
  147. window.setContent = function (nodes, opts, append) {
  148. const ele = document.getElementById('content') // 背景颜色
  149. if (opts[0]) document.body.bgColor = opts[0] // 长按复制
  150. if (!opts[5]) ele.style.userSelect = 'none'
  151. if (!append) {
  152. ele.innerHTML = '' // 不追加则先清空
  153. medias = []
  154. }
  155. options = opts
  156. const fragment = document.createDocumentFragment()
  157. createDom(nodes, fragment)
  158. ele.appendChild(fragment) // 触发事件
  159. let height = ele.scrollHeight
  160. uni.postMessage({
  161. data: {
  162. action: 'onLoad',
  163. height
  164. }
  165. })
  166. clearInterval(window.timer)
  167. let ready = false
  168. window.timer = setInterval(() => {
  169. if (ele.scrollHeight != height) {
  170. height = ele.scrollHeight
  171. uni.postMessage({
  172. data: {
  173. action: 'onHeightChange',
  174. height
  175. }
  176. })
  177. } else if (!ready) {
  178. ready = true
  179. uni.postMessage({
  180. data: {
  181. action: 'onReady'
  182. }
  183. })
  184. }
  185. }, 350)
  186. } // 回收计时器
  187. window.onunload = function () {
  188. clearInterval(window.timer)
  189. }