初始化代码
This commit is contained in:
62
uniapp/uni-app/components/jyf-Parser/handler.sjs
Normal file
62
uniapp/uni-app/components/jyf-Parser/handler.sjs
Normal file
@@ -0,0 +1,62 @@
|
||||
var inlineTags = {
|
||||
abbr: true,
|
||||
b: true,
|
||||
big: true,
|
||||
code: true,
|
||||
del: true,
|
||||
em: true,
|
||||
font: true,
|
||||
i: true,
|
||||
ins: true,
|
||||
label: true,
|
||||
mark: true,
|
||||
q: true,
|
||||
s: true,
|
||||
small: true,
|
||||
span: true,
|
||||
strong: true,
|
||||
u: true
|
||||
}
|
||||
export default {
|
||||
getStyle: function(style, display) {
|
||||
var res = "";
|
||||
var reg = getRegExp("float\s*:\s*[^;]*", "i");
|
||||
if (reg.test(style)) res += reg.exec(style)[0];
|
||||
reg = getRegExp("margin[^;]*", "gi");
|
||||
var margin = reg.exec(style);
|
||||
while (margin) {
|
||||
res += (';' + margin[0]);
|
||||
margin = reg.exec(style);
|
||||
}
|
||||
reg = getRegExp("display\s*:\s*([^;]*)", "i");
|
||||
if (reg.test(style) && reg.exec(style)[1] != "flex") res += (';' + reg.exec(style)[0]);
|
||||
else res += (';display:' + display);
|
||||
reg = getRegExp("flex\s*:[^;]*", "i");
|
||||
if (reg.test(style)) res += (';' + reg.exec(style)[0]);
|
||||
reg = getRegExp("[^;\s]*width[^;]*", "ig");
|
||||
var width = reg.exec(style);
|
||||
while (width) {
|
||||
res += (';' + width[0]);
|
||||
width = reg.exec(style);
|
||||
}
|
||||
return res;
|
||||
},
|
||||
setImgStyle: function(item, imgMode) {
|
||||
if (imgMode == "widthFix")
|
||||
item.attrs.style = (item.attrs.style || '') + ";height:auto !important";
|
||||
if (getRegExp("[^-]width[^pev;]+").test(";" + item.attrs.style))
|
||||
item.attrs.style = (item.attrs.style || '') + ";width:100%";
|
||||
if (item.attrs.style)
|
||||
item.attrs.style = item.attrs.style.replace(getRegExp('margin[^;]*', "gi"), "");
|
||||
return [item];
|
||||
},
|
||||
setStyle: function(item) {
|
||||
if (item.attrs.style)
|
||||
item.attrs.style = item.attrs.style.replace(getRegExp("width[^;]*?%", "gi"), "width:100%").replace(getRegExp(
|
||||
'margin[^;]+', "gi"), "");
|
||||
return [item];
|
||||
},
|
||||
notContinue: function(item) {
|
||||
return !(item.c || inlineTags[item.name] || item["continue"]);
|
||||
}
|
||||
}
|
||||
56
uniapp/uni-app/components/jyf-Parser/handler.wxs
Normal file
56
uniapp/uni-app/components/jyf-Parser/handler.wxs
Normal file
@@ -0,0 +1,56 @@
|
||||
var inlineTags = {
|
||||
abbr: true,
|
||||
b: true,
|
||||
big: true,
|
||||
code: true,
|
||||
del: true,
|
||||
em: true,
|
||||
font: true,
|
||||
i: true,
|
||||
ins: true,
|
||||
label: true,
|
||||
mark: true,
|
||||
q: true,
|
||||
s: true,
|
||||
small: true,
|
||||
span: true,
|
||||
strong: true,
|
||||
u: true
|
||||
}
|
||||
module.exports = {
|
||||
getStyle: function(style, display) {
|
||||
var res = "";
|
||||
var reg = getRegExp("float[^;]+(?![\s\S]*?float)", "i");
|
||||
if (reg.test(style)) res += reg.exec(style)[0];
|
||||
reg = getRegExp("margin[^;]+", "gi");
|
||||
if (reg.test(style)) res += (';' + style.match(reg).join(';'));
|
||||
reg = getRegExp("display\s*:\s*([^;]*)(?![\s\S]*?display)", "i");
|
||||
if (reg.test(style) && reg.exec(style)[1] != "flex") res += (';' + reg.exec(style)[0]);
|
||||
else res += (';display:' + display);
|
||||
reg = getRegExp("flex[^;]*:[^;]+", "ig");
|
||||
if (reg.test(style)) res += (';' + style.match(reg).join(';'));
|
||||
reg = getRegExp("[^;\s]*width[^;]+", "ig");
|
||||
if (reg.test(style)) res += (';' + style.match(reg).join(';'));
|
||||
return res;
|
||||
},
|
||||
setImgStyle: function(item, imgMode, imgLoad) {
|
||||
if (imgMode == "widthFix") item.attrs.style = (item.attrs.style || '') + ";height:auto !important";
|
||||
if (item.attrs.style)
|
||||
item.attrs.style = item.attrs.style.replace(getRegExp("width[^;]*?%", "gi"), "width:100%").replace(getRegExp(
|
||||
'margin[^;]+', "gi"), "");
|
||||
if (!imgLoad) {
|
||||
delete item.attrs.src;
|
||||
item.attrs.style += ";width:20px !important;height:20px !important";
|
||||
}
|
||||
return [item];
|
||||
},
|
||||
setStyle: function(item) {
|
||||
if (item.attrs.style)
|
||||
item.attrs.style = item.attrs.style.replace(getRegExp("width[^;]*?%", "gi"), "width:100%").replace(getRegExp(
|
||||
'margin[^;]+', "gi"), "");
|
||||
return [item];
|
||||
},
|
||||
notContinue: function(item) {
|
||||
return !(item.c || inlineTags[item.name] || item["continue"]);
|
||||
}
|
||||
}
|
||||
622
uniapp/uni-app/components/jyf-Parser/index.vue
Normal file
622
uniapp/uni-app/components/jyf-Parser/index.vue
Normal file
@@ -0,0 +1,622 @@
|
||||
<!--
|
||||
parser 主模块组件
|
||||
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>
|
||||
<!--#ifdef H5-->
|
||||
<slot v-if="!html && !nodes.length"></slot>
|
||||
<div :id="'rtf' + uid" :style="(selectable ? 'user-select:text;-webkit-user-select:text;' : '') + (showWithAnimation ? ('opacity:0;' + showAnimation) : '')"></div>
|
||||
<!--#endif-->
|
||||
<!--#ifndef H5-->
|
||||
<slot v-if="!html[0].name && !html[0].type && !nodes.length"></slot>
|
||||
<!--#endif-->
|
||||
<!--#ifdef MP-ALIPAY-->
|
||||
<view class="_contain" :style="(selectable ? 'user-select:text;-webkit-user-select:text;' : '') + (showWithAnimation ? ('opacity:0;' + showAnimation) : '')">
|
||||
<trees :nodes="nodes.length ? nodes : (html[0].name || html[0].type ? html : [])" :imgMode="imgMode" />
|
||||
</view>
|
||||
<!--#endif-->
|
||||
<!--#ifndef MP-ALIPAY || H5-->
|
||||
<trees class="_contain" :style="'display:block;' + (selectable ? 'user-select:text;-webkit-user-select:text;' : '') + (showWithAnimation ? ('opacity:0;' + showAnimation) : '')"
|
||||
:nodes="nodes.length ? nodes : (html[0].name || html[0].type ? html : [])" :imgMode="imgMode" :loadVideo="loadVideo" />
|
||||
<!--#endif-->
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
// #ifndef H5
|
||||
import trees from "./trees"
|
||||
var document; // document 补丁包,详见 https://jin-yufeng.github.io/Parser/#/instructions?id=document
|
||||
const parseHtmlSync = require('./libs/MpHtmlParser.js').parseHtmlSync;
|
||||
// #ifdef APP-PLUS
|
||||
const cache = {};
|
||||
// #endif
|
||||
// #ifndef APP-PLUS
|
||||
const cache = getApp().parserCache = {};
|
||||
// #endif
|
||||
const CssHandler = require("./libs/CssHandler.js");
|
||||
// 散列函数(计算 cache 的 key)
|
||||
const Hash = (str) => {
|
||||
for (var i = 0, hash = 5381, len = str.length; i < len; i++)
|
||||
hash += (hash << 5) + str.charCodeAt(i);
|
||||
return hash;
|
||||
};
|
||||
// #endif
|
||||
// 动画
|
||||
const showAnimation =
|
||||
"transition:400ms ease 0ms;transition-property:transform,opacity;transform-origin:50% 50% 0;-webkit-transition:400ms ease 0ms;-webkit-transform:;-webkit-transition-property:transform,opacity;-webkit-transform-origin:50% 50% 0;opacity: 1"
|
||||
const config = require('./libs/config.js');
|
||||
// #ifdef MP-WEIXIN || MP-QQ || MP-BAIDU || MP-TOUTIAO
|
||||
// 图片链接去重
|
||||
const Deduplication = (src) => {
|
||||
if (src.indexOf("http") != 0) return src;
|
||||
var newSrc = '';
|
||||
for (var i = 0; i < src.length; i++) {
|
||||
newSrc += (Math.random() >= 0.5 ? src[i].toUpperCase() : src[i].toLowerCase());
|
||||
if (src[i] == '/' && src[i - 1] != '/' && src[i + 1] != '/') break;
|
||||
}
|
||||
newSrc += src.substring(i + 1);
|
||||
return newSrc;
|
||||
}
|
||||
// #endif
|
||||
export default {
|
||||
name: 'parser',
|
||||
data() {
|
||||
return {
|
||||
// #ifdef APP-PLUS
|
||||
loadVideo: false,
|
||||
// #endif
|
||||
// #ifdef H5
|
||||
uid: this._uid,
|
||||
showAnimation: '',
|
||||
// #endif
|
||||
// #ifndef H5
|
||||
showAnimation: {},
|
||||
controls: {},
|
||||
// #endif
|
||||
nodes: []
|
||||
}
|
||||
},
|
||||
// #ifndef H5
|
||||
components: {
|
||||
trees
|
||||
},
|
||||
// #endif
|
||||
props: {
|
||||
'html': {
|
||||
type: null,
|
||||
default: null
|
||||
},
|
||||
'autocopy': {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
// #ifndef MP-ALIPAY
|
||||
'autopause': {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
// #endif
|
||||
'autopreview': {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
'autosetTitle': {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
'domain': {
|
||||
type: String,
|
||||
default: null
|
||||
},
|
||||
'imgMode': {
|
||||
type: String,
|
||||
default: 'default'
|
||||
},
|
||||
// #ifdef MP-WEIXIN || MP-QQ || H5 || APP-PLUS
|
||||
'lazyLoad': {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
// #endif
|
||||
'selectable': {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
'tagStyle': {
|
||||
type: Object,
|
||||
default: () => {
|
||||
return {};
|
||||
}
|
||||
},
|
||||
'showWithAnimation': {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
'useAnchor': {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
'useCache': {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
html(html) {
|
||||
this.setContent(html, undefined, true);
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.imgList = [];
|
||||
this.imgList.each = function(f) {
|
||||
for (var i = 0; i < this.length; i++) {
|
||||
// #ifdef MP-ALIPAY || APP-PLUS
|
||||
this[i] = f(this[i], i, this) || this[i];
|
||||
// #endif
|
||||
// #ifndef MP-ALIPAY || APP-PLUS
|
||||
var newSrc = f(this[i], i, this);
|
||||
if (newSrc) {
|
||||
if (this.includes(newSrc)) this[i] = Deduplication(newSrc);
|
||||
else this[i] = newSrc;
|
||||
}
|
||||
// #endif
|
||||
}
|
||||
}
|
||||
this.setContent(this.html, undefined, true);
|
||||
},
|
||||
// #ifdef H5
|
||||
beforeDestroy() {
|
||||
if (this._observer) this._observer.disconnect();
|
||||
},
|
||||
// #endif
|
||||
methods: {
|
||||
// #ifdef H5
|
||||
setContent(html, options, observed) {
|
||||
if (typeof options == "object")
|
||||
for (var key in options) {
|
||||
key = key.replace(/-(\w)/g, function() {
|
||||
return arguments[1].toUpperCase();
|
||||
})
|
||||
this[key] = options[key];
|
||||
}
|
||||
html = html || '';
|
||||
if (!html) {
|
||||
if (this.rtf) this.rtf.parentNode.removeChild(this.rtf);
|
||||
return;
|
||||
}
|
||||
if (typeof html != 'string') html = this.Dom2Str(html.nodes || html);
|
||||
// 处理 rpx
|
||||
if (/[0-9.]*?rpx/.test(html)) {
|
||||
const rpx = uni.getSystemInfoSync().screenWidth / 750;
|
||||
html = html.replace(/([0-9.]*?)rpx/g, function() {
|
||||
return parseFloat(arguments[1]) * rpx + "px";
|
||||
})
|
||||
}
|
||||
// 处理 tag-style 和 userAgentStyles
|
||||
var style = "<style>";
|
||||
for (var item in config.userAgentStyles)
|
||||
style += (item + '{' + config.userAgentStyles[item] + '}');
|
||||
for (var item in this.tagStyle)
|
||||
style += (item + '{' + this.tagStyle[item] + '}');
|
||||
style += "</style>";
|
||||
html = style + html;
|
||||
if (this.rtf) this.rtf.parentNode.removeChild(this.rtf);
|
||||
this.rtf = document.createElement('div');
|
||||
this.rtf.innerHTML = html;
|
||||
for (var style of this.rtf.getElementsByTagName("style")) {
|
||||
style.innerHTML = style.innerHTML.replace(/\s*body/g, "#rtf" + this._uid);
|
||||
style.setAttribute("scoped", "true");
|
||||
}
|
||||
// 懒加载
|
||||
if (this.lazyLoad && IntersectionObserver) {
|
||||
if (this._observer) this._observer.disconnect();
|
||||
this._observer = new IntersectionObserver(changes => {
|
||||
for (var change of changes) {
|
||||
if (change.isIntersecting) {
|
||||
change.target.src = change.target.getAttribute("data-src");
|
||||
change.target.removeAttribute("data-src");
|
||||
this._observer.unobserve(change.target);
|
||||
}
|
||||
}
|
||||
}, {
|
||||
rootMargin: "1000px 0px 1000px 0px"
|
||||
})
|
||||
}
|
||||
var component = this;
|
||||
// 获取标题
|
||||
var title = this.rtf.getElementsByTagName("title");
|
||||
if (title.length && this.autosetTitle)
|
||||
uni.setNavigationBarTitle({
|
||||
title: title[0].innerText
|
||||
})
|
||||
// 图片处理
|
||||
this.imgList.length = 0;
|
||||
var imgs = this.rtf.getElementsByTagName("img");
|
||||
for (var i = 0; i < imgs.length; i++) {
|
||||
var img = imgs[i];
|
||||
img.style.maxWidth = "100%";
|
||||
img.i = i;
|
||||
if (this.domain && img.getAttribute("src")[0] == "/") {
|
||||
if (img.getAttribute("src")[1] == "/")
|
||||
img.src = (this.domain.includes("://") ? this.domain.split("://")[0] : "http") + ':' + img.getAttribute("src");
|
||||
else img.src = this.domain + img.getAttribute("src");
|
||||
}
|
||||
component.imgList.push(img.src);
|
||||
if (img.parentElement.nodeName != 'A') {
|
||||
img.onclick = function() {
|
||||
if (!this.hasAttribute('ignore')) {
|
||||
var preview = true;
|
||||
this.ignore = () => preview = false;
|
||||
component.$emit('imgtap', this);
|
||||
if (preview && component.autopreview) {
|
||||
uni.previewImage({
|
||||
current: this.i,
|
||||
urls: component.imgList
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
img.onerror = function() {
|
||||
component.$emit('error', {
|
||||
source: "img",
|
||||
target: this
|
||||
});
|
||||
}
|
||||
if (component.lazyLoad && this._observer) {
|
||||
img.setAttribute("data-src", img.src);
|
||||
img.removeAttribute("src");
|
||||
this._observer.observe(img);
|
||||
}
|
||||
}
|
||||
// 链接处理
|
||||
var links = this.rtf.getElementsByTagName("a");
|
||||
for (var link of links) {
|
||||
link.onclick = function(e) {
|
||||
var jump = true,
|
||||
href = this.getAttribute("href");
|
||||
component.$emit('linkpress', {
|
||||
href,
|
||||
ignore: () => jump = false
|
||||
});
|
||||
if (jump && href) {
|
||||
if (href[0] == '#') {
|
||||
if (component.useAnchor) {
|
||||
component.navigateTo({
|
||||
id: href.substring(1)
|
||||
})
|
||||
}
|
||||
} else if (href.indexOf("http") == 0 || href.indexOf("//") == 0)
|
||||
return true;
|
||||
else {
|
||||
uni.navigateTo({
|
||||
url: href
|
||||
})
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// 视频处理
|
||||
var videos = this.rtf.getElementsByTagName("video");
|
||||
component.videoContexts = videos;
|
||||
for (var video of videos) {
|
||||
video.style.maxWidth = "100%";
|
||||
video.onerror = function() {
|
||||
component.$emit('error', {
|
||||
source: "video",
|
||||
target: this
|
||||
});
|
||||
}
|
||||
video.onplay = function() {
|
||||
if (component.autopause) {
|
||||
for (var video of component.videoContexts) {
|
||||
if (video != this)
|
||||
video.pause();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// 音频处理
|
||||
var audios = this.rtf.getElementsByTagName("audios");
|
||||
for (var audio of audios) {
|
||||
audio.onerror = function(e) {
|
||||
component.$emit('error', {
|
||||
source: "audio",
|
||||
target: this
|
||||
});
|
||||
}
|
||||
}
|
||||
document.getElementById("rtf" + this._uid).appendChild(this.rtf);
|
||||
if (this.showWithAnimation)
|
||||
this.showAnimation = showAnimation;
|
||||
if (!observed) this.nodes = [0];
|
||||
this.$nextTick(() => {
|
||||
this.$emit("ready", this.rtf.getBoundingClientRect());
|
||||
})
|
||||
},
|
||||
Dom2Str(nodes) {
|
||||
var str = "";
|
||||
for (var node of nodes) {
|
||||
if (node.type == "text")
|
||||
str += node.text;
|
||||
else {
|
||||
str += ('<' + node.name);
|
||||
for (var attr in node.attrs || {})
|
||||
str += (' ' + attr + '="' + node.attrs[attr] + '"');
|
||||
if (!node.children || !node.children.length) str += "/>";
|
||||
else str += ('>' + this.Dom2Str(node.children) + "</" + node.name + '>');
|
||||
}
|
||||
}
|
||||
return str;
|
||||
},
|
||||
getText(whiteSpace = true) {
|
||||
if (!whiteSpace) return this.rtf.innerText.replace(/\s/g, '');
|
||||
return this.rtf.innerText;
|
||||
},
|
||||
navigateTo(obj) {
|
||||
if (!obj.id) {
|
||||
window.scrollTo(0, this.rtf.offsetTop);
|
||||
return obj.success ? obj.success({
|
||||
errMsg: "pageScrollTo:ok"
|
||||
}) : null;
|
||||
}
|
||||
var target = document.getElementById(obj.id);
|
||||
if (!target) return obj.fail ? obj.fail({
|
||||
errMsg: "Label Not Found"
|
||||
}) : null;
|
||||
uni.pageScrollTo({
|
||||
scrollTop: this.rtf.offsetTop + target.offsetTop,
|
||||
success: obj.success,
|
||||
fail: obj.fail
|
||||
});
|
||||
},
|
||||
// #endif
|
||||
// #ifndef H5
|
||||
setContent(html, options, observed) {
|
||||
if (typeof options == "object")
|
||||
for (var key in options) {
|
||||
key = key.replace(/-(\w)/g, function() {
|
||||
return arguments[1].toUpperCase();
|
||||
})
|
||||
this[key] = options[key];
|
||||
}
|
||||
if (this.showWithAnimation)
|
||||
this.showAnimation = showAnimation;
|
||||
if (!html) {
|
||||
if (observed) return;
|
||||
else this.nodes = [];
|
||||
} else if (typeof html == "string") {
|
||||
var res;
|
||||
// 缓存读取
|
||||
if (this.useCache) {
|
||||
var hash = Hash(html);
|
||||
if (cache[hash])
|
||||
res = cache[hash];
|
||||
else {
|
||||
res = parseHtmlSync(html, this);
|
||||
cache[hash] = res;
|
||||
}
|
||||
} else res = parseHtmlSync(html, this);
|
||||
this.nodes = res;
|
||||
this.$emit('parse', res);
|
||||
} else if (html.constructor == Array) {
|
||||
if (!observed) this.nodes = html;
|
||||
else this.nodes = [];
|
||||
// 非本插件产生的 array 需要进行一些转换
|
||||
if (html.length && html[0].PoweredBy != "Parser") {
|
||||
const Parser = {
|
||||
_imgNum: 0,
|
||||
_videoNum: 0,
|
||||
_audioNum: 0,
|
||||
_domain: this.domain,
|
||||
_protocol: this.domain ? (this.domain.includes("://") ? this.domain.split("://")[0] : "http") : undefined,
|
||||
_STACK: [],
|
||||
CssHandler: new CssHandler(this.tagStyle)
|
||||
};
|
||||
Parser.CssHandler.getStyle('');
|
||||
const DFS = (nodes) => {
|
||||
for (var node of nodes) {
|
||||
if (node.type == "text") continue;
|
||||
node.attrs = node.attrs || {};
|
||||
for (var item in node.attrs) {
|
||||
if (!config.trustAttrs[item]) node.attrs[item] = undefined;
|
||||
else if (typeof node.attrs[item] != "string") node.attrs[item] = node.attrs[item].toString();
|
||||
}
|
||||
config.LabelAttrsHandler(node, Parser);
|
||||
if (config.blockTags[node.name]) node.name = 'div';
|
||||
else if (!config.trustTags[node.name]) node.name = 'span';
|
||||
if (node.children && node.children.length) {
|
||||
Parser._STACK.push(node);
|
||||
DFS(node.children);
|
||||
Parser._STACK.pop();
|
||||
} else node.children = undefined;
|
||||
}
|
||||
}
|
||||
DFS(html);
|
||||
this.nodes = html;
|
||||
}
|
||||
} else if (typeof html == 'object' && html.nodes) {
|
||||
this.nodes = html.nodes;
|
||||
console.warn("Parser 类型错误:object 类型已废弃,请直接将 html 设置为 object.nodes (array 类型)");
|
||||
} else {
|
||||
return this.$emit('error', {
|
||||
source: "parse",
|
||||
errMsg: "传入的nodes数组格式不正确!应该传入的类型是array,实际传入的类型是:" + typeof html.nodes
|
||||
});
|
||||
}
|
||||
// #ifdef APP-PLUS
|
||||
this.loadVideo = false;
|
||||
// #endif
|
||||
if (document) this.document = new document("html", this.html || html, this);
|
||||
this.$nextTick(() => {
|
||||
this.imgList.length = 0;
|
||||
this.videoContexts = [];
|
||||
const getContext = (components) => {
|
||||
for (let component of components) {
|
||||
if (component.$options.name == "trees") {
|
||||
var observered = false;
|
||||
for (var item of component.nodes) {
|
||||
if (item.continue) continue;
|
||||
if (item.name == 'img') {
|
||||
if (item.attrs.src && item.attrs.i) {
|
||||
// #ifndef MP-ALIPAY || APP-PLUS
|
||||
if (this.imgList.indexOf(item.attrs.src) == -1)
|
||||
this.imgList[item.attrs.i] = item.attrs.src;
|
||||
else this.imgList[item.attrs.i] = Deduplication(item.attrs.src);
|
||||
// #endif
|
||||
// #ifdef MP-ALIPAY || APP-PLUS
|
||||
this.imgList[item.attrs.i] = item.attrs.src;
|
||||
// #endif
|
||||
}
|
||||
// #ifndef MP-ALIPAY
|
||||
if (!observered) {
|
||||
observered = true;
|
||||
if (this.lazyLoad && uni.createIntersectionObserver) {
|
||||
if (component._observer) component._observer.disconnect();
|
||||
component._observer = uni.createIntersectionObserver(component);
|
||||
component._observer.relativeToViewport({
|
||||
top: 1000,
|
||||
bottom: 1000
|
||||
}).observe('.img', res => {
|
||||
component.imgLoad = true;
|
||||
component._observer.disconnect();
|
||||
component._observer = null;
|
||||
})
|
||||
} else
|
||||
component.imgLoad = true;
|
||||
}
|
||||
// #endif
|
||||
}
|
||||
// #ifndef MP-ALIPAY
|
||||
else if (item.name == 'video') {
|
||||
var context = uni.createVideoContext(item.attrs.id, component);
|
||||
context.id = item.attrs.id;
|
||||
this.videoContexts.push(context);
|
||||
}
|
||||
// #endif
|
||||
// #ifdef MP-WEIXIN
|
||||
else if (item.name == 'audio' && item.attrs.autoplay)
|
||||
wx.createAudioContext(item.attrs.id, component).play();
|
||||
// #endif
|
||||
// 设置标题
|
||||
else if (item.name == "title") {
|
||||
if (item.children[0].type == "text" && item.children[0].text && this.autosetTitle)
|
||||
uni.setNavigationBarTitle({
|
||||
title: item.children[0].text
|
||||
})
|
||||
}
|
||||
// #ifdef MP-BAIDU || MP-ALIPAY
|
||||
if (item.attrs && item.attrs.id) {
|
||||
this.anchors = this.anchors || [];
|
||||
this.anchors.push({
|
||||
id: item.attrs.id,
|
||||
node: component
|
||||
})
|
||||
}
|
||||
// #endif
|
||||
}
|
||||
}
|
||||
if (component.$children.length)
|
||||
getContext(component.$children)
|
||||
}
|
||||
}
|
||||
// #ifdef MP-TOUTIAO
|
||||
setTimeout(() => {
|
||||
// #endif
|
||||
getContext(this.$children)
|
||||
uni.createSelectorQuery().in(this).select("._contain").boundingClientRect(res => {
|
||||
this.$emit("ready", res);
|
||||
}).exec();
|
||||
// #ifdef MP-TOUTIAO
|
||||
}, 200)
|
||||
// #endif
|
||||
// #ifdef APP-PLUS
|
||||
setTimeout(() => {
|
||||
this.loadVideo = true;
|
||||
}, 3000);
|
||||
// #endif
|
||||
})
|
||||
},
|
||||
getText(whiteSpace = true) {
|
||||
var text = "";
|
||||
const DFS = (node) => {
|
||||
if (node.type == "text") return text += node.text;
|
||||
else {
|
||||
if (whiteSpace && (((node.name == 'p' || node.name == "div" || node.name == "tr" || node.name == "li" ||
|
||||
/h[1-6]/.test(node.name)) && text && text[text.length - 1] != '\n') || node.name == "br"))
|
||||
text += '\n';
|
||||
for (var child of node.children || [])
|
||||
DFS(child);
|
||||
if (whiteSpace && (node.name == 'p' || node.name == "div" || node.name == "tr" || node.name == "li" || /h[1-6]/.test(
|
||||
node.name)) && text && text[text.length - 1] != '\n')
|
||||
text += '\n';
|
||||
else if (whiteSpace && node.name == "td") text += '\t';
|
||||
}
|
||||
}
|
||||
var nodes = ((this.nodes && this.nodes.length) ? this.nodes : (this.html[0] && (this.html[0].name || this.html[0].type) ?
|
||||
this.html : []));
|
||||
if (!nodes.length) return "";
|
||||
for (var node of nodes)
|
||||
DFS(node);
|
||||
return text;
|
||||
},
|
||||
navigateTo(obj) {
|
||||
var Scroll = (selector, component) => {
|
||||
const query = uni.createSelectorQuery().in(component ? component : this);
|
||||
query.select(selector).boundingClientRect();
|
||||
query.selectViewport().scrollOffset();
|
||||
query.exec(res => {
|
||||
if (!res || !res[0])
|
||||
return obj.fail ? obj.fail({
|
||||
errMsg: "Label Not Found"
|
||||
}) : null;
|
||||
uni.pageScrollTo({
|
||||
scrollTop: res[1].scrollTop + res[0].top,
|
||||
success: obj.success,
|
||||
fail: obj.fail
|
||||
})
|
||||
})
|
||||
}
|
||||
if (!obj.id) Scroll("._contain");
|
||||
else {
|
||||
// #ifndef MP-BAIDU || MP-ALIPAY
|
||||
Scroll('._contain >>> #' + obj.id + ', ._contain >>> .' + obj.id);
|
||||
// #endif
|
||||
// #ifdef MP-BAIDU || MP-ALIPAY
|
||||
for (var anchor of this.anchors) {
|
||||
if (anchor.id == obj.id) {
|
||||
Scroll("#" + obj.id + ", ." + obj.id, anchor.node);
|
||||
}
|
||||
}
|
||||
// #endif
|
||||
}
|
||||
},
|
||||
// #endif
|
||||
getVideoContext(id) {
|
||||
if (!id) return this.videoContexts;
|
||||
else {
|
||||
for (var video of this.videoContexts) {
|
||||
if (video.id == id) return video;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
/* #ifndef MP-BAIDU */
|
||||
:host {
|
||||
display: block;
|
||||
overflow: scroll;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
}
|
||||
|
||||
/* #endif */
|
||||
</style>
|
||||
149
uniapp/uni-app/components/jyf-Parser/libs/CssHandler.js
Normal file
149
uniapp/uni-app/components/jyf-Parser/libs/CssHandler.js
Normal file
@@ -0,0 +1,149 @@
|
||||
/*
|
||||
解析和匹配 Css 的选择器
|
||||
github地址:https://github.com/jin-yufeng/Parser
|
||||
文档地址:https://jin-yufeng.github.io/Parser
|
||||
author:JinYufeng
|
||||
*/
|
||||
const userAgentStyles = require("./config.js").userAgentStyles;
|
||||
class CssHandler {
|
||||
constructor(tagStyle = {}) {
|
||||
this.styles = Object.assign({}, tagStyle);
|
||||
};
|
||||
getStyle(data) {
|
||||
var style = '';
|
||||
data = data.replace(/<[sS][tT][yY][lL][eE][\s\S]*?>([\s\S]*?)<\/[sS][tT][yY][lL][eE][\s\S]*?>/g, function() {
|
||||
style += arguments[1];
|
||||
return '';
|
||||
})
|
||||
this.styles = new CssParser(style, this.styles).parse();
|
||||
return data;
|
||||
};
|
||||
parseCss(css) {
|
||||
return new CssParser(css, {}, true).parse();
|
||||
};
|
||||
match(name, attrs) {
|
||||
var tmp, matched = ((tmp = this.styles[name]) ? (tmp + ';') : '');
|
||||
if (attrs.class) {
|
||||
var classes = attrs.class.split(' ');
|
||||
for (var i = 0; i < classes.length; i++)
|
||||
if (tmp = this.styles['.' + classes[i]])
|
||||
matched += (tmp + ';');
|
||||
}
|
||||
if (tmp = this.styles['#' + attrs.id])
|
||||
matched += tmp;
|
||||
return matched;
|
||||
};
|
||||
}
|
||||
module.exports = CssHandler;
|
||||
|
||||
function isBlankChar(c) {
|
||||
return c == ' ' || c == '\u00A0' || c == '\t' || c == '\r' || c == '\n' || c == '\f';
|
||||
};
|
||||
class CssParser {
|
||||
constructor(data, tagStyle, api) {
|
||||
this.data = data;
|
||||
this.res = tagStyle;
|
||||
if (!api)
|
||||
for (var item in userAgentStyles) {
|
||||
if (tagStyle[item]) tagStyle[item] = userAgentStyles[item] + ';' + tagStyle[item];
|
||||
else tagStyle[item] = userAgentStyles[item];
|
||||
}
|
||||
this._floor = 0;
|
||||
this._i = 0;
|
||||
this._list = [];
|
||||
this._comma = false;
|
||||
this._sectionStart = 0;
|
||||
this._state = this.Space;
|
||||
};
|
||||
parse() {
|
||||
for (; this._i < this.data.length; this._i++)
|
||||
this._state(this.data[this._i]);
|
||||
return this.res;
|
||||
};
|
||||
// 状态机
|
||||
Space(c) {
|
||||
if (c == '.' || c == '#' || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) {
|
||||
this._sectionStart = this._i;
|
||||
this._state = this.StyleName;
|
||||
} else if (c == '/' && this.data[this._i + 1] == '*')
|
||||
this.Comment();
|
||||
else if (!isBlankChar(c) && c != ';')
|
||||
this._state = this.Ignore;
|
||||
};
|
||||
Comment() {
|
||||
this._i = this.data.indexOf("*/", this._i);
|
||||
if (this._i == -1) this._i = this.data.length;
|
||||
this._i++;
|
||||
this._state = this.Space;
|
||||
};
|
||||
Ignore(c) {
|
||||
if (c == '{') this._floor++;
|
||||
else if (c == '}' && --this._floor <= 0) {
|
||||
this._list = [];
|
||||
this._state = this.Space;
|
||||
}
|
||||
};
|
||||
StyleName(c) {
|
||||
if (isBlankChar(c)) {
|
||||
this._list.push(this.data.substring(this._sectionStart, this._i));
|
||||
this._state = this.NameSpace;
|
||||
} else if (c == '{') {
|
||||
this._list.push(this.data.substring(this._sectionStart, this._i));
|
||||
this._floor = 1;
|
||||
this._sectionStart = this._i + 1;
|
||||
this.Content();
|
||||
} else if (c == ',') {
|
||||
this._list.push(this.data.substring(this._sectionStart, this._i));
|
||||
this._sectionStart = this._i + 1;
|
||||
this._comma = true;
|
||||
} else if (!(c >= 'a' && c <= 'z') && !(c >= 'A' && c <= 'Z') && !(c >= '0' && c <= '9') && c != '.' && c != '#' &&
|
||||
c != '-' && c != '_')
|
||||
this._state = this.Ignore;
|
||||
};
|
||||
NameSpace(c) {
|
||||
if (c == '{') {
|
||||
this._floor = 1;
|
||||
this._sectionStart = this._i + 1;
|
||||
this.Content();
|
||||
} else if (c == ',') {
|
||||
this._comma = true;
|
||||
this._sectionStart = this._i + 1;
|
||||
this._state = this.StyleName;
|
||||
} else if (!isBlankChar(c)) {
|
||||
if (this._comma) {
|
||||
this._state = this.StyleName;
|
||||
this._sectionStart = this._i;
|
||||
this._i--;
|
||||
this._comma = false;
|
||||
} else this._state = this.Ignore;
|
||||
}
|
||||
};
|
||||
Content() {
|
||||
this._i = this.data.indexOf('}', this._i);
|
||||
if (this._i == -1) this._i = this.data.length;
|
||||
// 去除空白符
|
||||
var flag = false,
|
||||
pos, content = this.data.substring(this._sectionStart, this._i);
|
||||
for (var i = 0; i < content.length; i++) {
|
||||
if (isBlankChar(content[i])) {
|
||||
if (!flag) {
|
||||
pos = i;
|
||||
flag = true;
|
||||
}
|
||||
} else {
|
||||
if (flag) {
|
||||
if (pos == 0) content = content.substring(i);
|
||||
else if (i - pos > 1) content = content.substring(0, pos) + (content[pos - 1] == ';' ? (pos--, '') : ' ') +
|
||||
content.substring(i);
|
||||
i = pos;
|
||||
flag = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (flag) content = content.substring(0, pos);
|
||||
for (var i = 0; i < this._list.length; i++)
|
||||
this.res[this._list[i]] = (this.res[this._list[i]] || '') + content;
|
||||
this._list = [];
|
||||
this._state = this.Space;
|
||||
}
|
||||
}
|
||||
430
uniapp/uni-app/components/jyf-Parser/libs/MpHtmlParser.js
Normal file
430
uniapp/uni-app/components/jyf-Parser/libs/MpHtmlParser.js
Normal file
@@ -0,0 +1,430 @@
|
||||
/*
|
||||
将 html 解析为适用于小程序 rich-text 的 DOM 结构
|
||||
github地址:https://github.com/jin-yufeng/Parser
|
||||
文档地址:https://jin-yufeng.github.io/Parser
|
||||
author:JinYufeng
|
||||
*/
|
||||
const CssHandler = require("./CssHandler.js");
|
||||
const config = require("./config.js");
|
||||
var emoji; // 需要使用 emoji 补丁包时将此行改为 const emoji = require("./emoji.js");
|
||||
|
||||
function isBlankChar(c) {
|
||||
return c == ' ' || c == '\u00A0' || c == '\t' || c == '\r' || c == '\n' || c == '\f';
|
||||
};
|
||||
class MpHtmlParser {
|
||||
constructor(data, options = {}, cb) {
|
||||
this.cb = cb;
|
||||
this.CssHandler = new CssHandler(options.tagStyle);
|
||||
this.data = data;
|
||||
this.DOM = [];
|
||||
// #ifdef MP-BAIDU || MP-TOUTIAO
|
||||
this._imgMode = options.imgMode;
|
||||
// #endif
|
||||
this._attrName = '';
|
||||
this._attrValue = '';
|
||||
this._attrs = {};
|
||||
this._domain = options.domain;
|
||||
this._protocol = options.domain ? (options.domain.includes("://") ? this._domain.split("://")[0] : "http") :
|
||||
undefined;
|
||||
this._i = 0;
|
||||
this._sectionStart = 0;
|
||||
this._state = this.Text;
|
||||
this._STACK = [];
|
||||
this._tagName = '';
|
||||
this._audioNum = 0;
|
||||
this._imgNum = 0;
|
||||
this._videoNum = 0;
|
||||
this._useAnchor = options.useAnchor;
|
||||
this._whiteSpace = false;
|
||||
};
|
||||
parse() {
|
||||
if (this.CssHandler) this.data = this.CssHandler.getStyle(this.data);
|
||||
if (emoji) this.data = emoji.parseEmoji(this.data);
|
||||
// 高亮处理
|
||||
if (config.highlight)
|
||||
this.data = this.data.replace(/<[pP][rR][eE]([\s\S]*?)>([\s\S]*?)<\/[pP][rR][eE][\s\S]*?>/g, function() {
|
||||
return "<pre" + arguments[1] + '>' + config.highlight(arguments[2], "<pre" + arguments[1] + '>') + "</pre>";
|
||||
})
|
||||
for (var len = this.data.length; this._i < len; this._i++)
|
||||
this._state(this.data[this._i]);
|
||||
if (this._state == this.Text) this.setText();
|
||||
while (this._STACK.length)
|
||||
this.popNode(this._STACK.pop());
|
||||
// #ifdef MP-BAIDU || MP-TOUTIAO
|
||||
const inlineTags = config.makeMap("abbr,b,big,code,del,em,font,i,ins,label,mark,q,s,small,span,strong,sub,sup,u")
|
||||
// 将顶层标签的一些样式提取出来给 rich-text
|
||||
const setContain = function(nodes) {
|
||||
for (var element of nodes) {
|
||||
if (element.type == "text")
|
||||
continue;
|
||||
if (!element.c) {
|
||||
var res = "";
|
||||
var style = element.attrs.style;
|
||||
var reg = /float[^;]+(?![\s\S]*?float)/i;
|
||||
if (reg.test(style)) res += reg.exec(style)[0];
|
||||
reg = /margin[^;]+/gi;
|
||||
if (reg.test(style)) res += (';' + style.match(reg).join(';'));
|
||||
reg = /display\s*:\s*([^;]*)(?![\s\S]*?display)/i;
|
||||
if (reg.test(style) && reg.exec(style)[1] != "flex") res += (';' + reg.exec(style)[0]);
|
||||
else if (inlineTags[element.name]) res += ";display:inline";
|
||||
else res += (";display:" + (element.name == 'img' ? 'inline-block' : 'block'));
|
||||
reg = /flex[^;]*:[^;]+/gi;
|
||||
if (reg.test(style)) res += (';' + style.match(reg).join(';'));
|
||||
reg = /[^;\s]*width[^;]+/gi;
|
||||
if (reg.test(style)) res += (';' + style.match(reg).join(';'));
|
||||
element.attrs.containStyle = res;
|
||||
if (/[^-]width[^pev;]+/.test(";" + style))
|
||||
element.attrs.style += ";width:100%";
|
||||
let addMargin = "";
|
||||
if (/margin\s*:/.test(style)) addMargin = ';margin:0';
|
||||
else if (/margin-top/.test(style)) addMargin = ';margin-top:0';
|
||||
else if (/margin-bottom/.test(style)) addMargin = ';margin-bottom:0';
|
||||
element.attrs.style = (element.attrs.style || '').replace(/margin[^;]*/gi, "");
|
||||
element.attrs.style += addMargin;
|
||||
} else setContain(element.children);
|
||||
}
|
||||
};
|
||||
setContain(this.DOM);
|
||||
// #endif
|
||||
if (this.DOM.length) this.DOM[0].PoweredBy = "Parser";
|
||||
// console.log(this.DOM)
|
||||
if (this.cb)
|
||||
this.cb(this.DOM)
|
||||
else return this.DOM;
|
||||
};
|
||||
// 设置属性
|
||||
setAttr() {
|
||||
if (config.trustAttrs[this._attrName])
|
||||
this._attrs[this._attrName] = (this._attrValue ? this._attrValue : (this._attrName == "src" ? "" : "true"));
|
||||
this._attrValue = '';
|
||||
while (isBlankChar(this.data[this._i])) this._i++;
|
||||
if (this.checkClose()) this.setNode();
|
||||
else this._state = this.AttrName;
|
||||
};
|
||||
// 设置文本节点
|
||||
setText() {
|
||||
var text = this.getSelection();
|
||||
if (text) {
|
||||
if (!this._whiteSpace) {
|
||||
// 移除空白符
|
||||
var flag = false,
|
||||
has = false,
|
||||
pos;
|
||||
for (var i = 0; i < text.length; i++) {
|
||||
if (isBlankChar(text[i])) {
|
||||
if (!flag) {
|
||||
pos = i;
|
||||
flag = true;
|
||||
}
|
||||
} else {
|
||||
has = true;
|
||||
if (flag) {
|
||||
if (i - pos > 1) text = text.substring(0, pos) + ' ' + text.substring(i);
|
||||
i = pos;
|
||||
flag = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (flag) text = text.substring(0, pos) + ' ';
|
||||
if (!text || !has) return;
|
||||
}
|
||||
// 检查实体
|
||||
// #ifdef MP-BAIDU || MP-ALIPAY || MP-TOUTIAO
|
||||
var entities = {
|
||||
lt: "<",
|
||||
gt: ">",
|
||||
amp: "&",
|
||||
quot: '"',
|
||||
apos: "'",
|
||||
nbsp: "\u00A0",
|
||||
ensp: "\u2002",
|
||||
emsp: "\u2003",
|
||||
ndash: "–",
|
||||
mdash: "—",
|
||||
middot: "·",
|
||||
lsquo: "‘",
|
||||
rsquo: "’",
|
||||
ldquo: "“",
|
||||
rdquo: "”",
|
||||
bull: "•",
|
||||
hellip: "…",
|
||||
permil: "‰",
|
||||
copy: "©",
|
||||
reg: "®",
|
||||
trade: "™",
|
||||
times: "×",
|
||||
divide: "÷",
|
||||
cent: "¢",
|
||||
pound: "£",
|
||||
yen: "¥",
|
||||
euro: "€",
|
||||
sect: "§"
|
||||
};
|
||||
// #endif
|
||||
var i = text.indexOf('&'),
|
||||
j, decode;
|
||||
while (i != -1 && i < text.length) {
|
||||
j = text.indexOf(';', i);
|
||||
if (j - i >= 2 && j - i <= 7) {
|
||||
var entity = text.substring(i + 1, j);
|
||||
// #ifdef MP-WEIXIN || MP-QQ || APP-PLUS
|
||||
if (!entity.includes("sp") && !entity.includes("lt") && !entity.includes("gt")) {
|
||||
decode = true
|
||||
break;
|
||||
}
|
||||
// #endif
|
||||
// #ifdef MP-BAIDU || MP-ALIPAY || MP-TOUTIAO
|
||||
if (entities[entity]) text = text.substring(0, i) + entities[entity] + text.substring(j + 1);
|
||||
// #endif
|
||||
}
|
||||
i = text.indexOf('&', i + 1);
|
||||
}
|
||||
var slibings = this._STACK.length ? this._STACK[this._STACK.length - 1].children : this.DOM;
|
||||
if (slibings.length && slibings[slibings.length - 1].type == "text") {
|
||||
slibings[slibings.length - 1].text += text;
|
||||
if (decode) slibings[slibings.length - 1].decode = true;
|
||||
} else
|
||||
slibings.push({
|
||||
type: "text",
|
||||
text,
|
||||
decode
|
||||
})
|
||||
}
|
||||
};
|
||||
// 设置元素节点
|
||||
setNode() {
|
||||
var slibings = this._STACK.length ? this._STACK[this._STACK.length - 1].children : this.DOM;
|
||||
var node = {
|
||||
name: this._tagName.toLowerCase(),
|
||||
attrs: this._attrs
|
||||
}
|
||||
config.LabelAttrsHandler(node, this);
|
||||
this._attrs = {};
|
||||
if (this.data[this._i] == '>') {
|
||||
if (!config.selfClosingTags[this._tagName]) {
|
||||
if (config.ignoreTags[node.name]) {
|
||||
var j = this._i;
|
||||
// 处理要被移除的标签
|
||||
while (this._i < this.data.length) {
|
||||
this._i = this.data.indexOf("</", this._i);
|
||||
if (this._i == -1) return this._i = this.data.length;
|
||||
this._i += 2;
|
||||
this._sectionStart = this._i;
|
||||
while (!isBlankChar(this.data[this._i]) && this.data[this._i] != '>' && this.data[this._i] != '/') this._i++;
|
||||
if (this.data.substring(this._sectionStart, this._i).toLowerCase() == node.name) {
|
||||
this._i = this.data.indexOf('>', this._i);
|
||||
if (this._i == -1) this._i = this.data.length;
|
||||
else this._sectionStart = this._i + 1;
|
||||
this._state = this.Text;
|
||||
// 处理svg
|
||||
if (node.name == "svg") {
|
||||
var src = this.data.substring(j, this._i + 1);
|
||||
if (!node.attrs.xmlns) src = " xmlns=\"http://www.w3.org/2000/svg\"" + src;
|
||||
this._i = j;
|
||||
while (this.data[j] != '<') j--;
|
||||
src = this.data.substring(j, this._i) + src;
|
||||
this._i = this._sectionStart - 1;
|
||||
node.name = "img";
|
||||
node.attrs = {
|
||||
src: "data:image/svg+xml;utf8," + src.replace(/#/g, "%23"),
|
||||
ignore: "true"
|
||||
}
|
||||
slibings.push(node);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
return;
|
||||
} else this._STACK.push(node);
|
||||
node.children = [];
|
||||
}
|
||||
} else this._i++;
|
||||
this._sectionStart = this._i + 1;
|
||||
this._state = this.Text;
|
||||
if (!config.ignoreTags[node.name]) {
|
||||
// 检查空白符是否有效
|
||||
if (node.name == "pre" || (node.attrs.style && node.attrs.style.toLowerCase().includes("white-space") && node.attrs
|
||||
.style.toLowerCase().includes("pre"))) {
|
||||
this._whiteSpace = true;
|
||||
node.pre = true;
|
||||
}
|
||||
slibings.push(node);
|
||||
}
|
||||
};
|
||||
// 标签出栈处理
|
||||
popNode(node) {
|
||||
// 替换一些标签名
|
||||
if (config.blockTags[node.name]) node.name = 'div';
|
||||
else if (!config.trustTags[node.name]) node.name = 'span';
|
||||
// 空白符处理
|
||||
if (node.pre) {
|
||||
this._whiteSpace = false;
|
||||
node.pre = undefined;
|
||||
for (var i = 0; i < this._STACK.length; i++)
|
||||
if (this._STACK[i].pre)
|
||||
this._whiteSpace = true;
|
||||
}
|
||||
// 处理表格的边框
|
||||
if (node.name == 'table') {
|
||||
if (node.attrs.border)
|
||||
node.attrs.style = "border:" + node.attrs.border + "px solid gray;" + (node.attrs.style || '');
|
||||
if (node.attrs.hasOwnProperty("cellspacing"))
|
||||
node.attrs.style = "border-spacing:" + node.attrs.cellspacing + "px;" + (node.attrs.style || '');
|
||||
|
||||
function setBorder(elem) {
|
||||
if (elem.name == 'th' || elem.name == 'td') {
|
||||
if (node.attrs.border)
|
||||
elem.attrs.style = "border:" + node.attrs.border + "px solid gray;" + (elem.attrs.style || '');
|
||||
if (node.attrs.hasOwnProperty("cellpadding"))
|
||||
elem.attrs.style = "padding:" + node.attrs.cellpadding + "px;" + (elem.attrs.style || '');
|
||||
return;
|
||||
}
|
||||
if (elem.type == 'text') return;
|
||||
for (var i = 0; i < elem.children.length; i++)
|
||||
setBorder(elem.children[i]);
|
||||
}
|
||||
if (node.attrs.border || node.attrs.hasOwnProperty("cellpadding"))
|
||||
for (var i = 0; i < node.children.length; i++)
|
||||
setBorder(node.children[i]);
|
||||
}
|
||||
// 合并一些不必要的层,减小节点深度
|
||||
if (node.children.length == 1 && node.name == "div" && node.children[0].name == "div") {
|
||||
var child = node.children[0];
|
||||
node.attrs.style = node.attrs.style || '';
|
||||
child.attrs.style = child.attrs.style || '';
|
||||
if (node.attrs.style.includes("padding") && (node.attrs.style.includes("margin") || child.attrs.style.includes(
|
||||
"margin")) && node.attrs.style.includes("display") && child.attrs.style.includes("display") && !(node.attrs.id &&
|
||||
node.attrs.id) && !(node.attrs.class && child.attrs.class)) {
|
||||
if (child.attrs.style.includes("padding"))
|
||||
child.attrs.style = "box-sizing:border-box;" + child.attrs.style;
|
||||
node.attrs.style = node.attrs.style + ";" + child.attrs.style;
|
||||
node.attrs.id = (child.attrs.id || '') + (node.attrs.id || '');
|
||||
node.attrs.class = (child.attrs.class || '') + (node.attrs.class || '');
|
||||
node.children = child.children;
|
||||
}
|
||||
}
|
||||
// 多层样式处理
|
||||
if (this.CssHandler.pop)
|
||||
this.CssHandler.pop(node);
|
||||
};
|
||||
// 工具函数
|
||||
checkClose() {
|
||||
if (this.data[this._i] == '>' || (this.data[this._i] == '/' && this.data[this._i + 1] == '>'))
|
||||
return true;
|
||||
return false;
|
||||
};
|
||||
getSelection(trim) {
|
||||
var str = (this._sectionStart == this._i ? '' : this.data.substring(this._sectionStart, this._i));
|
||||
while (trim && isBlankChar(this.data[++this._i]));
|
||||
if (trim) this._i--;
|
||||
this._sectionStart = this._i + 1;
|
||||
return str;
|
||||
};
|
||||
// 状态机
|
||||
Text(c) {
|
||||
if (c == '<') {
|
||||
var next = this.data[this._i + 1];
|
||||
if ((next >= 'a' && next <= 'z') || (next >= 'A' && next <= 'Z')) {
|
||||
this.setText();
|
||||
this._state = this.TagName;
|
||||
} else if (next == '/') {
|
||||
this.setText();
|
||||
this._i++;
|
||||
next = this.data[this._i + 1];
|
||||
if ((next >= 'a' && next <= 'z') || (next >= 'A' && next <= 'Z')) {
|
||||
this._sectionStart = this._i + 1;
|
||||
this._state = this.EndTag;
|
||||
} else
|
||||
this._state = this.Comment;
|
||||
} else if (next == '!') {
|
||||
this.setText();
|
||||
this._state = this.Comment;
|
||||
}
|
||||
}
|
||||
};
|
||||
Comment() {
|
||||
if (this.data.substring(this._i + 1, this._i + 3) == "--" || this.data.substring(this._i + 1, this._i + 7) ==
|
||||
"[CDATA[") {
|
||||
this._i = this.data.indexOf("-->", this._i + 1);
|
||||
if (this._i == -1) return this._i = this.data.length;
|
||||
else this._i = this._i + 2;
|
||||
} else {
|
||||
this._i = this.data.indexOf(">", this._i + 1);
|
||||
if (this._i == -1) return this._i = this.data.length;
|
||||
}
|
||||
this._sectionStart = this._i + 1;
|
||||
this._state = this.Text;
|
||||
};
|
||||
TagName(c) {
|
||||
if (isBlankChar(c)) {
|
||||
this._tagName = this.getSelection(true);
|
||||
if (this.checkClose()) this.setNode();
|
||||
else this._state = this.AttrName;
|
||||
} else if (this.checkClose()) {
|
||||
this._tagName = this.getSelection();
|
||||
this.setNode();
|
||||
}
|
||||
};
|
||||
AttrName(c) {
|
||||
if (isBlankChar(c)) {
|
||||
this._attrName = this.getSelection(true).toLowerCase();
|
||||
if (this.data[this._i] == '=') {
|
||||
while (isBlankChar(this.data[++this._i]));
|
||||
this._sectionStart = this._i;
|
||||
this._i--;
|
||||
this._state = this.AttrValue;
|
||||
} else this.setAttr();
|
||||
} else if (c == '=') {
|
||||
this._attrName = this.getSelection().toLowerCase();
|
||||
while (isBlankChar(this.data[++this._i]));
|
||||
this._sectionStart = this._i;
|
||||
this._i--;
|
||||
this._state = this.AttrValue;
|
||||
} else if (this.checkClose()) {
|
||||
this._attrName = this.getSelection().toLowerCase();
|
||||
this.setAttr();
|
||||
}
|
||||
};
|
||||
AttrValue(c) {
|
||||
if (c == '"' || c == "'") {
|
||||
this._sectionStart++;
|
||||
if ((this._i = this.data.indexOf(c, this._i + 1)) == -1) return this._i = this.data.length;
|
||||
} else
|
||||
for (; !isBlankChar(this.data[this._i] && this.data[this._i] != '/' && this.data[this._i] != '>'); this._i++);
|
||||
this._attrValue = this.getSelection();
|
||||
while (this._attrValue.includes(""")) this._attrValue = this._attrValue.replace(""", '');
|
||||
this.setAttr();
|
||||
};
|
||||
EndTag(c) {
|
||||
if (isBlankChar(c) || c == '>' || c == '/') {
|
||||
var name = this.getSelection().toLowerCase();
|
||||
var flag = false;
|
||||
for (var i = this._STACK.length - 1; i >= 0; i--)
|
||||
if (this._STACK[i].name == name) {
|
||||
flag = true;
|
||||
break;
|
||||
}
|
||||
if (flag) {
|
||||
var node;
|
||||
while (flag) {
|
||||
node = this._STACK.pop();
|
||||
if (node.name == name) flag = false;
|
||||
this.popNode(node);
|
||||
}
|
||||
} else if (name == 'p' || name == "br") {
|
||||
var slibings = this._STACK.length ? this._STACK[this._STACK.length - 1].children : this.DOM;
|
||||
var node = {
|
||||
name
|
||||
}
|
||||
slibings.push(node);
|
||||
}
|
||||
this._i = this.data.indexOf('>', this._i);
|
||||
if (this._i == -1) this._i = this.data.length;
|
||||
else this._state = this.Text;
|
||||
}
|
||||
};
|
||||
};
|
||||
module.exports = {
|
||||
parseHtml: (data, options) => new Promise((resolve) => new MpHtmlParser(data, options, resolve).parse()),
|
||||
parseHtmlSync: (data, options) => new MpHtmlParser(data, options).parse()
|
||||
};
|
||||
247
uniapp/uni-app/components/jyf-Parser/libs/config.js
Normal file
247
uniapp/uni-app/components/jyf-Parser/libs/config.js
Normal file
@@ -0,0 +1,247 @@
|
||||
// <<<<<<< HEAD
|
||||
/* 配置文件 */
|
||||
// =======
|
||||
/* 配置文件 xxx*/
|
||||
// >>>>>>> 53c74b30a29ef2e569158438db4f5df4b7480643
|
||||
function makeMap(str) {
|
||||
var map = Object.create(null),
|
||||
list = str.split(',');
|
||||
for (var item of list)
|
||||
map[item] = true;
|
||||
return map;
|
||||
}
|
||||
// 信任的属性列表,不在列表中的属性将被移除
|
||||
const trustAttrs = makeMap(
|
||||
"align,alt,app-id,appId,"
|
||||
// #ifdef MP-BAIDU
|
||||
+
|
||||
"appid,apid,"
|
||||
// #endif
|
||||
+
|
||||
"author,autoplay,border,cellpadding,cellspacing,class,color,colspan,controls,data-src,dir,face,height,href,id,ignore,loop,muted,name,path,poster,rowspan,size,span,src,start,style,type,lbType,lbtype,"
|
||||
// #ifdef MP-WEIXIN || MP-QQ
|
||||
+
|
||||
"unit-id,unitId,"
|
||||
// #endif
|
||||
+
|
||||
"width,xmlns"
|
||||
);
|
||||
// 信任的标签,将保持标签名不变
|
||||
const trustTags = makeMap(
|
||||
"a,abbr,ad,audio,b,blockquote,br,code,col,colgroup,dd,del,dl,dt,div,em,fieldset,h1,h2,h3,h4,h5,h6,hr,i,img,ins,label,legend,li,ol,p,q,source,span,strong,sub,sup,table,tbody,td,tfoot,th,thead,tr,title,u,ul,video,iframe"
|
||||
);
|
||||
// 块级标签,将被转为 div
|
||||
const blockTags = makeMap("address,article,aside,body,center,cite,footer,header,html,nav,pre,section");
|
||||
// 被移除的标签(其中 svg 系列标签会被转为图片)
|
||||
const ignoreTags = makeMap(
|
||||
"area,base,basefont,canvas,circle,command,ellipse,embed,frame,head,input,isindex,keygen,line,link,map,meta,param,path,polygon,rect,script,source,svg,textarea,track,use,wbr,"
|
||||
);
|
||||
// 只能用 rich-text 显示的标签(其中图片不能预览、不能显示视频、音频等)
|
||||
const richOnlyTags = makeMap(
|
||||
"a,ad,audio,colgroup,fieldset,legend,li,ol,sub,sup,table,tbody,td,tfoot,th,thead,tr,ul,video,iframe,");
|
||||
// 自闭合标签
|
||||
const selfClosingTags = makeMap(
|
||||
"area,base,basefont,br,col,circle,ellipse,embed,frame,hr,img,input,isindex,keygen,line,link,meta,param,path,polygon,rect,source,track,use,wbr,"
|
||||
);
|
||||
// 默认的标签样式
|
||||
var userAgentStyles = {
|
||||
a: "color:#366092;word-break:break-all;padding:1.5px 0 1.5px 0",
|
||||
address: "font-style:italic",
|
||||
blockquote: "background-color:#f6f6f6;border-left:3px solid #dbdbdb;color:#6c6c6c;padding:5px 0 5px 10px",
|
||||
center: "text-align:center",
|
||||
cite: "font-style:italic",
|
||||
code: "padding:0 1px 0 1px;margin-left:2px;margin-right:2px;background-color:#f8f8f8;border-radius:3px",
|
||||
dd: "margin-left:40px",
|
||||
img: "max-width:100%",
|
||||
mark: "background-color:yellow",
|
||||
pre: "font-family:monospace;white-space:pre;overflow:scroll",
|
||||
s: "text-decoration:line-through",
|
||||
u: "text-decoration:underline"
|
||||
};
|
||||
// #ifndef MP-ALIPAY || H5
|
||||
const SDKVersion = uni.getSystemInfoSync().SDKVersion;
|
||||
|
||||
function versionHigherThan(version = '') {
|
||||
var v1 = SDKVersion.split('.'),
|
||||
v2 = version.split('.');
|
||||
while (v1.length != v2.length)
|
||||
v1.length < v2.length ? v1.push('0') : v2.push('0');
|
||||
for (var i = 0; i < v1.length; i++) {
|
||||
if (v1[i] == v2[i]) continue;
|
||||
if (parseInt(v1[i]) > parseInt(v2[i])) return true;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
// #endif
|
||||
// #ifdef MP-WEIXIN || MP-QQ
|
||||
// 版本兼容
|
||||
if (versionHigherThan("2.7.1")) {
|
||||
trustTags.bdi = true;
|
||||
trustTags.bdo = true;
|
||||
trustTags.caption = true;
|
||||
trustTags.rt = true;
|
||||
trustTags.ruby = true;
|
||||
ignoreTags.rp = true;
|
||||
trustTags.big = true;
|
||||
trustTags.small = true;
|
||||
trustTags.pre = true;
|
||||
trustTags.iframe = true;
|
||||
richOnlyTags.bdi = true;
|
||||
richOnlyTags.bdo = true;
|
||||
richOnlyTags.caption = true;
|
||||
richOnlyTags.rt = true;
|
||||
richOnlyTags.ruby = true;
|
||||
richOnlyTags.pre = true;
|
||||
blockTags.pre = undefined;
|
||||
} else {
|
||||
blockTags.caption = true;
|
||||
userAgentStyles.big = "display:inline;font-size:1.2em";
|
||||
userAgentStyles.small = "display:inline;font-size:0.8em";
|
||||
}
|
||||
// #endif
|
||||
function bubbling(Parser) {
|
||||
for (var i = Parser._STACK.length - 1; i >= 0; i--) {
|
||||
if (!richOnlyTags[Parser._STACK[i].name])
|
||||
Parser._STACK[i].c = 1;
|
||||
else return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
module.exports = {
|
||||
// 高亮处理函数
|
||||
highlight: null,
|
||||
// 处理标签的属性,需要通过组件递归方式显示的标签需要调用 bubbling(Parser)
|
||||
LabelAttrsHandler(node, Parser) {
|
||||
node.attrs.style = Parser.CssHandler.match(node.name, node.attrs, node) + (node.attrs.style || '');
|
||||
switch (node.name) {
|
||||
case "ul":
|
||||
case "ol":
|
||||
case "li":
|
||||
case "dd":
|
||||
case "dl":
|
||||
case "dt":
|
||||
case "div":
|
||||
case "span":
|
||||
case "em":
|
||||
case 'p':
|
||||
let default_p_style = "max-width: 100% !important;display:block;"
|
||||
if (node.attrs.style) {
|
||||
node.attrs.style = node.attrs.style.includes('width:') ? default_p_style : node.attrs.style + default_p_style
|
||||
}
|
||||
if (node.attrs.align) {
|
||||
node.attrs.style = "text-align:" + node.attrs.align + ';' + node.attrs.style;
|
||||
node.attrs.align = undefined;
|
||||
}
|
||||
break;
|
||||
case "img":
|
||||
if (node.attrs.height) {
|
||||
node.attrs.height = 'auto'
|
||||
}
|
||||
let default_style = "max-width: 100% !important;display:block;"
|
||||
if (node.attrs.style) {
|
||||
node.attrs.style = node.attrs.style.includes('height:') ? default_style : node.attrs.style + default_style
|
||||
}
|
||||
if (node.attrs["data-src"]) {
|
||||
node.attrs.src = node.attrs.src || node.attrs["data-src"];
|
||||
node.attrs["data-src"] = undefined;
|
||||
}
|
||||
// #ifdef MP-BAIDU || MP-TOUTIAO
|
||||
if (Parser._imgMode == "widthFix") node.attrs.style = node.attrs.style + ";height:auto !important;";
|
||||
// #endif
|
||||
if (node.attrs.src) {
|
||||
if (!node.attrs.ignore) {
|
||||
if (bubbling(Parser)) node.attrs.i = (Parser._imgNum++).toString();
|
||||
else node.attrs.ignore = "true";
|
||||
}
|
||||
if (Parser._domain && node.attrs.src[0] == '/') {
|
||||
if (node.attrs.src[1] == '/') node.attrs.src = Parser._protocol + ":" + node.attrs.src;
|
||||
else node.attrs.src = Parser._domain + node.attrs.src;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'a':
|
||||
case "ad":
|
||||
bubbling(Parser);
|
||||
break;
|
||||
case "font":
|
||||
if (node.attrs.color) {
|
||||
node.attrs.style = "color:" + node.attrs.color + ';' + node.attrs.style;
|
||||
node.attrs.color = undefined;
|
||||
}
|
||||
if (node.attrs.face) {
|
||||
node.attrs.style = "font-family:" + node.attrs.face + ';' + node.attrs.style;
|
||||
node.attrs.face = undefined;
|
||||
}
|
||||
if (node.attrs.size) {
|
||||
var size = parseInt(node.attrs.size);
|
||||
if (size < 1) size = 1;
|
||||
else if (size > 7) size = 7;
|
||||
var map = ["xx-small", "x-small", "small", "medium", "large", "x-large", "xx-large"];
|
||||
node.attrs.style = "font-size:" + map[size - 1] + ';' + node.attrs.style;
|
||||
node.attrs.size = undefined;
|
||||
}
|
||||
break;
|
||||
case 'iframe':
|
||||
case "video":
|
||||
case "audio":
|
||||
node.attrs.loop = node.attrs.hasOwnProperty('loop') || false;
|
||||
node.attrs.controls = node.attrs.hasOwnProperty(
|
||||
'controls') || true;
|
||||
node.attrs.autoplay = node.attrs.hasOwnProperty('autoplay') || false;
|
||||
if (node.attrs.id) Parser['_' + node.name + "Num"]++;
|
||||
else node.attrs.id = (node.name + (++Parser['_' + node.name + "Num"]));
|
||||
if (node.name == "video") {
|
||||
node.attrs.style = node.attrs.style || '';
|
||||
if (node.attrs.width) {
|
||||
node.attrs.style = "width:" + parseFloat(node.attrs.width) + (node.attrs.height.includes('%') ? '%' : "px") +
|
||||
';' + node.attrs.style;
|
||||
node.attrs.width = undefined;
|
||||
}
|
||||
if (node.attrs.height) {
|
||||
node.attrs.style = "height:" + parseFloat(node.attrs.height) + (node.attrs.height.includes('%') ? '%' : "px") +
|
||||
';' + node.attrs.style;
|
||||
node.attrs.height = undefined;
|
||||
}
|
||||
if (Parser._videoNum > 3) node.lazyLoad = true;
|
||||
}
|
||||
// 新增iframe【create_by_xx】
|
||||
if (node.name == 'iframe') {
|
||||
// console.log(node.attrs, "====iframe attrs");
|
||||
}
|
||||
node.attrs.source = [];
|
||||
if (node.attrs.src) node.attrs.source.push(node.attrs.src);
|
||||
if (!node.attrs.controls && !node.attrs.autoplay)
|
||||
console.warn("存在没有controls属性的 " + node.name + " 标签,可能导致无法播放", node);
|
||||
bubbling(Parser);
|
||||
break;
|
||||
case "source":
|
||||
var parent = Parser._STACK[Parser._STACK.length - 1];
|
||||
if (parent && (parent.name == "video" || parent.name == "audio")) {
|
||||
parent.attrs.source.push(node.attrs.src);
|
||||
if (!parent.attrs.src) parent.attrs.src = node.attrs.src;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (Parser._domain && node.attrs.style.includes("url"))
|
||||
node.attrs.style = node.attrs.style.replace(/url\s*\(['"\s]*(\S*?)['"\s]*\)/, function() {
|
||||
var src = arguments[1];
|
||||
if (src && src[0] == '/') {
|
||||
if (src[1] == '/') return "url(" + Parser._protocol + ':' + src + ')';
|
||||
else return "url(" + Parser._domain + src + ')';
|
||||
} else return arguments[0];
|
||||
})
|
||||
if (!node.attrs.style) node.attrs.style = undefined;
|
||||
if (Parser._useAnchor && node.attrs.id) bubbling(Parser);
|
||||
},
|
||||
trustAttrs,
|
||||
trustTags,
|
||||
blockTags,
|
||||
ignoreTags,
|
||||
selfClosingTags,
|
||||
userAgentStyles,
|
||||
// #ifndef MP-ALIPAY || H5
|
||||
versionHigherThan,
|
||||
// #endif
|
||||
makeMap
|
||||
}
|
||||
392
uniapp/uni-app/components/jyf-Parser/trees.vue
Normal file
392
uniapp/uni-app/components/jyf-Parser/trees.vue
Normal file
@@ -0,0 +1,392 @@
|
||||
<!--
|
||||
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;">
|
||||
<block v-for="(item, index) in nodes" v-bind:key="index">
|
||||
<!--#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" :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="''+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>
|
||||
Reference in New Issue
Block a user