toJson.js 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296
  1. const Audio = require('./Audio'),
  2. tagsAndAttrs = require('./tagsAndAttrs');
  3. class ToJson {
  4. constructor(html,app){
  5. const _ts = this;
  6. let m = _ts.m = {};
  7. m.parse = require('./parse5');
  8. _ts.html = html;
  9. _ts.data = {};
  10. _ts.app = app;
  11. // 得到整体页面的数据
  12. _ts.data.document = m.parse.parse(_ts.html);
  13. // 得到body部分的数据
  14. _ts.data.body = _ts.getBodyData(_ts.data.document);
  15. // 生成当前的数据ID
  16. _ts.id = `dataId_${+new Date}_${(Math.random()+'').slice(2)}`;
  17. // 将数据保存到全局
  18. global.__towxmldata__ = global.__towxmldata__ || {};
  19. global.__towxmldata__[_ts.id] = global.__towxmldata__[_ts.id] || {};
  20. global.__towxmldata__[_ts.id].audio = {};
  21. }
  22. getData(){
  23. const _ts = this,
  24. m = _ts.m;
  25. let data = _ts.data,
  26. outData = _ts.sortOut(data.body);
  27. outData.node = 'root';
  28. // 为数据添加ID
  29. outData.id = _ts.id;
  30. global.__towxmldata__[_ts.id].article = outData;
  31. return global.__towxmldata__[_ts.id].article;
  32. }
  33. /**
  34. * 遍历页面数据整理成小程序想要的
  35. */
  36. sortOut(bodyData){
  37. const _ts = this,
  38. app = _ts.app,
  39. appData = app.data ;
  40. let result = {},
  41. arrange;
  42. (arrange = (data,result)=>{
  43. // 当有数据且有子元素时则遍历
  44. if(data && data.childNodes && data.childNodes.length){
  45. // 子元素数据不存在时,创建一个空的数组用以存储子元素数据
  46. if(!result.child){
  47. result.child = [];
  48. };
  49. // 遍历子节点,处理节点的数据
  50. for(let i=0,len=data.childNodes.length; i<len; i++){
  51. let node = data.childNodes[i], // 得到具体的节点
  52. attrs = node.attrs, // 得到节点的属性(一个数组)
  53. attrsLength = attrs && attrs.length ? attrs.length : 0, // 得到节点属性的长度
  54. current = { // 创建一个空对象,用于存储节点属性及处理之后的属性
  55. _e:{},
  56. attr:{} // html的原始数据
  57. };
  58. if(node){
  59. result.child.push(current);
  60. };
  61. // 如果有属性则处理其属性
  62. if (attrsLength) {
  63. if (current._e.attr === undefined) {
  64. //current.attr = {};
  65. current._e.attr = {};
  66. };
  67. for (let i = 0; i < attrsLength; i++) {
  68. let attrsItem = attrs[i],
  69. key = attrsItem.name,
  70. val = attrsItem.value;
  71. current.attr[key] = val;
  72. current._e.attr[key] = val;
  73. };
  74. };
  75. for(let key in node){
  76. // 保留最原始的html数据,父节点数据去掉(小程序会报错)
  77. if(typeof node[key] !== 'object'){
  78. current._e[key] = node[key];
  79. };
  80. switch (node.nodeName) {
  81. case 'body':
  82. current['node'] = 'root';
  83. break;
  84. case '#text':
  85. current['node'] = 'text';
  86. current['text'] = node.value;
  87. break;
  88. default:
  89. current['node'] = 'element';
  90. break;
  91. };
  92. };
  93. // 当前标签是audio的情况下
  94. if(node.tagName === 'audio'){
  95. current.tag = "view";
  96. current.attr = {};
  97. current.attr.class = 'audioForH2w';
  98. current._id = `audio_${+new Date()}_${(Math.random()+'').slice(2)}`;
  99. // // 用于保存播放器数据(小程序在setData完成之后,新的数据会重新占用内存空间,故此处保存没有必要)
  100. // if(appData){
  101. // appData.__audioData__ = appData.__audio__ || {};
  102. // appData.__audioData__[current._id] = current;
  103. // };
  104. // 创建播放器子元素
  105. current.child = [
  106. {
  107. node:"element",
  108. tag:"view",
  109. attr:{
  110. class:"h2w__view audioForH2w__icon"
  111. }
  112. },{
  113. node:"element",
  114. tag:"view",
  115. attr:{
  116. class:"h2w__view audioForH2w__cover"
  117. },
  118. child:[
  119. {
  120. node:"element",
  121. tag:"image",
  122. type:"audio",
  123. attr:{
  124. class:"h2w__img"
  125. }
  126. }
  127. ]
  128. },{
  129. node:"element",
  130. tag:"view",
  131. attr:{
  132. class:"h2w__view audioForH2w__info"
  133. },
  134. child:[
  135. {
  136. node:"element",
  137. tag:"view",
  138. attr:{
  139. class: "h2w__view audioForH2w__schedule",
  140. style: "width:0px;"
  141. }
  142. },{
  143. node:"element",
  144. tag:"view",
  145. attr:{
  146. class:"audioForH2w__title"
  147. },
  148. child:[
  149. {
  150. node:"text",
  151. text: "--",
  152. attr: {}
  153. }
  154. ]
  155. },{
  156. node:"element",
  157. tag:"view",
  158. attr:{
  159. class:"audioForH2w__author"
  160. },
  161. child:[
  162. {
  163. node:"text",
  164. text: "佚名",
  165. attr: {}
  166. }
  167. ]
  168. },{
  169. node:"element",
  170. tag:"view",
  171. attr:{
  172. class:"audioForH2w__time"
  173. },
  174. child:[
  175. {
  176. node:"text",
  177. text: "00:00:00 / 00:00:00",
  178. attr: {}
  179. }
  180. ]
  181. }
  182. ]
  183. }
  184. ];
  185. if(appData){
  186. // 得到音频选项
  187. let audioOption = ((node)=>{
  188. let option = {},
  189. nodeAttrs = node.attrs;
  190. for(let i=0,len=nodeAttrs.length; i<len; i++){
  191. let attrItem = nodeAttrs[i];
  192. option[attrItem.name] = attrItem.value;
  193. };
  194. return option;
  195. })(node);
  196. // 保存当前播放器数据
  197. global.__towxmldata__[_ts.id].audio[current._id] = current;
  198. //用于保存播放器对象
  199. appData.__audioObj__ = appData.__audioObj__ || {};
  200. appData.__audioObj__[current._id] = Audio({
  201. app:app, // 传入APP
  202. playerId:current._id, // 当前播放器ID
  203. dataId:_ts.id, // 数据ID
  204. option:audioOption // 传入音频选项
  205. });
  206. };
  207. }else if(node.tagName){
  208. current.tag = _ts.getTag(node.tagName);
  209. current.attr.class = current.attr.class ? `h2w__${node.tagName} ${current.attr.class}` : `h2w__${node.tagName}`;
  210. };
  211. arrange(node,current);
  212. };
  213. };
  214. })(bodyData,result);
  215. return result;
  216. }
  217. /**
  218. * 获取属于body那部分的数据
  219. */
  220. getBodyData(documentData){
  221. let data,
  222. getBody;
  223. (getBody = (list)=>{
  224. for(let i=0,len=list.length; i<len; i++){
  225. let item = list[i];
  226. if(item.nodeName === 'body' && item.tagName === 'body'){
  227. data = item;
  228. break;
  229. }else if (item.childNodes){
  230. getBody(item.childNodes);
  231. };
  232. }
  233. })(documentData.childNodes);
  234. return data;
  235. }
  236. /**
  237. * 得到转换对应的tag
  238. */
  239. getTag(tagName){
  240. let correspondTag = this.correspondTag(),
  241. wxmlTag = correspondTag[tagName] === undefined ? 'view' : correspondTag[tagName];
  242. return wxmlTag;
  243. }
  244. /**
  245. * 组织html与小程序的tag对应关系
  246. */
  247. correspondTag(){
  248. let data = {
  249. 'a':'navigator',
  250. 'img':'image',
  251. 'todogroup':'checkbox-group'
  252. };
  253. // 该系列的标签都转换为text
  254. ['span','b','strong','i','em','code','sub','sup','g-emoji','mark','ins'].forEach(item => {
  255. data[item] = 'text';
  256. });
  257. // 该系列是小程序原生tag,不需要转换
  258. tagsAndAttrs.wxml.forEach(item => {
  259. data[item] = item;
  260. });
  261. return data;
  262. }
  263. };
  264. module.exports = ToJson;