app_tree_planting/components/parser/libs/trees.vue

440 lines
12 KiB
Vue
Raw Normal View History

2023-01-11 19:31:59 +08:00
<!--
trees 递归显示组件
github地址https://github.com/jin-yufeng/Parser
文档地址https://jin-yufeng.github.io/Parser
插件市场https://ext.dcloud.net.cn/plugin?id=805
authorJinYufeng
-->
<template>
<view style="display: inherit; white-space: inherit;max-width: 100%;">
<block v-for="(item, index) in nodes" v-bind:key="index">
<!--图片-->
<!--#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, imgLoad)' :data-attrs="item.attrs" @tap="imgtap" @longpress="imglongtap" />
<!--#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="imgtap" @longpress="imglongtap" />
<!--#endif-->
<!--文本-->
<!--#ifdef MP-WEIXIN || MP-QQ || APP-PLUS-->
<text v-else-if="item.type=='text'&&!item.decode" decode>{{item.text}}</text>
<rich-text v-else-if="item.type=='text'" style="display:inline-block" :nodes="[item]"></rich-text>
<!--#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>
<!--视频-->
<view v-else-if="item.name=='video'">
<!--#ifdef APP-PLUS-->
<view v-if="(!loadVideo||item.lazyLoad)&&(!controls[item.attrs.id]||!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" :poster="item.attrs.poster" :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="play" @error="videoError" />
</view>
<!--音频-->
<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="linkpress">
<trees :nodes="item.children" />
</view>
<!--广告-->
<!--#ifdef MP-WEIXIN || MP-QQ || MP-TOUTIAO-->
<ad v-else-if="item.name=='ad'" :unit-id="item.attrs['unit-id']" :class="item.attrs.class||''" :style="item.attrs.style||''"
@error="adError" />
<!--#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" />
<!--#endif-->
<!--#ifdef APP-PLUS-->
<ad v-else-if="item.name=='ad'" :adpid="item.attrs.adpid" :class="item.attrs.class||''" :style="item.attrs.style||''"
@error="adError" />
<!--#endif-->
<!--列表-->
<view v-else-if="item.name=='li'" :class="(item.attrs.class||'')+' _li'" :style="(item.attrs.style||'')+';display:flex'">
<view v-if="item.type=='ol'" class="_ol-before">{{item.num}}</view>
<view v-else class="_ul-before">
<view v-if="item.floor%3==0" class="_ul-type1"></view>
<view v-else-if="item.floor%3==2" class="_ul-type2" />
<view v-else class="_ul-type1" style="border-radius:50%"></view>
</view>
<!--#ifdef MP-ALIPAY-->
<view>
<trees :nodes="item.children" />
</view>
<!--#endif-->
<!--#ifndef MP-ALIPAY-->
<trees class="_node" :nodes="item.children" :loadVideo="loadVideo" style="display:block" />
<!--#endif-->
</view>
<!--富文本-->
<!--#ifdef MP-WEIXIN || MP-QQ || MP-ALIPAY || APP-PLUS-->
<rich-text v-else-if="!(item.c||inlineTags[item.name]||item.continue)" :id="item.attrs.id" :class="'__'+item.name"
:style="''+handler.getStyle(item.attrs.style, 'block')" :nodes="handler.setStyle(item)" />
<!--#endif-->
<!--#ifdef MP-BAIDU || MP-TOUTIAO-->
<rich-text v-else-if="!(item.c||item.continue)" :id="item.attrs.id" :style="item.attrs?item.attrs.containStyle:''"
:nodes="[item]" />
<!--#endif-->
<!--#ifdef MP-ALIPAY-->
<view v-else :id="item.attrs.id" :class="'_'+item.name+' '+(item.attrs.class||'')" :style="item.attrs.style||''">
<trees :nodes="item.children" />
</view>
<!--#endif-->
<!--#ifndef MP-ALIPAY-->
<trees v-else :class="item.attrs.id+' _'+item.name+' '+(item.attrs.class||'')" :style="item.attrs.style||''" :nodes="item.children"
: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>
const inlineTags = require("./config.js").inlineTags;
import trees from "./trees"
export default {
components: {
trees
},
name: 'trees',
data() {
return {
controls: {},
// #ifdef MP-WEIXIN || MP-QQ || APP-PLUS
imgLoad: false,
// #endif
// #ifndef MP-BAIDU || MP-TOUTIAO
inlineTags
// #endif
}
},
props: {
nodes: {
type: Array,
default: []
},
// #ifdef APP-PLUS
loadVideo: {
type: Boolean,
default: false
}
// #endif
},
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
play(e) {
if ((this._top.videoContexts || []).length > 1 && this._top.autopause) {
for (var i = this._top.videoContexts.length; i--;) {
if (this._top.videoContexts[i].id != e.currentTarget.id)
this._top.videoContexts[i].pause();
}
}
},
// #endif
imgtap(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) {
var urls = this._top.imgList || [],
current = urls[attrs.i] ? parseInt(attrs.i) : (urls = [attrs.src], 0);
uni.previewImage({
current,
urls
})
}
}
},
imglongtap(e) {
this._top.$emit('imglongtap', {
id: e.currentTarget.id,
src: e.currentTarget.dataset.attrs.src
})
},
linkpress(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) {
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) {
if (target.dataset.source.length <= 1) return false;
if (!this.controls[target.id]) {
this.$set(this.controls, target.id, {
index: 1
})
return true;
} else if (this.controls[target.id] && this.controls[target.id].index < target.dataset.source.length) {
this.$set(this.controls[target.id], "index", this.controls[target.id].index + 1);
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-WEIXIN || APP-PLUS */
:host {
display: inherit;
float: inherit;
}
/* #endif */
._b,
._strong {
font-weight: bold;
}
._big {
font-size: 1.2em;
}
._small {
font-size: 0.8em;
}
._blockquote,
._div,
._p,
._ol,
._ul,
._li {
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;
}
._ol-before {
width: 36px;
text-align: right;
margin-right: 5px;
flex-shrink: 0;
}
._ul-before {
margin-left: 23px;
margin-right: 12px;
line-height: normal;
flex-shrink: 0;
}
._ul-type1 {
width: 0.3em;
height: 0.3em;
line-height: 0.3em;
color: inherit;
display: inline-block;
overflow: hidden;
}
._ul-type2 {
width: 0.23em;
height: 0.23em;
background-color: transparent;
border: 0.05em solid black;
border-radius: 50%;
display: inline-block;
}
._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>