|
|
<template> <view :class="'interlayer '+(c||'')" :style="s"> <block v-for="(n, i) in nodes" v-bind:key="i"> <!--图片--> <view v-if="n.name=='img'" :class="'_img '+n.attrs.class" :style="n.attrs.style" :data-attrs="n.attrs" @tap.stop="imgtap"> <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'}]" /> <image class="_image" :src="lazyLoad&&!ctrl[i]?placeholder:n.attrs.src" :lazy-load="lazyLoad" :show-menu-by-longpress="!n.attrs.ignore" :data-i="i" :data-index="n.attrs.i" data-source="img" @load="loadImg" @error="error" /> </view> <!--文本--> <text v-else-if="n.type=='text'" decode>{{n.text}}</text> <!--#ifndef MP-BAIDU--> <text v-else-if="n.name=='br'">\n</text> <!--#endif--> <!--视频--> <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||'')" :style="n.attrs.style" :data-i="i" @tap.stop="_loadVideo" /> <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" :controls="n.attrs.controls" :loop="n.attrs.loop" :muted="n.attrs.muted" :poster="n.attrs.poster" :src="n.attrs.source[ctrl[i]||0]" :unit-id="n.attrs['unit-id']" :data-id="n.attrs.id" :data-i="i" data-source="video" @error="error" @play="play" /> <!--音频--> <audio v-else-if="n.name=='audio'" :ref="n.attrs.id" :class="n.attrs.class" :style="n.attrs.style" :author="n.attrs.author" :autoplay="n.attrs.autoplay" :controls="n.attrs.controls" :loop="n.attrs.loop" :name="n.attrs.name" :poster="n.attrs.poster" :src="n.attrs.source[ctrl[i]||0]" :data-i="i" :data-id="n.attrs.id" data-source="audio" @error.native="error" @play.native="play" /> <!--链接--> <view v-else-if="n.name=='a'" :id="n.attrs.id" :class="'_a '+(n.attrs.class||'')" hover-class="_hover" :style="n.attrs.style" :data-attrs="n.attrs" @tap.stop="linkpress"> <trees class="_span" c="_span" :nodes="n.children" /> </view> <!--广告--> <!--<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" />--> <!--列表--> <view v-else-if="n.name=='li'" :id="n.attrs.id" :class="n.attrs.class" :style="(n.attrs.style||'')+';display:flex;flex-direction:row'"> <view v-if="n.type=='ol'" class="_ol-bef">{{n.num}}</view> <view v-else class="_ul-bef"> <view v-if="n.floor%3==0" class="_ul-p1">█</view> <view v-else-if="n.floor%3==2" class="_ul-p2" /> <view v-else class="_ul-p1" style="border-radius:50%">█</view> </view> <trees class="_li" c="_li" :nodes="n.children" :lazyLoad="lazyLoad" :loading="loading" /> </view> <!--表格--> <view v-else-if="n.name=='table'&&n.c&&n.flag" :id="n.attrs.id" :class="n.attrs.class" :style="(n.attrs.style||'')+';display:grid'"> <trees v-for="(cell,n) in n.children" v-bind:key="n" :class="cell.attrs.class" :c="cell.attrs.class" :style="cell.attrs.style" :s="cell.attrs.style" :nodes="cell.children" /> </view> <view v-else-if="n.name=='table'&&n.c" :id="n.attrs.id" :class="n.attrs.class" :style="(n.attrs.style||'')+';display:table'"> <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'):'')"> <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'):'')"> <trees v-if="tr.name=='td'" :nodes="tr.children" /> <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'):'')" :s="(td.attrs.style||'')+(td.name[0]=='t'?';display:table-'+(td.name=='tr'?'row':'cell'):'')" :nodes="td.children" /> </view> </view> </view> <!--#ifdef APP-PLUS--> <iframe v-else-if="n.name=='iframe'" :style="n.attrs.style" :allowfullscreen="n.attrs.allowfullscreen" :frameborder="n.attrs.frameborder" :width="n.attrs.width" :height="n.attrs.height" :src="n.attrs.src" /> <embed v-else-if="n.name=='embed'" :style="n.attrs.style" :width="n.attrs.width" :height="n.attrs.height" :src="n.attrs.src" /> <!--#endif--> <!--富文本--> <!--#ifdef MP-WEIXIN || MP-QQ || APP-PLUS--> <rich-text v-else-if="handler.use(n)" :id="n.attrs.id" :class="'_p __'+n.name" :nodes="[n]" /> <!--#endif--> <!--#ifndef MP-WEIXIN || MP-QQ || APP-PLUS--> <rich-text v-else-if="!n.c" :id="n.attrs.id" :nodes="[n]" style="display:inline" /> <!--#endif--> <trees v-else :class="(n.attrs.id||'')+' _'+n.name+' '+(n.attrs.class||'')" :c="(n.attrs.id||'')+' _'+n.name+' '+(n.attrs.class||'')" :style="n.attrs.style" :s="n.attrs.style" :nodes="n.children" :lazyLoad="lazyLoad" :loading="loading" /> </block> </view> </template> <script module="handler" lang="wxs" src="./handler.wxs"></script> <script> global.Parser = {}; import trees from './trees' const errorImg = require('../libs/config.js').errorImg; export default { components: { trees }, name: 'trees', data() { return { ctrl: [], placeholder: 'data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="300" height="225"/>', errorImg, loadVideo: typeof plus == 'undefined', // #ifndef MP-ALIPAY
c: '', s: '' // #endif
} }, props: { nodes: Array, lazyLoad: Boolean, loading: String, // #ifdef MP-ALIPAY
c: String, s: String // #endif
}, mounted() { for (this.top = this.$parent; this.top.$options.name != 'parser'; this.top = this.top.$parent); this.init(); }, // #ifdef APP-PLUS
beforeDestroy() { this.observer && this.observer.disconnect(); }, // #endif
methods: { init() { for (var i = this.nodes.length, n; n = this.nodes[--i];) { if (n.name == 'img') { this.top.imgList.setItem(n.attrs.i, n.attrs['original-src'] || n.attrs.src); // #ifdef APP-PLUS
if (this.lazyLoad && !this.observer) { this.observer = uni.createIntersectionObserver(this).relativeToViewport({ top: 500, bottom: 500 }); setTimeout(() => { this.observer.observe('._img', res => { if (res.intersectionRatio) { for (var j = this.nodes.length; j--;) if (this.nodes[j].name == 'img') this.$set(this.ctrl, j, 1); this.observer.disconnect(); } }) }, 0) } // #endif
} else if (n.name == 'video' || n.name == 'audio') { var ctx; if (n.name == 'video') { ctx = uni.createVideoContext(n.attrs.id // #ifndef MP-BAIDU
, this // #endif
); } else if (this.$refs[n.attrs.id]) ctx = this.$refs[n.attrs.id][0]; if (ctx) { ctx.id = n.attrs.id; this.top.videoContexts.push(ctx); } } } // #ifdef APP-PLUS
// APP 上避免 video 错位需要延时渲染
setTimeout(() => { this.loadVideo = true; }, 1000) // #endif
}, play(e) { var contexts = this.top.videoContexts; if (contexts.length > 1 && this.top.autopause) for (var i = contexts.length; i--;) if (contexts[i].id != e.currentTarget.dataset.id) contexts[i].pause(); }, imgtap(e) { var attrs = e.currentTarget.dataset.attrs; if (!attrs.ignore) { var preview = true, data = { id: e.target.id, src: attrs.src, ignore: () => preview = false }; global.Parser.onImgtap && global.Parser.onImgtap(data); this.top.$emit('imgtap', data); if (preview) { var urls = this.top.imgList, current = urls[attrs.i] ? parseInt(attrs.i) : (urls = [attrs.src], 0); uni.previewImage({ current, urls }) } } }, loadImg(e) { var i = e.currentTarget.dataset.i; if (this.lazyLoad && !this.ctrl[i]) { // #ifdef QUICKAPP-WEBVIEW
this.$set(this.ctrl, i, 0); this.$nextTick(function() { // #endif
// #ifndef APP-PLUS
this.$set(this.ctrl, i, 1); // #endif
// #ifdef QUICKAPP-WEBVIEW
}) // #endif
} else if (this.loading && this.ctrl[i] != 2) { // #ifdef QUICKAPP-WEBVIEW
this.$set(this.ctrl, i, 0); this.$nextTick(function() { // #endif
this.$set(this.ctrl, i, 2); // #ifdef QUICKAPP-WEBVIEW
}) // #endif
} }, linkpress(e) { var jump = true, attrs = e.currentTarget.dataset.attrs; attrs.ignore = () => jump = false; global.Parser.onLinkpress && global.Parser.onLinkpress(attrs); this.top.$emit('linkpress', attrs); if (jump) { // #ifdef MP
if (attrs['app-id']) { return uni.navigateToMiniProgram({ appId: attrs['app-id'], path: attrs.path }) } // #endif
if (attrs.href) { if (attrs.href[0] == '#') { if (this.top.useAnchor) this.top.navigateTo({ id: attrs.href.substring(1) }) } else if (attrs.href.indexOf('http') == 0 || attrs.href.indexOf('//') == 0) { // #ifdef APP-PLUS
plus.runtime.openWeb(attrs.href); // #endif
// #ifndef APP-PLUS
uni.setClipboardData({ data: attrs.href, success: () => uni.showToast({ title: '链接已复制' }) }) // #endif
} else uni.navigateTo({ url: attrs.href, fail() { uni.switchTab({ url: attrs.href, }) } }) } } }, error(e) { var target = e.currentTarget, source = target.dataset.source, i = target.dataset.i; if (source == 'video' || source == 'audio') { // 加载其他 source
var index = this.ctrl[i] ? this.ctrl[i].i + 1 : 1; if (index < this.nodes[i].attrs.source.length) this.$set(this.ctrl, i, index); if (e.detail.__args__) e.detail = e.detail.__args__[0]; } else if (errorImg && source == 'img') { this.top.imgList.setItem(target.dataset.index, errorImg); this.$set(this.ctrl, i, 3); } this.top && this.top.$emit('error', { source, target, errMsg: e.detail.errMsg }); }, _loadVideo(e) { this.$set(this.ctrl, e.target.dataset.i, 0); } } } </script>
<style> /* 在这里引入自定义样式 */
/* 链接和图片效果 */ ._a { display: inline; padding: 1.5px 0 1.5px 0; color: #366092; word-break: break-all; }
._hover { text-decoration: underline; opacity: 0.7; }
._img { display: inline-block; max-width: 100%; overflow: hidden; }
/* #ifdef MP-WEIXIN */ :host { display: inline; }
/* #endif */
/* #ifndef MP-ALIPAY || APP-PLUS */ .interlayer { display: inherit; flex-direction: inherit; flex-wrap: inherit; align-content: inherit; align-items: inherit; justify-content: inherit; width: 100%; white-space: inherit; }
/* #endif */
._b, ._strong { font-weight: bold; }
/* #ifndef MP-ALIPAY */ ._blockquote, ._div, ._p, ._ol, ._ul, ._li { display: block; }
/* #endif */
._code { font-family: monospace; }
._del { text-decoration: line-through; }
._em, ._i { font-style: italic; }
._h1 { font-size: 2em; }
._h2 { font-size: 1.5em; }
._h3 { font-size: 1.17em; }
._h5 { font-size: 0.83em; }
._h6 { font-size: 0.67em; }
._h1, ._h2, ._h3, ._h4, ._h5, ._h6 { display: block; font-weight: bold; }
._image { display: block; width: 100%; height: 360px; margin-top: -360px; opacity: 0; }
._ins { text-decoration: underline; }
._li { flex: 1; width: 0; }
._ol-bef { width: 36px; margin-right: 5px; text-align: right; }
._ul-bef { display: block; margin: 0 12px 0 23px; line-height: normal; }
._ol-bef, ._ul-bef { flex: none; user-select: none; }
._ul-p1 { display: inline-block; width: 0.3em; height: 0.3em; overflow: hidden; line-height: 0.3em; }
._ul-p2 { display: inline-block; width: 0.23em; height: 0.23em; border: 0.05em solid black; border-radius: 50%; }
._q::before { content: '"'; }
._q::after { content: '"'; }
._sub { font-size: smaller; vertical-align: sub; }
._sup { font-size: smaller; vertical-align: super; }
/* #ifdef MP-ALIPAY || APP-PLUS || QUICKAPP-WEBVIEW */ ._abbr, ._b, ._code, ._del, ._em, ._i, ._ins, ._label, ._q, ._span, ._strong, ._sub, ._sup { display: inline; }
/* #endif */
/* #ifdef MP-WEIXIN || MP-QQ */ .__bdo, .__bdi, .__ruby, .__rt { display: inline-block; }
/* #endif */ ._video { position: relative; display: inline-block; width: 300px; height: 225px; background-color: black; }
._video::after { position: absolute; top: 50%; left: 50%; margin: -15px 0 0 -15px; content: ''; border-color: transparent transparent transparent white; border-style: solid; border-width: 15px 0 15px 30px; } </style>
|