trees.vue 26 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004
  1. <<<<<<< HEAD
  2. <template>
  3. <view :class="'interlayer '+(c||'')" :style="s">
  4. <block v-for="(n, i) in nodes" v-bind:key="i">
  5. <!--图片-->
  6. <view v-if="n.name=='img'" :class="'_img '+n.attrs.class" :style="n.attrs.style" :data-attrs="n.attrs" @tap="imgtap">
  7. <rich-text v-if="ctrl[i]!=0" :nodes="[{attrs:{src:loading&&(ctrl[i]||0)<2?loading:(lazyLoad&&!ctrl[i]?placeholder:(ctrl[i]==3?errorImg:n.attrs.src||'')),alt:n.attrs.alt||'',width:n.attrs.width||'',style:'-webkit-touch-callout:none;max-width:100%;display:block'+(n.attrs.height?';height:'+n.attrs.height:'')},name:'img'}]" />
  8. <image class="_image" :src="lazyLoad&&!ctrl[i]?placeholder:n.attrs.src" :lazy-load="lazyLoad"
  9. :show-menu-by-longpress="!n.attrs.ignore" :data-i="i" :data-index="n.attrs.i" data-source="img" @load="loadImg"
  10. @error="error" />
  11. </view>
  12. <!--文本-->
  13. <text v-else-if="n.type=='text'" decode>{{n.text}}</text>
  14. <!--#ifndef MP-BAIDU-->
  15. <text v-else-if="n.name=='br'">\n</text>
  16. <!--#endif-->
  17. <!--视频-->
  18. <view v-else-if="((n.lazyLoad&&!n.attrs.autoplay)||(n.name=='video'&&!loadVideo))&&ctrl[i]==undefined" :id="n.attrs.id" :class="'_video '+(n.attrs.class||'')"
  19. :style="n.attrs.style" :data-i="i" @tap="_loadVideo" />
  20. <video v-else-if="n.name=='video'" :id="n.attrs.id" :class="n.attrs.class" :style="n.attrs.style" :autoplay="n.attrs.autoplay||ctrl[i]==0"
  21. :controls="n.attrs.controls" :loop="n.attrs.loop" :muted="n.attrs.muted" :poster="n.attrs.poster" :src="n.attrs.source[ctrl[i]||0]"
  22. :unit-id="n.attrs['unit-id']" :data-id="n.attrs.id" :data-i="i" data-source="video" @error="error" @play="play" />
  23. <!--音频-->
  24. <audio v-else-if="n.name=='audio'" :ref="n.attrs.id" :class="n.attrs.class" :style="n.attrs.style" :author="n.attrs.author"
  25. :autoplay="n.attrs.autoplay" :controls="n.attrs.controls" :loop="n.attrs.loop" :name="n.attrs.name" :poster="n.attrs.poster"
  26. :src="n.attrs.source[ctrl[i]||0]" :data-i="i" :data-id="n.attrs.id" data-source="audio"
  27. @error.native="error" @play.native="play" />
  28. <!--链接-->
  29. <view v-else-if="n.name=='a'" :id="n.attrs.id" :class="'_a '+(n.attrs.class||'')" hover-class="_hover" :style="n.attrs.style"
  30. :data-attrs="n.attrs" @tap="linkpress">
  31. <trees class="_span" c="_span" :nodes="n.children" />
  32. </view>
  33. <!--广告-->
  34. <!--<ad v-else-if="n.name=='ad'" :class="n.attrs.class" :style="n.attrs.style" :unit-id="n.attrs['unit-id']" :appid="n.attrs.appid" :apid="n.attrs.apid" :type="n.attrs.type" :adpid="n.attrs.adpid" data-source="ad" @error="error" />-->
  35. <!--列表-->
  36. <view v-else-if="n.name=='li'" :id="n.attrs.id" :class="n.attrs.class" :style="(n.attrs.style||'')+';display:flex;flex-direction:row'">
  37. <view v-if="n.type=='ol'" class="_ol-bef">{{n.num}}</view>
  38. <view v-else class="_ul-bef">
  39. <view v-if="n.floor%3==0" class="_ul-p1">█</view>
  40. <view v-else-if="n.floor%3==2" class="_ul-p2" />
  41. <view v-else class="_ul-p1" style="border-radius:50%">█</view>
  42. </view>
  43. <trees class="_li" c="_li" :nodes="n.children" :lazyLoad="lazyLoad" :loading="loading" />
  44. </view>
  45. <!--表格-->
  46. <view v-else-if="n.name=='table'&&n.c" :id="n.attrs.id" :class="n.attrs.class" :style="(n.attrs.style||'')+';display:table'">
  47. <view v-for="(tbody, o) in n.children" v-bind:key="o" :class="tbody.attrs.class" :style="(tbody.attrs.style||'')+(tbody.name[0]=='t'?';display:table-'+(tbody.name=='tr'?'row':'row-group'):'')">
  48. <view v-for="(tr, p) in tbody.children" v-bind:key="p" :class="tr.attrs.class" :style="(tr.attrs.style||'')+(tr.name[0]=='t'?';display:table-'+(tr.name=='tr'?'row':'cell'):'')">
  49. <trees v-if="tr.name=='td'" :nodes="tr.children" />
  50. <trees v-else v-for="(td, q) in tr.children" v-bind:key="q" :class="td.attrs.class" :c="td.attrs.class" :style="(td.attrs.style||'')+(td.name[0]=='t'?';display:table-'+(td.name=='tr'?'row':'cell'):'')"
  51. :s="(td.attrs.style||'')+(td.name[0]=='t'?';display:table-'+(td.name=='tr'?'row':'cell'):'')" :nodes="td.children" />
  52. </view>
  53. </view>
  54. </view>
  55. <!--#ifdef APP-PLUS-->
  56. <iframe v-else-if="n.name=='iframe'" :style="n.attrs.style" :allowfullscreen="n.attrs.allowfullscreen" :frameborder="n.attrs.frameborder"
  57. :width="n.attrs.width" :height="n.attrs.height" :src="n.attrs.src" />
  58. <embed v-else-if="n.name=='embed'" :style="n.attrs.style" :width="n.attrs.width" :height="n.attrs.height" :src="n.attrs.src" />
  59. <!--#endif-->
  60. <!--富文本-->
  61. <!--#ifdef MP-WEIXIN || MP-QQ || APP-PLUS-->
  62. <rich-text v-else-if="handler.use(n)" :id="n.attrs.id" :class="'_p __'+n.name" :nodes="[n]" />
  63. <!--#endif-->
  64. <!--#ifndef MP-WEIXIN || MP-QQ || APP-PLUS-->
  65. <rich-text v-else-if="!n.c" :id="n.attrs.id" :nodes="[n]" style="display:inline" />
  66. <!--#endif-->
  67. <trees v-else :class="(n.attrs.id||'')+' _'+n.name+' '+(n.attrs.class||'')" :c="(n.attrs.id||'')+' _'+n.name+' '+(n.attrs.class||'')"
  68. :style="n.attrs.style" :s="n.attrs.style" :nodes="n.children" :lazyLoad="lazyLoad" :loading="loading" />
  69. </block>
  70. </view>
  71. </template>
  72. <script module="handler" lang="wxs" src="./handler.wxs"></script>
  73. <script>
  74. global.Parser = {};
  75. import trees from './trees'
  76. const errorImg = require('../libs/config.js').errorImg;
  77. export default {
  78. components: {
  79. trees
  80. },
  81. name: 'trees',
  82. data() {
  83. return {
  84. ctrl: [],
  85. placeholder: 'data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="300" height="225"/>',
  86. errorImg,
  87. loadVideo: typeof plus == 'undefined',
  88. // #ifndef MP-ALIPAY
  89. c: '',
  90. s: ''
  91. // #endif
  92. }
  93. },
  94. props: {
  95. nodes: Array,
  96. lazyLoad: Boolean,
  97. loading: String,
  98. // #ifdef MP-ALIPAY
  99. c: String,
  100. s: String
  101. // #endif
  102. },
  103. mounted() {
  104. for (this.top = this.$parent; this.top.$options.name != 'parser'; this.top = this.top.$parent);
  105. this.init();
  106. },
  107. // #ifdef APP-PLUS
  108. beforeDestroy() {
  109. this.observer && this.observer.disconnect();
  110. },
  111. // #endif
  112. methods: {
  113. init() {
  114. for (var i = this.nodes.length, n; n = this.nodes[--i];) {
  115. if (n.name == 'img') {
  116. this.top.imgList.setItem(n.attrs.i, n.attrs.src);
  117. // #ifdef APP-PLUS
  118. if (this.lazyLoad && !this.observer) {
  119. this.observer = uni.createIntersectionObserver(this).relativeToViewport({
  120. top: 500,
  121. bottom: 500
  122. });
  123. setTimeout(() => {
  124. this.observer.observe('._img', res => {
  125. if (res.intersectionRatio) {
  126. for (var j = this.nodes.length; j--;)
  127. if (this.nodes[j].name == 'img')
  128. this.$set(this.ctrl, j, 1);
  129. this.observer.disconnect();
  130. }
  131. })
  132. }, 0)
  133. }
  134. // #endif
  135. } else if (n.name == 'video' || n.name == 'audio') {
  136. var ctx;
  137. if (n.name == 'video') {
  138. ctx = uni.createVideoContext(n.attrs.id
  139. // #ifndef MP-BAIDU
  140. , this
  141. // #endif
  142. );
  143. } else if (this.$refs[n.attrs.id])
  144. ctx = this.$refs[n.attrs.id][0];
  145. if (ctx) {
  146. ctx.id = n.attrs.id;
  147. this.top.videoContexts.push(ctx);
  148. }
  149. }
  150. }
  151. // #ifdef APP-PLUS
  152. // APP 上避免 video 错位需要延时渲染
  153. setTimeout(() => {
  154. this.loadVideo = true;
  155. }, 1000)
  156. // #endif
  157. },
  158. play(e) {
  159. var contexts = this.top.videoContexts;
  160. if (contexts.length > 1 && this.top.autopause)
  161. for (var i = contexts.length; i--;)
  162. if (contexts[i].id != e.currentTarget.dataset.id)
  163. contexts[i].pause();
  164. },
  165. imgtap(e) {
  166. var attrs = e.currentTarget.dataset.attrs;
  167. if (!attrs.ignore) {
  168. var preview = true,
  169. data = {
  170. id: e.target.id,
  171. src: attrs.src,
  172. ignore: () => preview = false
  173. };
  174. global.Parser.onImgtap && global.Parser.onImgtap(data);
  175. this.top.$emit('imgtap', data);
  176. if (preview) {
  177. var urls = this.top.imgList,
  178. current = urls[attrs.i] ? parseInt(attrs.i) : (urls = [attrs.src], 0);
  179. uni.previewImage({
  180. current,
  181. urls
  182. })
  183. }
  184. }
  185. },
  186. loadImg(e) {
  187. var i = e.currentTarget.dataset.i;
  188. if (this.lazyLoad && !this.ctrl[i]) {
  189. // #ifdef QUICKAPP-WEBVIEW
  190. this.$set(this.ctrl, i, 0);
  191. this.$nextTick(function() {
  192. // #endif
  193. // #ifndef APP-PLUS
  194. this.$set(this.ctrl, i, 1);
  195. // #endif
  196. // #ifdef QUICKAPP-WEBVIEW
  197. })
  198. // #endif
  199. } else if (this.loading && this.ctrl[i] != 2) {
  200. // #ifdef QUICKAPP-WEBVIEW
  201. this.$set(this.ctrl, i, 0);
  202. this.$nextTick(function() {
  203. // #endif
  204. this.$set(this.ctrl, i, 2);
  205. // #ifdef QUICKAPP-WEBVIEW
  206. })
  207. // #endif
  208. }
  209. },
  210. linkpress(e) {
  211. var jump = true,
  212. attrs = e.currentTarget.dataset.attrs;
  213. attrs.ignore = () => jump = false;
  214. global.Parser.onLinkpress && global.Parser.onLinkpress(attrs);
  215. this.top.$emit('linkpress', attrs);
  216. if (jump) {
  217. // #ifdef MP
  218. if (attrs['app-id']) {
  219. return uni.navigateToMiniProgram({
  220. appId: attrs['app-id'],
  221. path: attrs.path
  222. })
  223. }
  224. // #endif
  225. if (attrs.href) {
  226. if (attrs.href[0] == '#') {
  227. if (this.top.useAnchor)
  228. this.top.navigateTo({
  229. id: attrs.href.substring(1)
  230. })
  231. } else if (attrs.href.indexOf('http') == 0 || attrs.href.indexOf('//') == 0) {
  232. // #ifdef APP-PLUS
  233. plus.runtime.openWeb(attrs.href);
  234. // #endif
  235. // #ifndef APP-PLUS
  236. uni.setClipboardData({
  237. data: attrs.href,
  238. success: () =>
  239. uni.showToast({
  240. title: '链接已复制'
  241. })
  242. })
  243. // #endif
  244. } else
  245. uni.navigateTo({
  246. url: attrs.href,
  247. fail() {
  248. uni.switchTab({
  249. url: attrs.href,
  250. })
  251. }
  252. })
  253. }
  254. }
  255. },
  256. error(e) {
  257. var target = e.currentTarget,
  258. source = target.dataset.source,
  259. i = target.dataset.i;
  260. if (source == 'video' || source == 'audio') {
  261. // 加载其他 source
  262. var index = this.ctrl[i] ? this.ctrl[i].i + 1 : 1;
  263. if (index < this.nodes[i].attrs.source.length)
  264. this.$set(this.ctrl, i, index);
  265. if (e.detail.__args__)
  266. e.detail = e.detail.__args__[0];
  267. } else if (errorImg && source == 'img') {
  268. this.top.imgList.setItem(target.dataset.index, errorImg);
  269. this.$set(this.ctrl, i, 3);
  270. }
  271. this.top && this.top.$emit('error', {
  272. source,
  273. target,
  274. errMsg: e.detail.errMsg
  275. });
  276. },
  277. _loadVideo(e) {
  278. this.$set(this.ctrl, e.target.dataset.i, 0);
  279. }
  280. }
  281. }
  282. </script>
  283. <style>
  284. /* 在这里引入自定义样式 */
  285. /* 链接和图片效果 */
  286. ._a {
  287. display: inline;
  288. padding: 1.5px 0 1.5px 0;
  289. color: #366092;
  290. word-break: break-all;
  291. }
  292. ._hover {
  293. text-decoration: underline;
  294. opacity: 0.7;
  295. }
  296. ._img {
  297. display: inline-block;
  298. max-width: 100%;
  299. overflow: hidden;
  300. }
  301. /* #ifdef MP-WEIXIN */
  302. :host {
  303. display: inline;
  304. }
  305. /* #endif */
  306. /* #ifndef MP-ALIPAY || APP-PLUS */
  307. .interlayer {
  308. display: inherit;
  309. flex-direction: inherit;
  310. flex-wrap: inherit;
  311. align-content: inherit;
  312. align-items: inherit;
  313. justify-content: inherit;
  314. width: 100%;
  315. white-space: inherit;
  316. }
  317. /* #endif */
  318. ._b,
  319. ._strong {
  320. font-weight: bold;
  321. }
  322. /* #ifndef MP-ALIPAY */
  323. ._blockquote,
  324. ._div,
  325. ._p,
  326. ._ol,
  327. ._ul,
  328. ._li {
  329. display: block;
  330. }
  331. /* #endif */
  332. ._code {
  333. font-family: monospace;
  334. }
  335. ._del {
  336. text-decoration: line-through;
  337. }
  338. ._em,
  339. ._i {
  340. font-style: italic;
  341. }
  342. ._h1 {
  343. font-size: 2em;
  344. }
  345. ._h2 {
  346. font-size: 1.5em;
  347. }
  348. ._h3 {
  349. font-size: 1.17em;
  350. }
  351. ._h5 {
  352. font-size: 0.83em;
  353. }
  354. ._h6 {
  355. font-size: 0.67em;
  356. }
  357. ._h1,
  358. ._h2,
  359. ._h3,
  360. ._h4,
  361. ._h5,
  362. ._h6 {
  363. display: block;
  364. font-weight: bold;
  365. }
  366. ._image {
  367. display: block;
  368. width: 100%;
  369. height: 360px;
  370. margin-top: -360px;
  371. opacity: 0;
  372. }
  373. ._ins {
  374. text-decoration: underline;
  375. }
  376. ._li {
  377. flex: 1;
  378. width: 0;
  379. }
  380. ._ol-bef {
  381. width: 36px;
  382. margin-right: 5px;
  383. text-align: right;
  384. }
  385. ._ul-bef {
  386. display: block;
  387. margin: 0 12px 0 23px;
  388. line-height: normal;
  389. }
  390. ._ol-bef,
  391. ._ul-bef {
  392. flex: none;
  393. user-select: none;
  394. }
  395. ._ul-p1 {
  396. display: inline-block;
  397. width: 0.3em;
  398. height: 0.3em;
  399. overflow: hidden;
  400. line-height: 0.3em;
  401. }
  402. ._ul-p2 {
  403. display: inline-block;
  404. width: 0.23em;
  405. height: 0.23em;
  406. border: 0.05em solid black;
  407. border-radius: 50%;
  408. }
  409. ._q::before {
  410. content: '"';
  411. }
  412. ._q::after {
  413. content: '"';
  414. }
  415. ._sub {
  416. font-size: smaller;
  417. vertical-align: sub;
  418. }
  419. ._sup {
  420. font-size: smaller;
  421. vertical-align: super;
  422. }
  423. /* #ifdef MP-ALIPAY || APP-PLUS || QUICKAPP-WEBVIEW */
  424. ._abbr,
  425. ._b,
  426. ._code,
  427. ._del,
  428. ._em,
  429. ._i,
  430. ._ins,
  431. ._label,
  432. ._q,
  433. ._span,
  434. ._strong,
  435. ._sub,
  436. ._sup {
  437. display: inline;
  438. }
  439. /* #endif */
  440. /* #ifdef MP-WEIXIN || MP-QQ */
  441. .__bdo,
  442. .__bdi,
  443. .__ruby,
  444. .__rt {
  445. display: inline-block;
  446. }
  447. /* #endif */
  448. ._video {
  449. position: relative;
  450. display: inline-block;
  451. width: 300px;
  452. height: 225px;
  453. background-color: black;
  454. }
  455. ._video::after {
  456. position: absolute;
  457. top: 50%;
  458. left: 50%;
  459. margin: -15px 0 0 -15px;
  460. content: '';
  461. border-color: transparent transparent transparent white;
  462. border-style: solid;
  463. border-width: 15px 0 15px 30px;
  464. }
  465. =======
  466. <template>
  467. <view :class="'interlayer '+(c||'')" :style="s">
  468. <block v-for="(n, i) in nodes" v-bind:key="i">
  469. <!--图片-->
  470. <view v-if="n.name=='img'" :class="'_img '+n.attrs.class" :style="n.attrs.style" :data-attrs="n.attrs" @tap="imgtap">
  471. <rich-text v-if="ctrl[i]!=0" :nodes="[{attrs:{src:loading&&(ctrl[i]||0)<2?loading:(lazyLoad&&!ctrl[i]?placeholder:(ctrl[i]==3?errorImg:n.attrs.src||'')),alt:n.attrs.alt||'',width:n.attrs.width||'',style:'-webkit-touch-callout:none;max-width:100%;display:block'+(n.attrs.height?';height:'+n.attrs.height:'')},name:'img'}]" />
  472. <image class="_image" :src="lazyLoad&&!ctrl[i]?placeholder:n.attrs.src" :lazy-load="lazyLoad"
  473. :show-menu-by-longpress="!n.attrs.ignore" :data-i="i" :data-index="n.attrs.i" data-source="img" @load="loadImg"
  474. @error="error" />
  475. </view>
  476. <!--文本-->
  477. <text v-else-if="n.type=='text'" decode>{{n.text}}</text>
  478. <!--#ifndef MP-BAIDU-->
  479. <text v-else-if="n.name=='br'">\n</text>
  480. <!--#endif-->
  481. <!--视频-->
  482. <view v-else-if="((n.lazyLoad&&!n.attrs.autoplay)||(n.name=='video'&&!loadVideo))&&ctrl[i]==undefined" :id="n.attrs.id" :class="'_video '+(n.attrs.class||'')"
  483. :style="n.attrs.style" :data-i="i" @tap="_loadVideo" />
  484. <video v-else-if="n.name=='video'" :id="n.attrs.id" :class="n.attrs.class" :style="n.attrs.style" :autoplay="n.attrs.autoplay||ctrl[i]==0"
  485. :controls="n.attrs.controls" :loop="n.attrs.loop" :muted="n.attrs.muted" :poster="n.attrs.poster" :src="n.attrs.source[ctrl[i]||0]"
  486. :unit-id="n.attrs['unit-id']" :data-id="n.attrs.id" :data-i="i" data-source="video" @error="error" @play="play" />
  487. <!--音频-->
  488. <audio v-else-if="n.name=='audio'" :ref="n.attrs.id" :class="n.attrs.class" :style="n.attrs.style" :author="n.attrs.author"
  489. :autoplay="n.attrs.autoplay" :controls="n.attrs.controls" :loop="n.attrs.loop" :name="n.attrs.name" :poster="n.attrs.poster"
  490. :src="n.attrs.source[ctrl[i]||0]" :data-i="i" :data-id="n.attrs.id" data-source="audio"
  491. @error.native="error" @play.native="play" />
  492. <!--链接-->
  493. <view v-else-if="n.name=='a'" :id="n.attrs.id" :class="'_a '+(n.attrs.class||'')" hover-class="_hover" :style="n.attrs.style"
  494. :data-attrs="n.attrs" @tap="linkpress">
  495. <trees class="_span" c="_span" :nodes="n.children" />
  496. </view>
  497. <!--广告-->
  498. <!--<ad v-else-if="n.name=='ad'" :class="n.attrs.class" :style="n.attrs.style" :unit-id="n.attrs['unit-id']" :appid="n.attrs.appid" :apid="n.attrs.apid" :type="n.attrs.type" :adpid="n.attrs.adpid" data-source="ad" @error="error" />-->
  499. <!--列表-->
  500. <view v-else-if="n.name=='li'" :id="n.attrs.id" :class="n.attrs.class" :style="(n.attrs.style||'')+';display:flex;flex-direction:row'">
  501. <view v-if="n.type=='ol'" class="_ol-bef">{{n.num}}</view>
  502. <view v-else class="_ul-bef">
  503. <view v-if="n.floor%3==0" class="_ul-p1">█</view>
  504. <view v-else-if="n.floor%3==2" class="_ul-p2" />
  505. <view v-else class="_ul-p1" style="border-radius:50%">█</view>
  506. </view>
  507. <trees class="_li" c="_li" :nodes="n.children" :lazyLoad="lazyLoad" :loading="loading" />
  508. </view>
  509. <!--表格-->
  510. <view v-else-if="n.name=='table'&&n.c" :id="n.attrs.id" :class="n.attrs.class" :style="(n.attrs.style||'')+';display:table'">
  511. <view v-for="(tbody, o) in n.children" v-bind:key="o" :class="tbody.attrs.class" :style="(tbody.attrs.style||'')+(tbody.name[0]=='t'?';display:table-'+(tbody.name=='tr'?'row':'row-group'):'')">
  512. <view v-for="(tr, p) in tbody.children" v-bind:key="p" :class="tr.attrs.class" :style="(tr.attrs.style||'')+(tr.name[0]=='t'?';display:table-'+(tr.name=='tr'?'row':'cell'):'')">
  513. <trees v-if="tr.name=='td'" :nodes="tr.children" />
  514. <trees v-else v-for="(td, q) in tr.children" v-bind:key="q" :class="td.attrs.class" :c="td.attrs.class" :style="(td.attrs.style||'')+(td.name[0]=='t'?';display:table-'+(td.name=='tr'?'row':'cell'):'')"
  515. :s="(td.attrs.style||'')+(td.name[0]=='t'?';display:table-'+(td.name=='tr'?'row':'cell'):'')" :nodes="td.children" />
  516. </view>
  517. </view>
  518. </view>
  519. <!--#ifdef APP-PLUS-->
  520. <iframe v-else-if="n.name=='iframe'" :style="n.attrs.style" :allowfullscreen="n.attrs.allowfullscreen" :frameborder="n.attrs.frameborder"
  521. :width="n.attrs.width" :height="n.attrs.height" :src="n.attrs.src" />
  522. <embed v-else-if="n.name=='embed'" :style="n.attrs.style" :width="n.attrs.width" :height="n.attrs.height" :src="n.attrs.src" />
  523. <!--#endif-->
  524. <!--富文本-->
  525. <!--#ifdef MP-WEIXIN || MP-QQ || APP-PLUS-->
  526. <rich-text v-else-if="handler.use(n)" :id="n.attrs.id" :class="'_p __'+n.name" :nodes="[n]" />
  527. <!--#endif-->
  528. <!--#ifndef MP-WEIXIN || MP-QQ || APP-PLUS-->
  529. <rich-text v-else-if="!n.c" :id="n.attrs.id" :nodes="[n]" style="display:inline" />
  530. <!--#endif-->
  531. <trees v-else :class="(n.attrs.id||'')+' _'+n.name+' '+(n.attrs.class||'')" :c="(n.attrs.id||'')+' _'+n.name+' '+(n.attrs.class||'')"
  532. :style="n.attrs.style" :s="n.attrs.style" :nodes="n.children" :lazyLoad="lazyLoad" :loading="loading" />
  533. </block>
  534. </view>
  535. </template>
  536. <script module="handler" lang="wxs" src="./handler.wxs"></script>
  537. <script>
  538. global.Parser = {};
  539. import trees from './trees'
  540. const errorImg = require('../libs/config.js').errorImg;
  541. export default {
  542. components: {
  543. trees
  544. },
  545. name: 'trees',
  546. data() {
  547. return {
  548. ctrl: [],
  549. placeholder: 'data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="300" height="225"/>',
  550. errorImg,
  551. loadVideo: typeof plus == 'undefined',
  552. // #ifndef MP-ALIPAY
  553. c: '',
  554. s: ''
  555. // #endif
  556. }
  557. },
  558. props: {
  559. nodes: Array,
  560. lazyLoad: Boolean,
  561. loading: String,
  562. // #ifdef MP-ALIPAY
  563. c: String,
  564. s: String
  565. // #endif
  566. },
  567. mounted() {
  568. for (this.top = this.$parent; this.top.$options.name != 'parser'; this.top = this.top.$parent);
  569. this.init();
  570. },
  571. // #ifdef APP-PLUS
  572. beforeDestroy() {
  573. this.observer && this.observer.disconnect();
  574. },
  575. // #endif
  576. methods: {
  577. init() {
  578. for (var i = this.nodes.length, n; n = this.nodes[--i];) {
  579. if (n.name == 'img') {
  580. this.top.imgList.setItem(n.attrs.i, n.attrs.src);
  581. // #ifdef APP-PLUS
  582. if (this.lazyLoad && !this.observer) {
  583. this.observer = uni.createIntersectionObserver(this).relativeToViewport({
  584. top: 500,
  585. bottom: 500
  586. });
  587. setTimeout(() => {
  588. this.observer.observe('._img', res => {
  589. if (res.intersectionRatio) {
  590. for (var j = this.nodes.length; j--;)
  591. if (this.nodes[j].name == 'img')
  592. this.$set(this.ctrl, j, 1);
  593. this.observer.disconnect();
  594. }
  595. })
  596. }, 0)
  597. }
  598. // #endif
  599. } else if (n.name == 'video' || n.name == 'audio') {
  600. var ctx;
  601. if (n.name == 'video') {
  602. ctx = uni.createVideoContext(n.attrs.id
  603. // #ifndef MP-BAIDU
  604. , this
  605. // #endif
  606. );
  607. } else if (this.$refs[n.attrs.id])
  608. ctx = this.$refs[n.attrs.id][0];
  609. if (ctx) {
  610. ctx.id = n.attrs.id;
  611. this.top.videoContexts.push(ctx);
  612. }
  613. }
  614. }
  615. // #ifdef APP-PLUS
  616. // APP 上避免 video 错位需要延时渲染
  617. setTimeout(() => {
  618. this.loadVideo = true;
  619. }, 1000)
  620. // #endif
  621. },
  622. play(e) {
  623. var contexts = this.top.videoContexts;
  624. if (contexts.length > 1 && this.top.autopause)
  625. for (var i = contexts.length; i--;)
  626. if (contexts[i].id != e.currentTarget.dataset.id)
  627. contexts[i].pause();
  628. },
  629. imgtap(e) {
  630. var attrs = e.currentTarget.dataset.attrs;
  631. if (!attrs.ignore) {
  632. var preview = true,
  633. data = {
  634. id: e.target.id,
  635. src: attrs.src,
  636. ignore: () => preview = false
  637. };
  638. global.Parser.onImgtap && global.Parser.onImgtap(data);
  639. this.top.$emit('imgtap', data);
  640. if (preview) {
  641. var urls = this.top.imgList,
  642. current = urls[attrs.i] ? parseInt(attrs.i) : (urls = [attrs.src], 0);
  643. uni.previewImage({
  644. current,
  645. urls
  646. })
  647. }
  648. }
  649. },
  650. loadImg(e) {
  651. var i = e.currentTarget.dataset.i;
  652. if (this.lazyLoad && !this.ctrl[i]) {
  653. // #ifdef QUICKAPP-WEBVIEW
  654. this.$set(this.ctrl, i, 0);
  655. this.$nextTick(function() {
  656. // #endif
  657. // #ifndef APP-PLUS
  658. this.$set(this.ctrl, i, 1);
  659. // #endif
  660. // #ifdef QUICKAPP-WEBVIEW
  661. })
  662. // #endif
  663. } else if (this.loading && this.ctrl[i] != 2) {
  664. // #ifdef QUICKAPP-WEBVIEW
  665. this.$set(this.ctrl, i, 0);
  666. this.$nextTick(function() {
  667. // #endif
  668. this.$set(this.ctrl, i, 2);
  669. // #ifdef QUICKAPP-WEBVIEW
  670. })
  671. // #endif
  672. }
  673. },
  674. linkpress(e) {
  675. var jump = true,
  676. attrs = e.currentTarget.dataset.attrs;
  677. attrs.ignore = () => jump = false;
  678. global.Parser.onLinkpress && global.Parser.onLinkpress(attrs);
  679. this.top.$emit('linkpress', attrs);
  680. if (jump) {
  681. // #ifdef MP
  682. if (attrs['app-id']) {
  683. return uni.navigateToMiniProgram({
  684. appId: attrs['app-id'],
  685. path: attrs.path
  686. })
  687. }
  688. // #endif
  689. if (attrs.href) {
  690. if (attrs.href[0] == '#') {
  691. if (this.top.useAnchor)
  692. this.top.navigateTo({
  693. id: attrs.href.substring(1)
  694. })
  695. } else if (attrs.href.indexOf('http') == 0 || attrs.href.indexOf('//') == 0) {
  696. // #ifdef APP-PLUS
  697. plus.runtime.openWeb(attrs.href);
  698. // #endif
  699. // #ifndef APP-PLUS
  700. uni.setClipboardData({
  701. data: attrs.href,
  702. success: () =>
  703. uni.showToast({
  704. title: '链接已复制'
  705. })
  706. })
  707. // #endif
  708. } else
  709. uni.navigateTo({
  710. url: attrs.href,
  711. fail() {
  712. uni.switchTab({
  713. url: attrs.href,
  714. })
  715. }
  716. })
  717. }
  718. }
  719. },
  720. error(e) {
  721. var target = e.currentTarget,
  722. source = target.dataset.source,
  723. i = target.dataset.i;
  724. if (source == 'video' || source == 'audio') {
  725. // 加载其他 source
  726. var index = this.ctrl[i] ? this.ctrl[i].i + 1 : 1;
  727. if (index < this.nodes[i].attrs.source.length)
  728. this.$set(this.ctrl, i, index);
  729. if (e.detail.__args__)
  730. e.detail = e.detail.__args__[0];
  731. } else if (errorImg && source == 'img') {
  732. this.top.imgList.setItem(target.dataset.index, errorImg);
  733. this.$set(this.ctrl, i, 3);
  734. }
  735. this.top && this.top.$emit('error', {
  736. source,
  737. target,
  738. errMsg: e.detail.errMsg
  739. });
  740. },
  741. _loadVideo(e) {
  742. this.$set(this.ctrl, e.target.dataset.i, 0);
  743. }
  744. }
  745. }
  746. </script>
  747. <style>
  748. /* 在这里引入自定义样式 */
  749. /* 链接和图片效果 */
  750. ._a {
  751. display: inline;
  752. padding: 1.5px 0 1.5px 0;
  753. color: #366092;
  754. word-break: break-all;
  755. }
  756. ._hover {
  757. text-decoration: underline;
  758. opacity: 0.7;
  759. }
  760. ._img {
  761. display: inline-block;
  762. max-width: 100%;
  763. overflow: hidden;
  764. }
  765. /* #ifdef MP-WEIXIN */
  766. :host {
  767. display: inline;
  768. }
  769. /* #endif */
  770. /* #ifndef MP-ALIPAY || APP-PLUS */
  771. .interlayer {
  772. display: inherit;
  773. flex-direction: inherit;
  774. flex-wrap: inherit;
  775. align-content: inherit;
  776. align-items: inherit;
  777. justify-content: inherit;
  778. width: 100%;
  779. white-space: inherit;
  780. }
  781. /* #endif */
  782. ._b,
  783. ._strong {
  784. font-weight: bold;
  785. }
  786. /* #ifndef MP-ALIPAY */
  787. ._blockquote,
  788. ._div,
  789. ._p,
  790. ._ol,
  791. ._ul,
  792. ._li {
  793. display: block;
  794. }
  795. /* #endif */
  796. ._code {
  797. font-family: monospace;
  798. }
  799. ._del {
  800. text-decoration: line-through;
  801. }
  802. ._em,
  803. ._i {
  804. font-style: italic;
  805. }
  806. ._h1 {
  807. font-size: 2em;
  808. }
  809. ._h2 {
  810. font-size: 1.5em;
  811. }
  812. ._h3 {
  813. font-size: 1.17em;
  814. }
  815. ._h5 {
  816. font-size: 0.83em;
  817. }
  818. ._h6 {
  819. font-size: 0.67em;
  820. }
  821. ._h1,
  822. ._h2,
  823. ._h3,
  824. ._h4,
  825. ._h5,
  826. ._h6 {
  827. display: block;
  828. font-weight: bold;
  829. }
  830. ._image {
  831. display: block;
  832. width: 100%;
  833. height: 360px;
  834. margin-top: -360px;
  835. opacity: 0;
  836. }
  837. ._ins {
  838. text-decoration: underline;
  839. }
  840. ._li {
  841. flex: 1;
  842. width: 0;
  843. }
  844. ._ol-bef {
  845. width: 36px;
  846. margin-right: 5px;
  847. text-align: right;
  848. }
  849. ._ul-bef {
  850. display: block;
  851. margin: 0 12px 0 23px;
  852. line-height: normal;
  853. }
  854. ._ol-bef,
  855. ._ul-bef {
  856. flex: none;
  857. user-select: none;
  858. }
  859. ._ul-p1 {
  860. display: inline-block;
  861. width: 0.3em;
  862. height: 0.3em;
  863. overflow: hidden;
  864. line-height: 0.3em;
  865. }
  866. ._ul-p2 {
  867. display: inline-block;
  868. width: 0.23em;
  869. height: 0.23em;
  870. border: 0.05em solid black;
  871. border-radius: 50%;
  872. }
  873. ._q::before {
  874. content: '"';
  875. }
  876. ._q::after {
  877. content: '"';
  878. }
  879. ._sub {
  880. font-size: smaller;
  881. vertical-align: sub;
  882. }
  883. ._sup {
  884. font-size: smaller;
  885. vertical-align: super;
  886. }
  887. /* #ifdef MP-ALIPAY || APP-PLUS || QUICKAPP-WEBVIEW */
  888. ._abbr,
  889. ._b,
  890. ._code,
  891. ._del,
  892. ._em,
  893. ._i,
  894. ._ins,
  895. ._label,
  896. ._q,
  897. ._span,
  898. ._strong,
  899. ._sub,
  900. ._sup {
  901. display: inline;
  902. }
  903. /* #endif */
  904. /* #ifdef MP-WEIXIN || MP-QQ */
  905. .__bdo,
  906. .__bdi,
  907. .__ruby,
  908. .__rt {
  909. display: inline-block;
  910. }
  911. /* #endif */
  912. ._video {
  913. position: relative;
  914. display: inline-block;
  915. width: 300px;
  916. height: 225px;
  917. background-color: black;
  918. }
  919. ._video::after {
  920. position: absolute;
  921. top: 50%;
  922. left: 50%;
  923. margin: -15px 0 0 -15px;
  924. content: '';
  925. border-color: transparent transparent transparent white;
  926. border-style: solid;
  927. border-width: 15px 0 15px 30px;
  928. }
  929. >>>>>>> 5b465a14bac2c1448cc18a0b08b88844fc895cd5
  930. </style>