优化组件/更新
This commit is contained in:
@@ -2,7 +2,7 @@
|
||||
<view id="_root" :class="(selectable?'_select ':'')+'_root'" :style="containerStyle">
|
||||
<slot v-if="!nodes[0]" />
|
||||
<!-- #ifndef APP-PLUS-NVUE -->
|
||||
<node v-else :childs="nodes" :opts="[lazyLoad,loadingImg,errorImg,showImgMenu]" name="span" />
|
||||
<node v-else :childs="nodes" :opts="[lazyLoad,loadingImg,errorImg,showImgMenu,selectable]" name="span" />
|
||||
<!-- #endif -->
|
||||
<!-- #ifdef APP-PLUS-NVUE -->
|
||||
<web-view ref="web" src="/uni_modules/mp-html/static/app-plus/mp-html/local.html" :style="'margin-top:-2px;height:' + height + 'px'" @onPostMessage="_onMessage" />
|
||||
@@ -12,7 +12,7 @@
|
||||
|
||||
<script>
|
||||
/**
|
||||
* mp-html v2.3.0
|
||||
* mp-html v2.5.1
|
||||
* @description 富文本组件
|
||||
* @tutorial https://github.com/jin-yufeng/mp-html
|
||||
* @property {String} container-style 容器的样式
|
||||
@@ -128,7 +128,6 @@ export default {
|
||||
},
|
||||
beforeDestroy () {
|
||||
this._hook('onDetached')
|
||||
clearInterval(this._timer)
|
||||
},
|
||||
methods: {
|
||||
/**
|
||||
@@ -284,6 +283,28 @@ export default {
|
||||
// #endif
|
||||
},
|
||||
|
||||
/**
|
||||
* @description 设置媒体播放速率
|
||||
* @param {Number} rate 播放速率
|
||||
*/
|
||||
setPlaybackRate (rate) {
|
||||
this.playbackRate = rate
|
||||
for (let i = (this._videos || []).length; i--;) {
|
||||
this._videos[i].playbackRate(rate)
|
||||
}
|
||||
// #ifdef APP-PLUS
|
||||
const command = 'for(var e=document.getElementsByTagName("video"),i=e.length;i--;)e[i].playbackRate=' + rate
|
||||
// #ifndef APP-PLUS-NVUE
|
||||
let page = this.$parent
|
||||
while (!page.$scope) page = page.$parent
|
||||
page.$scope.$getAppWebview().evalJS(command)
|
||||
// #endif
|
||||
// #ifdef APP-PLUS-NVUE
|
||||
this.$refs.web.evalJs(command)
|
||||
// #endif
|
||||
// #endif
|
||||
},
|
||||
|
||||
/**
|
||||
* @description 设置内容
|
||||
* @param {String} content html 内容
|
||||
@@ -308,19 +329,32 @@ export default {
|
||||
this.$emit('load')
|
||||
})
|
||||
|
||||
// 等待图片加载完毕
|
||||
let height
|
||||
clearInterval(this._timer)
|
||||
this._timer = setInterval(() => {
|
||||
this.getRect().then(rect => {
|
||||
if (this.lazyLoad || this.imgList._unloadimgs < this.imgList.length / 2) {
|
||||
// 设置懒加载,每 350ms 获取高度,不变则认为加载完毕
|
||||
let height = 0
|
||||
const callback = rect => {
|
||||
if (!rect || !rect.height) rect = {}
|
||||
// 350ms 总高度无变化就触发 ready 事件
|
||||
if (rect.height === height) {
|
||||
this.$emit('ready', rect)
|
||||
clearInterval(this._timer)
|
||||
} else {
|
||||
height = rect.height
|
||||
setTimeout(() => {
|
||||
this.getRect().then(callback).catch(callback)
|
||||
}, 350)
|
||||
}
|
||||
height = rect.height
|
||||
}).catch(() => { })
|
||||
}, 350)
|
||||
}
|
||||
this.getRect().then(callback).catch(callback)
|
||||
} else {
|
||||
// 未设置懒加载,等待所有图片加载完毕
|
||||
if (!this.imgList._unloadimgs) {
|
||||
this.getRect().then(rect => {
|
||||
this.$emit('ready', rect)
|
||||
}).catch(() => {
|
||||
this.$emit('ready', {})
|
||||
})
|
||||
}
|
||||
}
|
||||
// #endif
|
||||
},
|
||||
|
||||
@@ -340,7 +374,7 @@ export default {
|
||||
* @description 设置内容
|
||||
*/
|
||||
_set (nodes, append) {
|
||||
this.$refs.web.evalJs('setContent(' + JSON.stringify(nodes) + ',' + JSON.stringify([this.containerStyle.replace(/(?:margin|padding)[^;]+/g, ''), this.errorImg, this.loadingImg, this.pauseVideo, this.scrollTable, this.selectable]) + ',' + append + ')')
|
||||
this.$refs.web.evalJs('setContent(' + JSON.stringify(nodes).replace(/%22/g, '') + ',' + JSON.stringify([this.containerStyle.replace(/(?:margin|padding)[^;]+/g, ''), this.errorImg, this.loadingImg, this.pauseVideo, this.scrollTable, this.selectable]) + ',' + append + ')')
|
||||
},
|
||||
|
||||
/**
|
||||
@@ -366,7 +400,9 @@ export default {
|
||||
case 'onReady':
|
||||
this.getRect().then(res => {
|
||||
this.$emit('ready', res)
|
||||
}).catch(() => { })
|
||||
}).catch(() => {
|
||||
this.$emit('ready', {})
|
||||
})
|
||||
break
|
||||
// 总高度发生变化
|
||||
case 'onHeightChange':
|
||||
|
||||
@@ -3,20 +3,33 @@
|
||||
<block v-for="(n, i) in childs" v-bind:key="i">
|
||||
<!-- 图片 -->
|
||||
<!-- 占位图 -->
|
||||
<image v-if="n.name==='img'&&((opts[1]&&!ctrl[i])||ctrl[i]<0)" class="_img" :style="n.attrs.style" :src="ctrl[i]<0?opts[2]:opts[1]" mode="widthFix" />
|
||||
<image v-if="n.name==='img'&&!n.t&&((opts[1]&&!ctrl[i])||ctrl[i]<0)" class="_img" :style="n.attrs.style" :src="ctrl[i]<0?opts[2]:opts[1]" mode="widthFix" />
|
||||
<!-- 显示图片 -->
|
||||
<!-- #ifdef H5 || (APP-PLUS && VUE2) -->
|
||||
<img v-if="n.name==='img'" :id="n.attrs.id" :class="'_img '+n.attrs.class" :style="(ctrl[i]===-1?'display:none;':'')+n.attrs.style" :src="n.attrs.src||(ctrl.load?n.attrs['data-src']:'')" :data-i="i" @load="imgLoad" @error="mediaError" @tap.stop="imgTap" @longpress="imgLongTap" />
|
||||
<!-- #endif -->
|
||||
<!-- #ifndef H5 || APP-PLUS -->
|
||||
<image v-if="n.name==='img'" :id="n.attrs.id" :class="'_img '+n.attrs.class" :style="(ctrl[i]===-1?'display:none;':'')+'width:'+(ctrl[i]||1)+'px;height:1px;'+n.attrs.style" :src="n.attrs.src" :mode="!n.h?'widthFix':(!n.w?'heightFix':'')" :lazy-load="opts[0]" :webp="n.webp" :show-menu-by-longpress="opts[3]&&!n.attrs.ignore" :image-menu-prevent="!opts[3]||n.attrs.ignore" :data-i="i" @load="imgLoad" @error="mediaError" @tap.stop="imgTap" @longpress="imgLongTap" />
|
||||
<!-- #ifndef H5 || (APP-PLUS && VUE2) -->
|
||||
<!-- 表格中的图片,使用 rich-text 防止大小不正确 -->
|
||||
<rich-text v-if="n.name==='img'&&n.t" :style="'display:'+n.t" :nodes="[{attrs:{style:n.attrs.style||'',src:n.attrs.src},name:'img'}]" :data-i="i" @tap.stop="imgTap" />
|
||||
<!-- #endif -->
|
||||
<!-- #ifdef APP-HARMONY -->
|
||||
<image v-else-if="n.name==='img'" :id="n.attrs.id" :class="'_img '+n.attrs.class" :style="(ctrl[i]===-1?'display:none;':'')+'width:'+ctrl[i]+'px;'+n.attrs.style" :src="n.attrs.src||(ctrl.load?n.attrs['data-src']:'')" :mode="!n.h?'widthFix':(!n.w?'heightFix':(n.m||'scaleToFill'))" :data-i="i" @load="imgLoad" @error="mediaError" @tap.stop="imgTap" @longpress="imgLongTap" />
|
||||
<!-- #endif -->
|
||||
<!-- #ifndef H5 || APP-PLUS || MP-KUAISHOU -->
|
||||
<image v-else-if="n.name==='img'" :id="n.attrs.id" :class="'_img '+n.attrs.class" :style="(ctrl[i]===-1?'display:none;':'')+'width:'+(ctrl[i]||1)+'px;height:1px;'+n.attrs.style" :src="n.attrs.src" :mode="!n.h?'widthFix':(!n.w?'heightFix':(n.m||'scaleToFill'))" :lazy-load="opts[0]" :webp="n.webp" :show-menu-by-longpress="opts[3]&&!n.attrs.ignore" :image-menu-prevent="!opts[3]||n.attrs.ignore" :data-i="i" @load="imgLoad" @error="mediaError" @tap.stop="imgTap" @longpress="imgLongTap" />
|
||||
<!-- #endif -->
|
||||
<!-- #ifdef MP-KUAISHOU -->
|
||||
<image v-else-if="n.name==='img'" :id="n.attrs.id" :class="'_img '+n.attrs.class" :style="(ctrl[i]===-1?'display:none;':'')+n.attrs.style" :src="n.attrs.src" :lazy-load="opts[0]" :data-i="i" @load="imgLoad" @error="mediaError" @tap.stop="imgTap"></image>
|
||||
<!-- #endif -->
|
||||
<!-- #ifdef APP-PLUS && VUE3 -->
|
||||
<image v-if="n.name==='img'" :id="n.attrs.id" :class="'_img '+n.attrs.class" :style="(ctrl[i]===-1?'display:none;':'')+'width:'+(ctrl[i]||1)+'px;'+n.attrs.style" :src="n.attrs.src||(ctrl.load?n.attrs['data-src']:'')" :mode="!n.h?'widthFix':(!n.w?'heightFix':'')" :data-i="i" @load="imgLoad" @error="mediaError" @tap.stop="imgTap" @longpress="imgLongTap" />
|
||||
<image v-else-if="n.name==='img'" :id="n.attrs.id" :class="'_img '+n.attrs.class" :style="(ctrl[i]===-1?'display:none;':'')+'width:'+(ctrl[i]||1)+'px;'+n.attrs.style" :src="n.attrs.src||(ctrl.load?n.attrs['data-src']:'')" :mode="!n.h?'widthFix':(!n.w?'heightFix':(n.m||''))" :data-i="i" @load="imgLoad" @error="mediaError" @tap.stop="imgTap" @longpress="imgLongTap" />
|
||||
<!-- #endif -->
|
||||
<!-- 文本 -->
|
||||
<!-- #ifndef MP-BAIDU || MP-ALIPAY || MP-TOUTIAO -->
|
||||
<text v-else-if="n.text" :user-select="n.us" decode>{{n.text}}</text>
|
||||
<!-- #ifdef MP-WEIXIN -->
|
||||
<text v-else-if="n.text" :user-select="opts[4]=='force'&&isiOS" decode>{{n.text}}</text>
|
||||
<!-- #endif -->
|
||||
<!-- #ifndef MP-WEIXIN || MP-BAIDU || MP-ALIPAY || MP-TOUTIAO -->
|
||||
<text v-else-if="n.text" decode>{{n.text}}</text>
|
||||
<!-- #endif -->
|
||||
<text v-else-if="n.name==='br'">\n</text>
|
||||
<!-- 链接 -->
|
||||
@@ -25,7 +38,7 @@
|
||||
</view>
|
||||
<!-- 视频 -->
|
||||
<!-- #ifdef APP-PLUS -->
|
||||
<view v-else-if="n.html" :id="n.attrs.id" :class="'_video '+n.attrs.class" :style="n.attrs.style" v-html="n.html" @vplay.stop="play" />
|
||||
<view v-else-if="n.html" :id="n.attrs.id" :class="'_video '+n.attrs.class" :style="n.attrs.style" v-html="n.html" :data-i="i" @vplay.stop="play" />
|
||||
<!-- #endif -->
|
||||
<!-- #ifndef APP-PLUS -->
|
||||
<video v-else-if="n.name==='video'" :id="n.attrs.id" :class="n.attrs.class" :style="n.attrs.style" :autoplay="n.attrs.autoplay" :controls="n.attrs.controls" :loop="n.attrs.loop" :muted="n.attrs.muted" :object-fit="n.attrs['object-fit']" :poster="n.attrs.poster" :src="n.src[ctrl[i]||0]" :data-i="i" @play="play" @error="mediaError" />
|
||||
@@ -57,10 +70,10 @@
|
||||
|
||||
<!-- 富文本 -->
|
||||
<!-- #ifdef H5 || ((MP-WEIXIN || MP-QQ || APP-PLUS || MP-360) && VUE2) -->
|
||||
<rich-text v-else-if="!n.c&&!handler.isInline(n.name, n.attrs.style)" :id="n.attrs.id" :style="n.f" :nodes="[n]" />
|
||||
<rich-text v-else-if="!n.c&&!handler.isInline(n.name, n.attrs.style)" :id="n.attrs.id" :style="n.f" :user-select="opts[4]" :nodes="[n]" />
|
||||
<!-- #endif -->
|
||||
<!-- #ifndef H5 || ((MP-WEIXIN || MP-QQ || APP-PLUS || MP-360) && VUE2) -->
|
||||
<rich-text v-else-if="!n.c" :id="n.attrs.id" :style="n.f+';display:inline'" :preview="false" :nodes="[n]" />
|
||||
<rich-text v-else-if="!n.c" :id="n.attrs.id" :style="'display:inline;'+n.f" :preview="false" :selectable="opts[4]" :user-select="opts[4]" :nodes="[n]" />
|
||||
<!-- #endif -->
|
||||
<!-- 继续递归 -->
|
||||
<view v-else-if="n.c===2" :id="n.attrs.id" :class="'_block _'+n.name+' '+n.attrs.class" :style="n.f+';'+n.attrs.style">
|
||||
@@ -113,7 +126,10 @@ export default {
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
ctrl: {}
|
||||
ctrl: {},
|
||||
// #ifdef MP-WEIXIN
|
||||
isiOS: uni.getSystemInfoSync().system.includes('iOS')
|
||||
// #endif
|
||||
}
|
||||
},
|
||||
props: {
|
||||
@@ -129,7 +145,7 @@ export default {
|
||||
},
|
||||
components: {
|
||||
|
||||
// #ifndef H5 && VUE3
|
||||
// #ifndef ((H5 || APP-PLUS) && VUE3) || APP-HARMONY
|
||||
node
|
||||
// #endif
|
||||
},
|
||||
@@ -167,14 +183,22 @@ export default {
|
||||
},
|
||||
methods:{
|
||||
// #ifdef MP-WEIXIN
|
||||
toJSON () { },
|
||||
toJSON () { return this },
|
||||
// #endif
|
||||
/**
|
||||
* @description 播放视频事件
|
||||
* @param {Event} e
|
||||
*/
|
||||
play (e) {
|
||||
this.root.$emit('play')
|
||||
const i = e.currentTarget.dataset.i
|
||||
const node = this.childs[i]
|
||||
this.root.$emit('play', {
|
||||
source: node.name,
|
||||
attrs: {
|
||||
...node.attrs,
|
||||
src: node.src[this.ctrl[i] || 0]
|
||||
}
|
||||
})
|
||||
// #ifndef APP-PLUS
|
||||
if (this.root.pauseVideo) {
|
||||
let flag = false
|
||||
@@ -194,6 +218,9 @@ export default {
|
||||
// #endif
|
||||
)
|
||||
ctx.id = id
|
||||
if (this.root.playbackRate) {
|
||||
ctx.playbackRate(this.root.playbackRate)
|
||||
}
|
||||
this.root._videos.push(ctx)
|
||||
}
|
||||
}
|
||||
@@ -214,7 +241,14 @@ export default {
|
||||
// #ifdef H5 || APP-PLUS
|
||||
node.attrs.src = node.attrs.src || node.attrs['data-src']
|
||||
// #endif
|
||||
// #ifndef APP-HARMONY
|
||||
this.root.$emit('imgtap', node.attrs)
|
||||
// #endif
|
||||
// #ifdef APP-HARMONY
|
||||
this.root.$emit('imgtap', {
|
||||
...node.attrs
|
||||
})
|
||||
// #endif
|
||||
// 自动预览图片
|
||||
if (this.root.previewImg) {
|
||||
uni.previewImage({
|
||||
@@ -279,6 +313,25 @@ export default {
|
||||
// 加载完毕,取消加载中占位图
|
||||
this.$set(this.ctrl, i, 1)
|
||||
}
|
||||
this.checkReady()
|
||||
},
|
||||
|
||||
/**
|
||||
* @description 检查是否所有图片加载完毕
|
||||
*/
|
||||
checkReady () {
|
||||
if (this.root && !this.root.lazyLoad) {
|
||||
this.root._unloadimgs -= 1
|
||||
if (!this.root._unloadimgs) {
|
||||
setTimeout(() => {
|
||||
this.root.getRect().then(rect => {
|
||||
this.root.$emit('ready', rect)
|
||||
}).catch(() => {
|
||||
this.root.$emit('ready', {})
|
||||
})
|
||||
}, 350)
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
@@ -355,6 +408,7 @@ export default {
|
||||
if (this.opts[2]) {
|
||||
this.$set(this.ctrl, i, -1)
|
||||
}
|
||||
this.checkReady()
|
||||
}
|
||||
if (this.root) {
|
||||
this.root.$emit('error', {
|
||||
|
||||
@@ -71,16 +71,24 @@ const config = {
|
||||
viewbox: 'viewBox',
|
||||
attributename: 'attributeName',
|
||||
repeatcount: 'repeatCount',
|
||||
repeatdur: 'repeatDur'
|
||||
repeatdur: 'repeatDur',
|
||||
foreignobject: 'foreignObject'
|
||||
}
|
||||
}
|
||||
const tagSelector={}
|
||||
const {
|
||||
windowWidth,
|
||||
let windowWidth, system
|
||||
// #ifdef MP-WEIXIN
|
||||
if (uni.canIUse('getWindowInfo')) {
|
||||
windowWidth = uni.getWindowInfo().windowWidth
|
||||
system = uni.getDeviceInfo().system
|
||||
} else {
|
||||
// #endif
|
||||
const systemInfo = uni.getSystemInfoSync()
|
||||
windowWidth = systemInfo.windowWidth
|
||||
// #ifdef MP-WEIXIN
|
||||
system
|
||||
// #endif
|
||||
} = uni.getSystemInfoSync()
|
||||
system = systemInfo.system
|
||||
}
|
||||
// #endif
|
||||
const blankChar = makeMap(' ,\r,\n,\t,\f')
|
||||
let idIndex = 0
|
||||
|
||||
@@ -138,6 +146,26 @@ function decodeEntity (str, amp) {
|
||||
return str
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 合并多个块级标签,加快长内容渲染
|
||||
* @param {Array} nodes 要合并的标签数组
|
||||
*/
|
||||
function mergeNodes (nodes) {
|
||||
let i = nodes.length - 1
|
||||
for (let j = i; j >= -1; j--) {
|
||||
if (j === -1 || nodes[j].c || !nodes[j].name || (nodes[j].name !== 'div' && nodes[j].name !== 'p' && nodes[j].name[0] !== 'h') || (nodes[j].attrs.style || '').includes('inline')) {
|
||||
if (i - j >= 5) {
|
||||
nodes.splice(j + 1, i - j, {
|
||||
name: 'div',
|
||||
attrs: {},
|
||||
children: nodes.slice(j + 1, i + 1)
|
||||
})
|
||||
}
|
||||
i = j - 1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @description html 解析器
|
||||
* @param {Object} vm 组件实例
|
||||
@@ -146,6 +174,7 @@ function Parser (vm) {
|
||||
this.options = vm || {}
|
||||
this.tagStyle = Object.assign({}, config.tagStyle, this.options.tagStyle)
|
||||
this.imgList = vm.imgList || []
|
||||
this.imgList._unloadimgs = 0
|
||||
this.plugins = vm.plugins || []
|
||||
this.attrs = Object.create(null)
|
||||
this.stack = []
|
||||
@@ -170,6 +199,9 @@ Parser.prototype.parse = function (content) {
|
||||
while (this.stack.length) {
|
||||
this.popNode()
|
||||
}
|
||||
if (this.nodes.length > 50) {
|
||||
mergeNodes(this.nodes)
|
||||
}
|
||||
return this.nodes
|
||||
}
|
||||
|
||||
@@ -214,9 +246,15 @@ Parser.prototype.getUrl = function (url) {
|
||||
} else if (domain) {
|
||||
// 否则补充整个域名
|
||||
url = domain + url
|
||||
}
|
||||
} else if (domain && !url.includes('data:') && !url.includes('://')) {
|
||||
url = domain + '/' + url
|
||||
} /* #ifdef APP-PLUS */ else {
|
||||
url = plus.io.convertLocalFileSystemURL(url)
|
||||
} /* #endif */
|
||||
} else if (!url.includes('data:') && !url.includes('://')) {
|
||||
if (domain) {
|
||||
url = domain + '/' + url
|
||||
} /* #ifdef APP-PLUS */ else {
|
||||
url = plus.io.convertLocalFileSystemURL(url)
|
||||
} /* #endif */
|
||||
}
|
||||
return url
|
||||
}
|
||||
@@ -291,6 +329,7 @@ Parser.prototype.onTagName = function (name) {
|
||||
this.tagName = this.xml ? name : name.toLowerCase()
|
||||
if (this.tagName === 'svg') {
|
||||
this.xml = (this.xml || 0) + 1 // svg 标签内大小写敏感
|
||||
config.ignoreTags.style = undefined // svg 标签内 style 可用
|
||||
}
|
||||
}
|
||||
|
||||
@@ -301,6 +340,12 @@ Parser.prototype.onTagName = function (name) {
|
||||
*/
|
||||
Parser.prototype.onAttrName = function (name) {
|
||||
name = this.xml ? name : name.toLowerCase()
|
||||
// #ifdef (VUE3 && (H5 || APP-PLUS)) || APP-PLUS-NVUE
|
||||
if (name.includes('?') || name.includes(';')) {
|
||||
this.attrName = undefined
|
||||
return
|
||||
}
|
||||
// #endif
|
||||
if (name.substr(0, 5) === 'data-') {
|
||||
if (name === 'data-src' && !this.attrs.src) {
|
||||
// data-src 自动转为 src
|
||||
@@ -427,7 +472,7 @@ Parser.prototype.onOpenTag = function (selfClose) {
|
||||
node.webp = 'T'
|
||||
}
|
||||
// data url 图片如果没有设置 original-src 默认为不可预览的小图片
|
||||
if (attrs.src.includes('data:') && !attrs['original-src']) {
|
||||
if (attrs.src.includes('data:') && this.options.previewImg !== 'all' && !attrs['original-src']) {
|
||||
attrs.ignore = 'T'
|
||||
}
|
||||
if (!attrs.ignore || node.webp || attrs.src.includes('cloud://')) {
|
||||
@@ -435,11 +480,18 @@ Parser.prototype.onOpenTag = function (selfClose) {
|
||||
const item = this.stack[i]
|
||||
if (item.name === 'a') {
|
||||
node.a = item.attrs
|
||||
break
|
||||
}
|
||||
if (item.name === 'table' && !node.webp && !attrs.src.includes('cloud://')) {
|
||||
if (!styleObj.display || styleObj.display.includes('inline')) {
|
||||
node.t = 'inline-block'
|
||||
} else {
|
||||
node.t = styleObj.display
|
||||
}
|
||||
styleObj.display = undefined
|
||||
}
|
||||
// #ifndef H5 || APP-PLUS
|
||||
const style = item.attrs.style || ''
|
||||
if (style.includes('flex:') && !style.includes('flex:0') && !style.includes('flex: 0') && (!styleObj.width || !styleObj.width.includes('%'))) {
|
||||
if (style.includes('flex:') && !style.includes('flex:0') && !style.includes('flex: 0') && (!styleObj.width || parseInt(styleObj.width) > 100)) {
|
||||
styleObj.width = '100% !important'
|
||||
styleObj.height = ''
|
||||
for (let j = i + 1; j < this.stack.length; j++) {
|
||||
@@ -483,6 +535,9 @@ Parser.prototype.onOpenTag = function (selfClose) {
|
||||
}
|
||||
// #endif
|
||||
this.imgList.push(src)
|
||||
if (!node.t) {
|
||||
this.imgList._unloadimgs += 1
|
||||
}
|
||||
// #ifdef H5 || APP-PLUS
|
||||
if (this.options.lazyLoad) {
|
||||
attrs['data-src'] = attrs.src
|
||||
@@ -511,6 +566,13 @@ Parser.prototype.onOpenTag = function (selfClose) {
|
||||
if (!isNaN(parseInt(styleObj.height)) && (!styleObj.height.includes('%') || (parent && (parent.attrs.style || '').includes('height')))) {
|
||||
node.h = 'T'
|
||||
}
|
||||
if (node.w && node.h && styleObj['object-fit']) {
|
||||
if (styleObj['object-fit'] === 'contain') {
|
||||
node.m = 'aspectFit'
|
||||
} else if (styleObj['object-fit'] === 'cover') {
|
||||
node.m = 'aspectFill'
|
||||
}
|
||||
}
|
||||
} else if (node.name === 'svg') {
|
||||
siblings.push(node)
|
||||
this.stack.push(node)
|
||||
@@ -523,6 +585,11 @@ Parser.prototype.onOpenTag = function (selfClose) {
|
||||
}
|
||||
}
|
||||
attrs.style = attrs.style.substr(1) || undefined
|
||||
// #ifdef (MP-WEIXIN || MP-QQ) && VUE3
|
||||
if (!attrs.style) {
|
||||
delete attrs.style
|
||||
}
|
||||
// #endif
|
||||
} else {
|
||||
if ((node.name === 'pre' || ((attrs.style || '').includes('white-space') && attrs.style.includes('pre'))) && this.pre !== 2) {
|
||||
this.pre = node.pre = 1
|
||||
@@ -556,8 +623,8 @@ Parser.prototype.onCloseTag = function (name) {
|
||||
siblings.push({
|
||||
name,
|
||||
attrs: {
|
||||
class: tagSelector[name],
|
||||
style: this.tagStyle[name]
|
||||
class: tagSelector[name] || '',
|
||||
style: this.tagStyle[name] || ''
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -632,11 +699,19 @@ Parser.prototype.popNode = function () {
|
||||
return
|
||||
}
|
||||
const name = config.svgDict[node.name] || node.name
|
||||
if (name === 'foreignObject') {
|
||||
for (const child of (node.children || [])) {
|
||||
if (child.attrs && !child.attrs.xmlns) {
|
||||
child.attrs.xmlns = 'http://www.w3.org/1999/xhtml'
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
src += '<' + name
|
||||
for (const item in node.attrs) {
|
||||
const val = node.attrs[item]
|
||||
if (val) {
|
||||
src += ` ${config.svgDict[item] || item}="${val}"`
|
||||
src += ` ${config.svgDict[item] || item}="${val.replace(/"/g, '')}"`
|
||||
}
|
||||
}
|
||||
if (!node.children) {
|
||||
@@ -658,6 +733,7 @@ Parser.prototype.popNode = function () {
|
||||
node.children = undefined
|
||||
// #endif
|
||||
this.xml = false
|
||||
config.ignoreTags.style = true
|
||||
return
|
||||
}
|
||||
|
||||
@@ -777,6 +853,8 @@ Parser.prototype.popNode = function () {
|
||||
let padding = parseFloat(attrs.cellpadding)
|
||||
let spacing = parseFloat(attrs.cellspacing)
|
||||
const border = parseFloat(attrs.border)
|
||||
const bordercolor = styleObj['border-color']
|
||||
const borderstyle = styleObj['border-style']
|
||||
if (node.c) {
|
||||
// padding 和 spacing 默认 2
|
||||
if (isNaN(padding)) {
|
||||
@@ -787,11 +865,15 @@ Parser.prototype.popNode = function () {
|
||||
}
|
||||
}
|
||||
if (border) {
|
||||
attrs.style += ';border:' + border + 'px solid gray'
|
||||
attrs.style += `;border:${border}px ${borderstyle || 'solid'} ${bordercolor || 'gray'}`
|
||||
}
|
||||
if (node.flag && node.c) {
|
||||
// 有 colspan 或 rowspan 且含有链接的表格通过 grid 布局实现
|
||||
styleObj.display = 'grid'
|
||||
if (styleObj['border-collapse'] === 'collapse') {
|
||||
styleObj['border-collapse'] = undefined
|
||||
spacing = 0
|
||||
}
|
||||
if (spacing) {
|
||||
styleObj['grid-gap'] = spacing + 'px'
|
||||
styleObj.padding = spacing + 'px'
|
||||
@@ -809,6 +891,23 @@ Parser.prototype.popNode = function () {
|
||||
for (let i = 0; i < nodes.length; i++) {
|
||||
if (nodes[i].name === 'tr') {
|
||||
trList.push(nodes[i])
|
||||
} else if (nodes[i].name === 'colgroup') {
|
||||
let colI = 1
|
||||
for (const col of (nodes[i].children || [])) {
|
||||
if (col.name === 'col') {
|
||||
const style = col.attrs.style || ''
|
||||
const start = style.indexOf('width') ? style.indexOf(';width') : 0
|
||||
// 提取出宽度
|
||||
if (start !== -1) {
|
||||
let end = style.indexOf(';', start + 6)
|
||||
if (end === -1) {
|
||||
end = style.length
|
||||
}
|
||||
width[colI] = style.substring(start ? start + 7 : 6, end)
|
||||
}
|
||||
colI += 1
|
||||
}
|
||||
}
|
||||
} else {
|
||||
traversal(nodes[i].children || [])
|
||||
}
|
||||
@@ -825,7 +924,7 @@ Parser.prototype.popNode = function () {
|
||||
col++
|
||||
}
|
||||
let style = td.attrs.style || ''
|
||||
const start = style.indexOf('width') ? style.indexOf(';width') : 0
|
||||
let start = style.indexOf('width') ? style.indexOf(';width') : 0
|
||||
// 提取出 td 的宽度
|
||||
if (start !== -1) {
|
||||
let end = style.indexOf(';', start + 6)
|
||||
@@ -837,7 +936,30 @@ Parser.prototype.popNode = function () {
|
||||
}
|
||||
style = style.substr(0, start) + style.substr(end)
|
||||
}
|
||||
style += (border ? `;border:${border}px solid gray` + (spacing ? '' : ';border-right:0;border-bottom:0') : '') + (padding ? `;padding:${padding}px` : '')
|
||||
// 设置竖直对齐
|
||||
style += ';display:flex'
|
||||
start = style.indexOf('vertical-align')
|
||||
if (start !== -1) {
|
||||
const val = style.substr(start + 15, 10)
|
||||
if (val.includes('middle')) {
|
||||
style += ';align-items:center'
|
||||
} else if (val.includes('bottom')) {
|
||||
style += ';align-items:flex-end'
|
||||
}
|
||||
} else {
|
||||
style += ';align-items:center'
|
||||
}
|
||||
// 设置水平对齐
|
||||
start = style.indexOf('text-align')
|
||||
if (start !== -1) {
|
||||
const val = style.substr(start + 11, 10)
|
||||
if (val.includes('center')) {
|
||||
style += ';justify-content: center'
|
||||
} else if (val.includes('right')) {
|
||||
style += ';justify-content: right'
|
||||
}
|
||||
}
|
||||
style = (border ? `;border:${border}px ${borderstyle || 'solid'} ${bordercolor || 'gray'}` + (spacing ? '' : ';border-right:0;border-bottom:0') : '') + (padding ? `;padding:${padding}px` : '') + ';' + style
|
||||
// 处理列合并
|
||||
if (td.attrs.colspan) {
|
||||
style += `;grid-column-start:${col};grid-column-end:${col + parseInt(td.attrs.colspan)}`
|
||||
@@ -890,7 +1012,7 @@ Parser.prototype.popNode = function () {
|
||||
const td = nodes[i]
|
||||
if (td.name === 'th' || td.name === 'td') {
|
||||
if (border) {
|
||||
td.attrs.style = `border:${border}px solid gray;${td.attrs.style || ''}`
|
||||
td.attrs.style = `border:${border}px ${borderstyle || 'solid'} ${bordercolor || 'gray'};${td.attrs.style || ''}`
|
||||
}
|
||||
if (padding) {
|
||||
td.attrs.style = `padding:${padding}px;${td.attrs.style || ''}`
|
||||
@@ -912,11 +1034,26 @@ Parser.prototype.popNode = function () {
|
||||
node.children = [table]
|
||||
attrs = table.attrs
|
||||
}
|
||||
} else if ((node.name === 'tbody' || node.name === 'tr') && node.flag && node.c) {
|
||||
node.flag = undefined;
|
||||
(function traversal (nodes) {
|
||||
for (let i = 0; i < nodes.length; i++) {
|
||||
if (nodes[i].name === 'td') {
|
||||
// 颜色样式设置给单元格避免丢失
|
||||
for (const style of ['color', 'background', 'background-color']) {
|
||||
if (styleObj[style]) {
|
||||
nodes[i].attrs.style = style + ':' + styleObj[style] + ';' + (nodes[i].attrs.style || '')
|
||||
}
|
||||
}
|
||||
} else {
|
||||
traversal(nodes[i].children || [])
|
||||
}
|
||||
}
|
||||
})(children)
|
||||
} else if ((node.name === 'td' || node.name === 'th') && (attrs.colspan || attrs.rowspan)) {
|
||||
for (let i = this.stack.length; i--;) {
|
||||
if (this.stack[i].name === 'table') {
|
||||
if (this.stack[i].name === 'table' || this.stack[i].name === 'tbody' || this.stack[i].name === 'tr') {
|
||||
this.stack[i].flag = 1 // 指示含有合并单元格
|
||||
break
|
||||
}
|
||||
}
|
||||
} else if (node.name === 'ruby') {
|
||||
@@ -941,18 +1078,20 @@ Parser.prototype.popNode = function () {
|
||||
}
|
||||
}
|
||||
} else if (node.c) {
|
||||
node.c = 2
|
||||
for (let i = node.children.length; i--;) {
|
||||
const child = node.children[i]
|
||||
// #ifdef (MP-WEIXIN || MP-QQ || APP-PLUS || MP-360) && VUE3
|
||||
if (child.name && (config.inlineTags[child.name] || (child.attrs.style || '').includes('inline'))) {
|
||||
child.c = 1
|
||||
(function traversal (node) {
|
||||
node.c = 2
|
||||
for (let i = node.children.length; i--;) {
|
||||
const child = node.children[i]
|
||||
// #ifdef (MP-WEIXIN || MP-QQ || APP-PLUS || MP-360) && VUE3
|
||||
if (child.name && (config.inlineTags[child.name] || ((child.attrs.style || '').includes('inline') && child.children)) && !child.c) {
|
||||
traversal(child)
|
||||
}
|
||||
// #endif
|
||||
if (!child.c || child.name === 'table') {
|
||||
node.c = 1
|
||||
}
|
||||
}
|
||||
// #endif
|
||||
if (!child.c || child.name === 'table') {
|
||||
node.c = 1
|
||||
}
|
||||
}
|
||||
})(node)
|
||||
}
|
||||
|
||||
if ((styleObj.display || '').includes('flex') && !node.c) {
|
||||
@@ -977,22 +1116,8 @@ Parser.prototype.popNode = function () {
|
||||
node.f = ';max-width:100%'
|
||||
}
|
||||
|
||||
// 优化长内容加载速度
|
||||
if (children.length >= 50 && node.c && !(styleObj.display || '').includes('flex')) {
|
||||
let i = children.length - 1
|
||||
for (let j = i; j >= -1; j--) {
|
||||
// 合并多个块级标签
|
||||
if (j === -1 || children[j].c || !children[j].name || (children[j].name !== 'div' && children[j].name !== 'p' && children[j].name[0] !== 'h') || (children[j].attrs.style || '').includes('inline')) {
|
||||
if (i - j >= 5) {
|
||||
children.splice(j + 1, i - j, {
|
||||
name: 'div',
|
||||
attrs: {},
|
||||
children: node.children.slice(j + 1, i + 1)
|
||||
})
|
||||
}
|
||||
i = j - 1
|
||||
}
|
||||
}
|
||||
mergeNodes(children)
|
||||
}
|
||||
// #endif
|
||||
|
||||
@@ -1012,8 +1137,10 @@ Parser.prototype.popNode = function () {
|
||||
}
|
||||
attrs.style = attrs.style.substr(1) || undefined
|
||||
// #ifdef (MP-WEIXIN || MP-QQ) && VUE3
|
||||
if (!attrs.style) {
|
||||
delete attrs.style
|
||||
for (const key in attrs) {
|
||||
if (!attrs[key]) {
|
||||
delete attrs[key]
|
||||
}
|
||||
}
|
||||
// #endif
|
||||
}
|
||||
@@ -1040,7 +1167,15 @@ Parser.prototype.onText = function (text) {
|
||||
}
|
||||
}
|
||||
// 去除含有换行符的空串
|
||||
if (trim === ' ' && flag) return
|
||||
if (trim === ' ') {
|
||||
if (flag) return
|
||||
// #ifdef VUE3
|
||||
else {
|
||||
const parent = this.stack[this.stack.length - 1]
|
||||
if (parent && parent.name[0] === 't') return
|
||||
}
|
||||
// #endif
|
||||
}
|
||||
text = trim
|
||||
}
|
||||
const node = Object.create(null)
|
||||
@@ -1051,9 +1186,8 @@ Parser.prototype.onText = function (text) {
|
||||
node.text = decodeEntity(text)
|
||||
if (this.hook(node)) {
|
||||
// #ifdef MP-WEIXIN
|
||||
if (this.options.selectable === 'force' && system.includes('iOS')) {
|
||||
if (this.options.selectable === 'force' && system.includes('iOS') && !uni.canIUse('rich-text.user-select')) {
|
||||
this.expose()
|
||||
node.us = 'T'
|
||||
}
|
||||
// #endif
|
||||
const siblings = this.stack.length ? this.stack[this.stack.length - 1].children : this.nodes
|
||||
|
||||
Reference in New Issue
Block a user