408 lines
10 KiB
Vue
408 lines
10 KiB
Vue
|
<!--
|
|||
|
trees 递归显示组件
|
|||
|
github地址:https://github.com/jin-yufeng/Parser
|
|||
|
文档地址:https://jin-yufeng.github.io/Parser
|
|||
|
插件市场:https://ext.dcloud.net.cn/plugin?id=805
|
|||
|
author:JinYufeng
|
|||
|
-->
|
|||
|
<template>
|
|||
|
<view style="display: inherit; white-space: inherit;word-break:normal">
|
|||
|
<block v-for="(item, index) in nodes" v-bind:key="index">
|
|||
|
<!-- {{item.name}} {{item}} -->
|
|||
|
<!--#ifdef MP-WEIXIN || MP-QQ || MP-ALIPAY || APP-PLUS-->
|
|||
|
<block v-if="handler.notContinue(item)">
|
|||
|
<!--#endif-->
|
|||
|
<!--#ifdef MP-BAIDU || MP-TOUTIAO-->
|
|||
|
<block v-if="!item.c">
|
|||
|
<!--#endif-->
|
|||
|
<!--图片-->
|
|||
|
<!--#ifdef MP-WEIXIN || MP-QQ || MP-ALIPAY || APP-PLUS-->
|
|||
|
<rich-text v-if="item.name=='img'" :id="item.attrs.id" class="img"
|
|||
|
:style="'text-indent:0;'+handler.getStyle(item.attrs.style, 'inline-block')"
|
|||
|
:nodes='handler.setImgStyle(item, imgMode, imgLoad)' :data-attrs="item.attrs"
|
|||
|
@tap='previewEvent' />
|
|||
|
<!--#endif-->
|
|||
|
<!--#ifdef MP-BAIDU || MP-TOUTIAO-->
|
|||
|
<rich-text v-if="item.name=='img'" :id="item.attrs.id"
|
|||
|
:style="'text-indent:0;'+item.attrs.containStyle" :nodes='[item]' :data-attrs="item.attrs"
|
|||
|
@tap='previewEvent' />
|
|||
|
<!--#endif-->
|
|||
|
<!--文本-->
|
|||
|
<!--#ifdef MP-WEIXIN || MP-QQ || APP-PLUS-->
|
|||
|
<block v-else-if="item.type=='text'">
|
|||
|
<text v-if="!item.decode" decode>{{item.text}}</text>
|
|||
|
<rich-text v-else style="display:inline-block;word-break:normal" :nodes="[item]"></rich-text>
|
|||
|
</block>
|
|||
|
<!--#endif-->
|
|||
|
<!--#ifdef MP-ALIPAY-->
|
|||
|
<text v-else-if="item.type=='text'" decode>{{item.text}}</text>
|
|||
|
<!--#endif-->
|
|||
|
<text v-else-if="item.name=='br'">\n</text>
|
|||
|
<!--视频-->
|
|||
|
<block v-else-if="item.name=='video'">
|
|||
|
<!--#ifdef APP-PLUS-->
|
|||
|
<view v-if="(!loadVideo||item.lazyLoad)&&!controls[item.attrs.id].play" :id="item.attrs.id"
|
|||
|
:class="'_video '+(item.attrs.class||'')" :style="item.attrs.style||''" @tap="_loadVideo" />
|
|||
|
<!--#endif-->
|
|||
|
<!--#ifndef APP-PLUS-->
|
|||
|
<view v-if="item.lazyLoad&&!controls[item.attrs.id].play" :id="item.attrs.id"
|
|||
|
:class="'_video '+(item.attrs.class||'')" :style="item.attrs.style||''" @tap="_loadVideo" />
|
|||
|
<!--#endif-->
|
|||
|
<video v-else
|
|||
|
:src="controls[item.attrs.id]?item.attrs.source[controls[item.attrs.id].index] : item.attrs.src"
|
|||
|
:id="item.attrs.id" :loop="item.attrs.loop" :controls="item.attrs.controls"
|
|||
|
:autoplay="item.attrs.autoplay||(controls[item.attrs.id]&&controls[item.attrs.id].play)"
|
|||
|
:unit-id="item.attrs['unit-id']" :class="item.attrs.class" :muted="item.attrs.muted"
|
|||
|
:style="item.attrs.style||''" :data-source="item.attrs.source" @play="playEvent"
|
|||
|
@error="videoError" />
|
|||
|
</block>
|
|||
|
<!-- iframe 【create_by_xx】-->
|
|||
|
<block v-else-if="item.name=='iframe'">
|
|||
|
<!-- #ifdef MP-WEIXIN -->
|
|||
|
<!-- 腾讯视频 -->
|
|||
|
<txv-video :vid="item.attrs.src" :playerid="item.attrs.src" width="100%" height="100%"
|
|||
|
:controls="true" :autoplay="false" :isHiddenStop="true"
|
|||
|
v-if="item.attrs.lbType=='vid' || item.attrs.lbtype=='vid'">
|
|||
|
</txv-video>
|
|||
|
<!-- #endif -->
|
|||
|
</block>
|
|||
|
<!--音频-->
|
|||
|
<audio v-else-if="item.name=='audio'"
|
|||
|
:src="controls[item.attrs.id]?item.attrs.source[controls[item.attrs.id].index] : item.attrs.src"
|
|||
|
:id="item.attrs.id" :loop="item.attrs.loop" :controls="item.attrs.controls"
|
|||
|
:poster="item.attrs.poster" :name="item.attrs.name" :author="item.attrs.author"
|
|||
|
:class="item.attrs.class" :style="item.attrs.style||''" :data-source="item.attrs.source"
|
|||
|
@error="audioError" />
|
|||
|
<!--链接-->
|
|||
|
<view v-else-if="item.name=='a'" :class="'_a '+(item.attrs.class||'')" :style="item.attrs.style||''"
|
|||
|
:data-attrs="item.attrs" hover-class="navigator-hover" :hover-start-time="25"
|
|||
|
:hover-stay-time="300" @tap="tapEvent">
|
|||
|
<trees :nodes="item.children" :imgMode="imgMode" />
|
|||
|
</view>
|
|||
|
<!--广告-->
|
|||
|
<!--#ifdef MP-WEIXIN || MP-QQ-->
|
|||
|
<ad v-else-if="item.name=='ad'" :unit-id="item.attrs['unit-id']" :class="item.attrs.class||''"
|
|||
|
:style="item.attrs.style||''" @error="adError"></ad>
|
|||
|
<!--#endif-->
|
|||
|
<!--#ifdef MP-BAIDU-->
|
|||
|
<ad v-else-if="item.name=='ad'" :appid="item.attrs.appid" :apid="item.attrs.apid"
|
|||
|
:type="item.attrs.type" :class="item.attrs.class||''" :style="item.attrs.style"
|
|||
|
@error="adError"></ad>
|
|||
|
<!--#endif-->
|
|||
|
<!--富文本-->
|
|||
|
<!--#ifdef MP-WEIXIN || MP-QQ || MP-ALIPAY || APP-PLUS-->
|
|||
|
<rich-text v-else :id="item.attrs.id" :class="'__'+item.name"
|
|||
|
:style="'word-break:normal;'+handler.getStyle(item.attrs.style, 'block')" :nodes="handler.setStyle(item)" />
|
|||
|
<!--#endif-->
|
|||
|
<!--#ifdef MP-BAIDU || MP-TOUTIAO-->
|
|||
|
<rich-text v-else :id="item.attrs.id" :style="item.attrs?item.attrs.containStyle:''"
|
|||
|
:nodes="[item]" />
|
|||
|
<!--#endif-->
|
|||
|
</block>
|
|||
|
<!--#ifdef MP-ALIPAY-->
|
|||
|
<view v-else :id="item.attrs.id" :class="'_'+item.name+' '+(item.attrs.class||'')"
|
|||
|
:style="item.attrs.style||''">
|
|||
|
<trees :nodes="item.children" :imgMode="imgMode" />
|
|||
|
</view>
|
|||
|
<!--#endif-->
|
|||
|
<!--#ifndef MP-ALIPAY-->
|
|||
|
<trees v-else :class="item.attrs.id+' _'+item.name+' '+(item.attrs.class||'')"
|
|||
|
:style="item.attrs.style||''" :nodes="item.children" :imgMode="imgMode" :loadVideo="loadVideo" />
|
|||
|
<!--#endif-->
|
|||
|
</block>
|
|||
|
</view>
|
|||
|
</template>
|
|||
|
<script module="handler" lang="wxs" src="./handler.wxs"></script>
|
|||
|
<script module="handler" lang="sjs" src="./handler.sjs"></script>
|
|||
|
<script>
|
|||
|
import trees from "./trees"
|
|||
|
export default {
|
|||
|
components: {
|
|||
|
trees
|
|||
|
},
|
|||
|
name: 'trees',
|
|||
|
data() {
|
|||
|
return {
|
|||
|
controls: {},
|
|||
|
// #ifdef MP-WEIXIN || MP-QQ || APP-PLUS
|
|||
|
imgLoad: true
|
|||
|
// #endif
|
|||
|
}
|
|||
|
},
|
|||
|
props: {
|
|||
|
nodes: {
|
|||
|
type: Array,
|
|||
|
default: []
|
|||
|
},
|
|||
|
// #ifdef APP-PLUS
|
|||
|
loadVideo: {
|
|||
|
type: Boolean,
|
|||
|
default: false
|
|||
|
},
|
|||
|
// #endif
|
|||
|
imgMode: {
|
|||
|
type: String,
|
|||
|
default: "default"
|
|||
|
}
|
|||
|
},
|
|||
|
mounted() {
|
|||
|
// 获取顶层组件
|
|||
|
this._top = this.$parent;
|
|||
|
while (this._top.$options.name != 'parser') {
|
|||
|
if (this._top._top) {
|
|||
|
this._top = this._top._top;
|
|||
|
break;
|
|||
|
}
|
|||
|
this._top = this._top.$parent;
|
|||
|
}
|
|||
|
},
|
|||
|
// #ifdef MP-WEIXIN || MP-QQ || APP-PLUS
|
|||
|
beforeDestroy() {
|
|||
|
if (this._observer)
|
|||
|
this._observer.disconnect();
|
|||
|
},
|
|||
|
// #endif
|
|||
|
methods: {
|
|||
|
// #ifndef MP-ALIPAY
|
|||
|
playEvent(e) {
|
|||
|
if ((this._top.videoContexts || []).length > 1 && this._top.autopause) {
|
|||
|
for (var video of this._top.videoContexts) {
|
|||
|
if (video.id == e.currentTarget.id) continue;
|
|||
|
video.pause();
|
|||
|
}
|
|||
|
}
|
|||
|
},
|
|||
|
// #endif
|
|||
|
previewEvent(e) {
|
|||
|
var attrs = e.currentTarget.dataset.attrs;
|
|||
|
if (!attrs.ignore) {
|
|||
|
var preview = true;
|
|||
|
this._top.$emit('imgtap', {
|
|||
|
id: e.currentTarget.id,
|
|||
|
src: attrs.src,
|
|||
|
ignore: () => preview = false
|
|||
|
})
|
|||
|
if (preview && this._top.autopreview) {
|
|||
|
var urls = this._top.imgList || [],
|
|||
|
current = urls[attrs.i] ? attrs.i : (urls = [attrs.src], 0);
|
|||
|
uni.previewImage({
|
|||
|
current,
|
|||
|
urls
|
|||
|
})
|
|||
|
}
|
|||
|
}
|
|||
|
},
|
|||
|
tapEvent(e) {
|
|||
|
var jump = true,
|
|||
|
attrs = e.currentTarget.dataset.attrs;
|
|||
|
attrs.ignore = () => jump = false;
|
|||
|
this._top.$emit('linkpress', attrs);
|
|||
|
if (jump) {
|
|||
|
// #ifdef MP
|
|||
|
if (attrs['app-id'] || attrs.appId) {
|
|||
|
return uni.navigateToMiniProgram({
|
|||
|
appId: attrs['app-id'] || attrs.appId,
|
|||
|
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) {
|
|||
|
if (this._top.autocopy) {
|
|||
|
uni.setClipboardData({
|
|||
|
data: attrs.href,
|
|||
|
success() {
|
|||
|
uni.showToast({
|
|||
|
title: '链接已复制'
|
|||
|
});
|
|||
|
}
|
|||
|
});
|
|||
|
}
|
|||
|
} else
|
|||
|
uni.navigateTo({
|
|||
|
url: attrs.href
|
|||
|
})
|
|||
|
}
|
|||
|
}
|
|||
|
},
|
|||
|
triggerError(source, target, errMsg, errCode, context) {
|
|||
|
this._top.$emit('error', {
|
|||
|
source,
|
|||
|
target,
|
|||
|
errMsg,
|
|||
|
errCode,
|
|||
|
context
|
|||
|
});
|
|||
|
},
|
|||
|
loadSource(target) {
|
|||
|
// console.log(target)
|
|||
|
var index = (this.controls[target.id] ? this.controls[target.id].index : 0) + 1;
|
|||
|
if (index < target.dataset.source.length) {
|
|||
|
this.$set(this.controls[target.id], "index", index);
|
|||
|
return true;
|
|||
|
}
|
|||
|
return false;
|
|||
|
},
|
|||
|
adError(e) {
|
|||
|
this.triggerError("ad", e.currentTarget, "", e.detail.errorCode);
|
|||
|
},
|
|||
|
videoError(e) {
|
|||
|
if (!this.loadSource(e.currentTarget) && this._top)
|
|||
|
this.triggerError("video", e.currentTarget, e.detail.errMsg, undefined, uni.createVideoContext(e
|
|||
|
.currentTarget.id,
|
|||
|
this));
|
|||
|
},
|
|||
|
audioError(e) {
|
|||
|
if (!this.loadSource(e.currentTarget))
|
|||
|
this.triggerError("audio", e.currentTarget, e.detail.errMsg);
|
|||
|
},
|
|||
|
_loadVideo(e) {
|
|||
|
this.$set(this.controls, e.currentTarget.id, {
|
|||
|
play: true,
|
|||
|
index: 0
|
|||
|
})
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
</script>
|
|||
|
|
|||
|
<style>
|
|||
|
/* 可以在这里引入自定义的外部样式 */
|
|||
|
|
|||
|
/* 链接受到点击的hover-class,可自定义修改 */
|
|||
|
.navigator-hover {
|
|||
|
opacity: 0.7;
|
|||
|
text-decoration: underline;
|
|||
|
}
|
|||
|
|
|||
|
/* 以下内容不建议修改 */
|
|||
|
/* #ifndef MP-BAIDU */
|
|||
|
:host {
|
|||
|
display: inherit;
|
|||
|
float: inherit;
|
|||
|
}
|
|||
|
|
|||
|
/* #endif */
|
|||
|
|
|||
|
._b,
|
|||
|
._strong {
|
|||
|
font-weight: bold;
|
|||
|
}
|
|||
|
|
|||
|
._big {
|
|||
|
font-size: 1.2em;
|
|||
|
}
|
|||
|
|
|||
|
._small {
|
|||
|
font-size: 0.8em;
|
|||
|
}
|
|||
|
|
|||
|
._blockquote,
|
|||
|
._div,
|
|||
|
._p {
|
|||
|
display: block;
|
|||
|
}
|
|||
|
|
|||
|
._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.67em;
|
|||
|
}
|
|||
|
|
|||
|
._h1,
|
|||
|
._h2,
|
|||
|
._h3,
|
|||
|
._h4,
|
|||
|
._h5,
|
|||
|
._h6 {
|
|||
|
font-weight: bold;
|
|||
|
}
|
|||
|
|
|||
|
._ins {
|
|||
|
text-decoration: underline;
|
|||
|
}
|
|||
|
|
|||
|
._q::before {
|
|||
|
content: '"';
|
|||
|
}
|
|||
|
|
|||
|
._q::after {
|
|||
|
content: '"';
|
|||
|
}
|
|||
|
|
|||
|
._a,
|
|||
|
._abbr,
|
|||
|
._b,
|
|||
|
._big,
|
|||
|
._small,
|
|||
|
._code,
|
|||
|
._del,
|
|||
|
._em,
|
|||
|
._i,
|
|||
|
._ins,
|
|||
|
._label,
|
|||
|
._q,
|
|||
|
._span,
|
|||
|
._strong {
|
|||
|
display: inline;
|
|||
|
}
|
|||
|
|
|||
|
/* #ifdef MP-WEIXIN || MP-QQ || MP-ALIPAY */
|
|||
|
.__sub,
|
|||
|
.__sup,
|
|||
|
.__bdo,
|
|||
|
.__bdi,
|
|||
|
.__ruby,
|
|||
|
.__rt {
|
|||
|
display: inline-block !important;
|
|||
|
}
|
|||
|
|
|||
|
/* #endif */
|
|||
|
._video {
|
|||
|
background-color: black;
|
|||
|
width: 300px;
|
|||
|
height: 225px;
|
|||
|
display: inline-block;
|
|||
|
position: relative;
|
|||
|
}
|
|||
|
|
|||
|
._video::after {
|
|||
|
content: '';
|
|||
|
border-width: 15px 0 15px 30px;
|
|||
|
border-style: solid;
|
|||
|
border-color: transparent transparent transparent white;
|
|||
|
position: absolute;
|
|||
|
left: 50%;
|
|||
|
top: 50%;
|
|||
|
margin: -15px 0 0 -15px;
|
|||
|
}
|
|||
|
</style>
|