From d8b41fff43a2cee6a8f714ffa807623b15803786 Mon Sep 17 00:00:00 2001 From: quanyawei <401863037@qq.com> Date: Fri, 20 Oct 2023 15:21:35 +0800 Subject: [PATCH] fix:立行立改Uniapp小程序新建项目 --- uni_modules/uview-ui/components/u-parse/u-parse.vue | 366 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 366 insertions(+), 0 deletions(-) diff --git a/uni_modules/uview-ui/components/u-parse/u-parse.vue b/uni_modules/uview-ui/components/u-parse/u-parse.vue new file mode 100644 index 0000000..7bc8b3d --- /dev/null +++ b/uni_modules/uview-ui/components/u-parse/u-parse.vue @@ -0,0 +1,366 @@ +<template> + <view id="_root" :class="(selectable?'_select ':'')+'_root'"> + <slot v-if="!nodes[0]" /> + <!-- #ifndef APP-PLUS-NVUE --> + <node v-else :childs="nodes" :opts="[lazyLoad,loadingImg,errorImg,showImgMenu]" /> + <!-- #endif --> + <!-- #ifdef APP-PLUS-NVUE --> + <web-view ref="web" src="/static/app-plus/mp-html/local.html" :style="'margin-top:-2px;height:' + height + 'px'" @onPostMessage="_onMessage" /> + <!-- #endif --> + </view> +</template> + +<script> + import props from './props.js'; +/** + * mp-html v2.0.4 + * @description ��������������� + * @tutorial https://github.com/jin-yufeng/mp-html + * @property {String} bgColor ���������������������������APP-PLUS-NVUE + * @property {String} content ������������������������������������������ true ��� + * @property {Boolean} copyLink ������������������������������������������������ + * @property {String} domain ������������������������������ + * @property {String} errorImg ��������������������������������� + * @property {Boolean} lazyLoad ������������������������������������ true ��� + * @property {string} loadingImg ��������������������������������������� + * @property {Boolean} pauseVideo ��������������������������������������������������������������� true ��� + * @property {Boolean} previewImg ��������������������������������������������������� true ��� + * @property {Boolean} scrollTable ��������������������������������������������������������������������� + * @property {Boolean} selectable ������������������������ + * @property {Boolean} setTitle ��������� title ��������������������������������������������� true ��� + * @property {Boolean} showImgMenu ��������������������������������������������������� true ��� + * @property {Object} tagStyle ��������������������� + * @property {Boolean | Number} useAnchor ������������������������ + * + * @event {Function} load dom ��������������������������� + * @event {Function} ready ��������������������������������� + * @event {Function} imgTap ������������������������ + * @event {Function} linkTap ������������������������ + * @event {Function} error ��������������������������� + */ +const plugins=[] +const parser = require('./parser') +// #ifndef APP-PLUS-NVUE +import node from './node/node' +// #endif +// #ifdef APP-PLUS-NVUE +const dom = weex.requireModule('dom') +// #endif +export default { + name: 'mp-html', + data() { + return { + nodes: [], + // #ifdef APP-PLUS-NVUE + height: 0 + // #endif + } + }, + mixins:[props], + // #ifndef APP-PLUS-NVUE + components: { + node + }, + // #endif + watch: { + content(content) { + this.setContent(content) + } + }, + created() { + this.plugins = [] + for (let i = plugins.length; i--;) + this.plugins.push(new plugins[i](this)) + }, + mounted() { + if (this.content && !this.nodes.length) + this.setContent(this.content) + }, + beforeDestroy() { + this._hook('onDetached') + clearInterval(this._timer) + }, + methods: { + /** + * @description ��������������������������������������� scroll-view ��� + * @param {Object} page scroll-view ��������������������� + * @param {String} selector scroll-view ������������ + * @param {String} scrollTop scroll-view scroll-top ������������������������ + */ + in(page, selector, scrollTop) { + // #ifndef APP-PLUS-NVUE + if (page && selector && scrollTop) + this._in = { + page, + selector, + scrollTop + } + // #endif + }, + + /** + * @description ������������ + * @param {String} id ������������������ id + * @param {Number} offset ������������������������ + * @returns {Promise} + */ + navigateTo(id, offset) { + return new Promise((resolve, reject) => { + if (!this.useAnchor) + return reject('Anchor is disabled') + offset = offset || parseInt(this.useAnchor) || 0 + // #ifdef APP-PLUS-NVUE + if (!id) { + dom.scrollToElement(this.$refs.web, { + offset + }) + resolve() + } else { + this._navigateTo = { + resolve, + reject, + offset + } + this.$refs.web.evalJs('uni.postMessage({data:{action:"getOffset",offset:(document.getElementById(' + id + ')||{}).offsetTop}})') + } + // #endif + // #ifndef APP-PLUS-NVUE + let deep = ' ' + // #ifdef MP-WEIXIN || MP-QQ || MP-TOUTIAO + deep = '>>>' + // #endif + const selector = uni.createSelectorQuery() + // #ifndef MP-ALIPAY + .in(this._in ? this._in.page : this) + // #endif + .select((this._in ? this._in.selector : '._root') + (id ? `${deep}#${id}` : '')).boundingClientRect() + if (this._in) + selector.select(this._in.selector).scrollOffset() + .select(this._in.selector).boundingClientRect() // ������ scroll-view ������������������������ + else + selector.selectViewport().scrollOffset() // ��������������������������� + selector.exec(res => { + if (!res[0]) + return reject('Label not found') + const scrollTop = res[1].scrollTop + res[0].top - (res[2] ? res[2].top : 0) + offset + if (this._in) + // scroll-view ������ + this._in.page[this._in.scrollTop] = scrollTop + else + // ������������ + uni.pageScrollTo({ + scrollTop, + duration: 300 + }) + resolve() + }) + // #endif + }) + }, + + /** + * @description ������������������ + * @return {String} + */ + getText() { + let text = ''; + (function traversal(nodes) { + for (let i = 0; i < nodes.length; i++) { + const node = nodes[i] + if (node.type == 'text') + text += node.text.replace(/&/g, '&') + else if (node.name == 'br') + text += '\n' + else { + // ��������������������������� + const isBlock = node.name == 'p' || node.name == 'div' || node.name == 'tr' || node.name == 'li' || (node.name[0] == 'h' && node.name[1] > '0' && node.name[1] < '7') + if (isBlock && text && text[text.length - 1] != '\n') + text += '\n' + // ������������������������������ + if (node.children) + traversal(node.children) + if (isBlock && text[text.length - 1] != '\n') + text += '\n' + else if (node.name == 'td' || node.name == 'th') + text += '\t' + } + } + })(this.nodes) + return text + }, + + /** + * @description ��������������������������� + * @return {Promise} + */ + getRect() { + return new Promise((resolve, reject) => { + uni.createSelectorQuery() + // #ifndef MP-ALIPAY + .in(this) + // #endif + .select('#_root').boundingClientRect().exec(res => res[0] ? resolve(res[0]) : reject('Root label not found')) + }) + }, + + /** + * @description ������������ + * @param {String} content html ������ + * @param {Boolean} append ��������������������� + */ + setContent(content, append) { + if (!append || !this.imgList) + this.imgList = [] + const nodes = new parser(this).parse(content) + // #ifdef APP-PLUS-NVUE + if (this._ready) + this._set(nodes, append) + // #endif + this.$set(this, 'nodes', append ? (this.nodes || []).concat(nodes) : nodes) + + // #ifndef APP-PLUS-NVUE + this._videos = [] + this.$nextTick(() => { + this._hook('onLoad') + this.$emit('load') + }) + + // ������������������������ + let height + clearInterval(this._timer) + this._timer = setInterval(() => { + this.getRect().then(rect => { + // 350ms ��������������������������� ready ������ + if (rect.height == height) { + this.$emit('ready', rect) + clearInterval(this._timer) + } + height = rect.height + }).catch(() => { }) + }, 350) + // #endif + }, + + /** + * @description ������������������������ + */ + _hook(name) { + for (let i = plugins.length; i--;) + if (this.plugins[i][name]) + this.plugins[i][name]() + }, + + // #ifdef APP-PLUS-NVUE + /** + * @description ������������ + */ + _set(nodes, append) { + this.$refs.web.evalJs('setContent(' + JSON.stringify(nodes) + ',' + JSON.stringify([this.bgColor, this.errorImg, this.loadingImg, this.pauseVideo, this.scrollTable, this.selectable]) + ',' + append + ')') + }, + + /** + * @description ��������� web-view ������ + */ + _onMessage(e) { + const message = e.detail.data[0] + switch (message.action) { + // web-view ��������������� + case 'onJSBridgeReady': + this._ready = true + if (this.nodes) + this._set(this.nodes) + break + // ������ dom ������������ + case 'onLoad': + this.height = message.height + this._hook('onLoad') + this.$emit('load') + break + // ������������������������ + case 'onReady': + this.getRect().then(res => { + this.$emit('ready', res) + }).catch(() => { }) + break + // ��������������������� + case 'onHeightChange': + this.height = message.height + break + // ������������ + case 'onImgTap': + this.$emit('imgTap', message.attrs) + if (this.previewImg) + uni.previewImage({ + current: parseInt(message.attrs.i), + urls: this.imgList + }) + break + // ������������ + case 'onLinkTap': + const href = message.attrs.href + this.$emit('linkTap', message.attrs) + if (href) { + // ������������ + if (href[0] == '#') { + if (this.useAnchor) + dom.scrollToElement(this.$refs.web, { + offset: message.offset + }) + } + // ������������ + else if (href.includes('://')) { + if (this.copyLink) + plus.runtime.openWeb(href) + } + else + uni.navigateTo({ + url: href, + fail() { + wx.switchTab({ + url: href + }) + } + }) + } + break + // ��������������������������� + case 'getOffset': + if (typeof message.offset == 'number') { + dom.scrollToElement(this.$refs.web, { + offset: message.offset + this._navigateTo.offset + }) + this._navigateTo.resolve() + } else + this._navigateTo.reject('Label not found') + break + // ������ + case 'onClick': + this.$emit('tap') + break + // ������ + case 'onError': + this.$emit('error', { + source: message.source, + attrs: message.attrs + }) + } + } + // #endif + } +} +</script> + +<style> +/* #ifndef APP-PLUS-NVUE */ +/* ��������������� */ +._root { + overflow: auto; + -webkit-overflow-scrolling: touch; +} + +/* ������������ */ +._select { + user-select: text; +} +/* #endif */ +</style> -- Gitblit v1.8.0