123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405 |
- <template>
- <view>
- <!--#ifdef H5-->
- <slot v-if="!html"></slot>
- <iframe id="contain" :style="'width:100%;'+(selectable?'user-select:text;-webkit-user-select:text':'')+(showWithAnimation?('opacity:0;'+showAnimation):'')"
- frameborder="0"></iframe>
- <!--#endif-->
- <!--#ifndef H5-->
- <slot v-if="!(html.nodes||((html&&(html[0].name||html[0].type))?1:nodes.length))"></slot>
- <!--#endif-->
- <!--#ifdef MP-ALIPAY || H5-->
- <view class="contain" :style="(showWithAnimation?'opacity:0;':'')+(selectable?'user-select:text;-webkit-user-select:text':'')"
- :animation="showAnimation">
- <trees :nodes="html.nodes||((html&&(html[0].name||html[0].type))?html:nodes)" :imgMode="imgMode" />
- </view>
- <!--#endif-->
- <!--#ifndef MP-ALIPAY || H5-->
- <trees class="contain" :style="'display:block'+(showWithAnimation?'opacity:0;':'')+(selectable?'user-select:text;-webkit-user-select:text':'')"
- :animation="showAnimation" :nodes="html.nodes||((html[0].name||html[0].type)?html:nodes)" :imgMode="imgMode"
- :lazyLoad="lazyLoad" :loadVideo="loadVideo" />
- <!--#endif-->
- </view>
- </template>
- <script>
- import trees from "./trees"
- const html2nodes = require("./Parser.js");
- // #ifdef MP-WEIXIN || MP-QQ
- const CanIUseObserver = require("./api.js").versionHigherThan('1.9.3');
- // #endif
- // #ifdef APP-PLUS
- const CanIUseObserver = true;
- // #endif
- var Document; // 使用document补丁包时将此句改为 const Document = require('./document.js');
- export default {
- name: 'parser',
- data() {
- return {
- nodes: [],
- showAnimation: {},
- // #ifdef APP-PLUS
- loadVideo: false,
- // #endif
- }
- },
- components: {
- trees
- },
- props: {
- 'html': {
- type: null,
- default: ''
- },
- '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: ''
- },
- 'imgMode': {
- type: String,
- default: 'default'
- },
- // #ifdef MP-WEIXIN || MP-QQ || APP-PLUS
- 'lazyLoad': {
- type: Boolean,
- default: false
- },
- // #endif
- 'selectable': {
- type: Boolean,
- default: false
- },
- 'tagStyle': {
- type: Object,
- default: () => {
- return {};
- }
- },
- 'showWithAnimation': {
- type: Boolean,
- default: false
- },
- 'animationDuration': {
- type: Number,
- default: 400
- },
- 'useAnchor': {
- type: Boolean,
- default: false
- }
- },
- mounted() {
- this.execHtml(this.html);
- // #ifndef MP-ALIPAY || H5
- this.videoContext = [];
- // #endif
- // #ifdef MP-BAIDU || MP-ALIPAY
- this.anchors = [];
- // #endif
- },
- methods: {
- execHtml(html) {
- // #ifdef H5
- var iframe = document.getElementById("contain");
- // 支持 iframe.srcdoc
- if (typeof(iframe.srcdoc) == "string") {
- var script =
- '<script>"use strict";function calcPageHeight(t){var e=Math.max(t.body.clientHeight,t.documentElement.clientHeight),n=Math.max(t.body.scrollHeight,t.documentElement.scrollHeight);return Math.max(e,n)}document.addEventListener("DOMContentLoaded",function(){for(var t=document.getElementsByTagName("img"),e=[],n=0;n<t.length;n++){var r=t[n];r.style+=";max-width:100%",e.push(r.src),r.index=n,"A"!=r.parentElement.nodeName&&(r.onclick=function(){parent.document.previewEvent(this,e)}),r.onerror=function(){parent.document.errorEvent(this,"img")};var o=document.getElementsByTagName("a"),a=!0,i=!1,c=void 0;try{for(var u,l=o[Symbol.iterator]();!(a=(u=l.next()).done);a=!0){u.value.onclick=function(t){if("#"==this.getAttribute("href")[0]){var e=document.getElementById(this.getAttribute("href").substring(1));return parent.document.tapEvent(this,e?e.offsetTop:-1)}return parent.document.tapEvent(this)}}}catch(t){i=!0,c=t}finally{try{!a&&l.return&&l.return()}finally{if(i)throw c}}var d=document.getElementsByTagName("video"),m=!0,h=!1,s=void 0;try{for(var v,y=d[Symbol.iterator]();!(m=(v=y.next()).done);m=!0){var f=v.value;f.style+=";max-width:100%",f.onerror=function(){parent.document.errorEvent(this,"video")},f.onplay=function(){parent.document.playEvent(this)}}}catch(t){h=!0,s=t}finally{try{!m&&y.return&&y.return()}finally{if(h)throw s}}parent.document.setVideoContext(d);var g=document.getElementsByTagName("audios"),p=!0,E=!1,x=void 0;try{for(var b,w=g[Symbol.iterator]();!(p=(b=w.next()).done);p=!0){b.value.onerror=function(t){parent.document.errorEvent(this,"audio")}}}catch(t){E=!0,x=t}finally{try{!p&&w.return&&w.return()}finally{if(E)throw x}}}},!1),window.onload=function(){var t=calcPageHeight(document);parent.document.getElementById("contain").style.height=t+"px",parent.document.setTitle(document.title)};<\/script>';
- if (!html) return;
- if (typeof html != 'string') {
- if (typeof html == 'object') {
- var str = "";
- for (var node of (html.nodes || html))
- str += this.Dom2Str(node);
- html = str;
- } else {
- this.$emit('error', {
- source: "parse",
- errMsg: "传入的html格式不正确!"
- });
- return;
- }
- }
- // 处理 rpx
- if (/[0-9.]*?rpx/.test(html)) {
- var rpx = uni.getSystemInfoSync().screenWidth / 750;
- html = html.replace(/([0-9.]*?)rpx/g, function() {
- return parseFloat(arguments[1]) * rpx + "px";
- })
- }
- document.previewEvent = (img, imgList) => {
- if (!img.hasAttribute('ignore')) {
- var preview = true;
- img.ignore = () => preview = false;
- this.$emit('imgtap', img);
- if (preview && this.autopreview) {
- uni.previewImage({
- current: img.index,
- urls: imgList
- });
- }
- }
- }
- document.tapEvent = (link, offsetTop) => {
- var jump = true;
- this.$emit('linkpress', {
- href: link.getAttribute("href"),
- ignore: () => jump = false
- });
- if (jump && link.getAttribute("href")) {
- if (link.getAttribute("href")[0] == '#') {
- if (this.useAnchor)
- window.scrollTo(0, iframe.offsetTop + offsetTop);
- } else if (/^http/.test(link.getAttribute("href"))) {
- if (this.autocopy)
- window.location.href = link.href;
- } else {
- uni.navigateTo({
- url: link.getAttribute("href")
- })
- }
- }
- return false;
- }
- document.setTitle = (title) => {
- if (title && this.autosetTitle) {
- uni.setNavigationBarTitle({
- title: title
- })
- }
- if (html)
- uni.createSelectorQuery().in(this).select("#contain").boundingClientRect(res => {
- this.$emit('ready', res);
- }).exec()
- }
- document.errorEvent = (target, source) => {
- this.$emit('error', {
- source,
- target
- });
- }
- document.setVideoContext = (videos) => {
- this.videoContext = videos;
- }
- document.playEvent = (v) => {
- if (this.autopause) {
- for (var video of this.videoContext) {
- if (video != v)
- video.pause();
- }
- }
- }
- iframe.srcdoc = script + html;
- this.showAnimation =
- "opacity: 1; transition: opacity 400ms ease 0ms, -webkit-transform 400ms ease 0ms, transform 400ms ease 0ms; transform-origin: 50% 50% 0px;";
- return;
- }
- // #endif
- let showAnimation = {};
- if (this.showWithAnimation) {
- showAnimation = uni.createAnimation({
- duration: this.animationDuration,
- timingFunction: "ease"
- }).opacity(1).step().export();
- }
- if (!html) {
- this.nodes = [];
- } else if (typeof html == 'string') {
- html2nodes(html, this).then(res => {
- // #ifdef APP-PLUS
- this.loadVideo = false;
- // #endif
- this.nodes = res.nodes;
- this.showAnimation = showAnimation;
- this.imgList = res.imgList;
- if (Document) this.document = new Document("nodes", res.nodes, this);
- if (res.title && this.autosetTitle) {
- uni.setNavigationBarTitle({
- title: res.title
- })
- }
- this.$emit('parser', res);
- this.ready();
- }).catch(err => {
- this.$emit('error', {
- source: "parse",
- errMsg: err
- });
- })
- } else if (html.constructor == Array) {
- this.showAnimation = showAnimation;
- this.imgList = [];
- // #ifdef APP-PLUS
- this.loadVideo = false;
- // #endif
- if (Document) this.document = new Document("html", html, this);
- this.ready();
- } else if (typeof html == 'object') {
- if (!html.nodes || html.nodes.constructor != Array) {
- if ((html.name && html.children && html.attrs) || (html.type == "text"))
- return;
- this.$emit('error', {
- source: "parse",
- errMsg: "传入的nodes数组格式不正确!应该传入的类型是array,实际传入的类型是:" + typeof html.nodes
- });
- return;
- }
- this.showAnimation = showAnimation;
- this.imgList = html.imgList || [];
- // #ifdef APP-PLUS
- this.loadVideo = false;
- // #endif
- if (Document) this.document = new Document("html.nodes", html.nodes, this);
- if (html.title && this.autosetTitle)
- uni.setNavigationBarTitle({
- title: html.title
- })
- this.ready();
- } else {
- this.$emit('error', {
- source: "parse",
- errMsg: "错误的html类型:" + typeof html
- });
- }
- },
- // #ifdef H5
- Dom2Str(node) {
- if (node.type == "text")
- return node.text;
- var elem = '<' + node.name;
- for (var attr in node.attrs)
- elem += (' ' + atts + '="' + node.attrs[attr] + '"');
- elem += ">";
- for (var child of node.children)
- elem += Dom2Str(child);
- elem += ("</" + node.name + ">");
- return elem;
- },
- // #endif
- // #ifndef H5
- getContext(components) {
- for (let component of components) {
- let observered = false;
- if (!component.nodes)
- return this.getContext(component.$children);
- for (let item of component.nodes) {
- // #ifndef MP-ALIPAY
- if (item.name == 'img' && !observered) {
- observered = true;
- if (component.lazyLoad && CanIUseObserver) {
- 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;
- } else if (item.name == 'video') {
- this.videoContext.push({
- id: item.attrs.id,
- context: uni.createVideoContext(item.attrs.id, component)
- });
- }
- // #endif
- // #ifdef MP-BAIDU || MP-ALIPAY
- if (item.attrs && item.attrs.id) {
- this.anchors.push({
- id: item.attrs.id,
- node: component
- })
- }
- // #endif
- }
- this.getContext(component.$children);
- }
- },
- // #endif
- ready() {
- this.$nextTick(() => {
- this.navigateTo = (obj) => {
- obj.success = obj.success || function() {};
- obj.fail = obj.fail || function() {};
- 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({
- errMsg: "Label Not Found"
- });
- 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);
- // #endif
- // #ifdef MP-BAIDU || MP-ALIPAY
- for (var anchor of this.anchors) {
- if (anchor.id == obj.id) {
- Scroll("#" + obj.id, anchor.node);
- }
- }
- // #endif
- }
- }
- uni.createSelectorQuery().in(this).select(".contain").boundingClientRect(res => {
- this.$emit("ready", res);
- }).exec()
- // #ifndef H5
- this.getContext(this.$children);
- // #endif
- // #ifdef APP-PLUS
- setTimeout(() => {
- this.loadVideo = true;
- }, 2000);
- // #endif
- })
- }
- },
- watch: {
- html(html) {
- this.execHtml(html);
- }
- }
- }
- </script>
- <style>
- /* #ifndef MP-BAIDU */
- :host {
- display: block;
- overflow: scroll;
- -webkit-overflow-scrolling: touch;
- }
- /* #endif */
- </style>
|