oxy-uni-ui 1.2.0 → 1.2.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (116) hide show
  1. package/attributes.json +1 -1
  2. package/components/common/abstracts/variable.scss +51 -1
  3. package/components/common/path.ts +9 -0
  4. package/components/common/util.ts +42 -0
  5. package/components/composables/useGlobalLoading.ts +42 -0
  6. package/components/composables/useGlobalMessage.ts +48 -0
  7. package/components/composables/useGlobalToast.ts +84 -0
  8. package/components/composables/useVirtualScroll.ts +3 -2
  9. package/components/oxy-cell/oxy-cell.vue +15 -2
  10. package/components/oxy-cell/types.ts +4 -0
  11. package/components/oxy-checkbox/index.scss +1 -1
  12. package/components/oxy-checkbox/oxy-checkbox.vue +2 -2
  13. package/components/oxy-col-picker/oxy-col-picker.vue +3 -0
  14. package/components/oxy-col-picker/types.ts +5 -1
  15. package/components/oxy-corner/oxy-corner.vue +15 -3
  16. package/components/oxy-corner/types.ts +15 -1
  17. package/components/oxy-date-strip/index.scss +10 -0
  18. package/components/oxy-date-strip/oxy-date-strip.vue +198 -0
  19. package/components/oxy-date-strip/types.ts +98 -0
  20. package/components/oxy-date-strip/utils.ts +67 -0
  21. package/components/oxy-date-strip-item/index.scss +94 -0
  22. package/components/oxy-date-strip-item/oxy-date-strip-item.vue +102 -0
  23. package/components/oxy-date-strip-item/types.ts +53 -0
  24. package/components/oxy-datetime-picker/oxy-datetime-picker.vue +3 -1
  25. package/components/oxy-datetime-picker/types.ts +5 -1
  26. package/components/oxy-echarts/index.scss +17 -0
  27. package/components/oxy-echarts/index.ts +1 -0
  28. package/components/oxy-echarts/oxy-echarts.vue +32 -0
  29. package/components/oxy-echarts/types.ts +12 -0
  30. package/components/oxy-file-list/index.scss +26 -0
  31. package/components/oxy-file-list/oxy-file-list.vue +208 -34
  32. package/components/oxy-file-list/types.ts +58 -2
  33. package/components/oxy-global-loading/oxy-global-loading.vue +53 -0
  34. package/components/oxy-global-message/oxy-global-message.vue +64 -0
  35. package/components/oxy-global-toast/oxy-global-toast.vue +53 -0
  36. package/components/oxy-img-lazy/index.scss +17 -0
  37. package/components/oxy-img-lazy/oxy-img-lazy.vue +332 -0
  38. package/components/oxy-img-lazy/types.ts +69 -0
  39. package/components/oxy-link/index.scss +57 -0
  40. package/components/oxy-link/oxy-link.vue +130 -0
  41. package/components/oxy-link/types.ts +81 -0
  42. package/components/oxy-list/index.scss +7 -1
  43. package/components/oxy-list/types.ts +1 -1
  44. package/components/oxy-picker/oxy-picker.vue +3 -0
  45. package/components/oxy-picker/types.ts +5 -1
  46. package/components/oxy-radio/index.scss +3 -3
  47. package/components/oxy-radio/oxy-radio.vue +1 -1
  48. package/components/oxy-rich-text/icon/emjio.svg +1 -0
  49. package/components/oxy-rich-text/icon/quote.svg +1 -0
  50. package/components/oxy-rich-text/icon/text.svg +1 -0
  51. package/components/oxy-rich-text/icon/title.svg +1 -0
  52. package/components/oxy-rich-text/index.scss +159 -0
  53. package/components/oxy-rich-text/mp-html/card/card.vue +122 -0
  54. package/components/oxy-rich-text/mp-html/card/index.js +7 -0
  55. package/components/oxy-rich-text/mp-html/editable/config.js +15 -0
  56. package/components/oxy-rich-text/mp-html/editable/index.js +553 -0
  57. package/components/oxy-rich-text/mp-html/emoji/index.js +203 -0
  58. package/components/oxy-rich-text/mp-html/highlight/config.js +5 -0
  59. package/components/oxy-rich-text/mp-html/highlight/index.js +96 -0
  60. package/components/oxy-rich-text/mp-html/highlight/prism.css +1 -0
  61. package/components/oxy-rich-text/mp-html/highlight/prism.min.js +7 -0
  62. package/components/oxy-rich-text/mp-html/img-cache/index.js +138 -0
  63. package/components/oxy-rich-text/mp-html/latex/index.js +80 -0
  64. package/components/oxy-rich-text/mp-html/latex/katex.css +1 -0
  65. package/components/oxy-rich-text/mp-html/latex/katex.min.js +1 -0
  66. package/components/oxy-rich-text/mp-html/markdown/index.js +50 -0
  67. package/components/oxy-rich-text/mp-html/markdown/marked.min.js +71 -0
  68. package/components/oxy-rich-text/mp-html/mp-html.d.ts +184 -0
  69. package/components/oxy-rich-text/mp-html/mp-html.vue +675 -0
  70. package/components/oxy-rich-text/mp-html/node/node.vue +1161 -0
  71. package/components/oxy-rich-text/mp-html/parser.js +1428 -0
  72. package/components/oxy-rich-text/mp-html/search/index.js +132 -0
  73. package/components/oxy-rich-text/mp-html/style/index.js +129 -0
  74. package/components/oxy-rich-text/mp-html/style/parser.js +175 -0
  75. package/components/oxy-rich-text/mp-html/template/index.js +67 -0
  76. package/components/oxy-rich-text/mp-html/txv-video/index.js +46 -0
  77. package/components/oxy-rich-text/oxy-rich-text.vue +642 -0
  78. package/components/oxy-rich-text/types.ts +71 -0
  79. package/components/oxy-select/index.scss +255 -0
  80. package/components/oxy-select/oxy-select.vue +421 -0
  81. package/components/oxy-select/types.ts +71 -0
  82. package/components/oxy-select-picker/oxy-select-picker.vue +3 -0
  83. package/components/oxy-select-picker/types.ts +5 -1
  84. package/components/oxy-stream-render/index.scss +6 -0
  85. package/components/oxy-stream-render/oxy-stream-render.vue +204 -0
  86. package/components/oxy-stream-render/types.ts +5 -0
  87. package/components/oxy-tree/index.scss +17 -1
  88. package/components/oxy-tree/oxy-tree.vue +89 -8
  89. package/components/oxy-tree/types.ts +11 -1
  90. package/components/oxy-waterfall/index.scss +18 -0
  91. package/components/oxy-waterfall/oxy-waterfall.vue +218 -0
  92. package/components/oxy-waterfall/types.ts +90 -0
  93. package/components/oxy-waterfall-item/index.scss +8 -0
  94. package/components/oxy-waterfall-item/oxy-waterfall-item.vue +89 -0
  95. package/components/oxy-waterfall-item/types.ts +16 -0
  96. package/global.d.ts +7 -0
  97. package/index.ts +3 -0
  98. package/locale/lang/en-US.ts +26 -0
  99. package/locale/lang/zh-CN.ts +26 -0
  100. package/oxy-uni-ui.zip +0 -0
  101. package/package.json +1 -1
  102. package/tags.json +1 -1
  103. package/uni-echarts/changelog.md +2 -0
  104. package/uni-echarts/components/index.js +1 -0
  105. package/uni-echarts/components/uni-echarts/events.js +95 -0
  106. package/uni-echarts/components/uni-echarts/types.d.ts +183 -0
  107. package/uni-echarts/components/uni-echarts/types.js +1 -0
  108. package/uni-echarts/components/uni-echarts/uni-echarts.vue +530 -0
  109. package/uni-echarts/components/uni-echarts/uni-echarts.vue.d.ts +19 -0
  110. package/uni-echarts/global.d.ts +7 -0
  111. package/uni-echarts/index.d.ts +440 -0
  112. package/uni-echarts/index.js +2 -0
  113. package/uni-echarts/package.json +105 -0
  114. package/uni-echarts/shared-core.d.ts +269 -0
  115. package/uni-echarts/shared-core.js +900 -0
  116. package/web-types.json +1 -1
@@ -0,0 +1,675 @@
1
+ <template>
2
+ <view
3
+ id="_root"
4
+ class="mp-html"
5
+ :class="(selectable ? '_select ' : '') + '_root'"
6
+ :style="(editable ? 'min-height:200px;' : '') + containerStyle"
7
+ @tap="_containTap"
8
+ >
9
+ <slot v-if="!nodes[0]" />
10
+ <!-- #ifndef APP-PLUS-NVUE -->
11
+ <node v-else :childs="nodes" :opts="[lazyLoad, loadingImg, errorImg, showImgMenu, selectable, editable, placeholder, 'nodes']" name="span" />
12
+ <!-- #endif -->
13
+ <!-- #ifdef APP-PLUS-NVUE -->
14
+ <web-view ref="web" src="/static/app-plus/mp-html/local.html" :style="'margin-top:-2px;height:' + height + 'px'" @onPostMessage="_onMessage" />
15
+ <!-- #endif -->
16
+ <view v-if="tooltip" class="_tooltip_contain" :style="'top:' + tooltip.top + 'px'">
17
+ <view class="_tooltip">
18
+ <view v-for="(item, index) in tooltip.items" v-bind:key="index" class="_tooltip_item" :data-i="index" @tap="_tooltipTap">{{ item }}</view>
19
+ </view>
20
+ </view>
21
+ <view v-if="slider" class="_slider" :style="'top:' + slider.top + 'px'">
22
+ <slider
23
+ :value="slider.value"
24
+ :min="slider.min"
25
+ :max="slider.max"
26
+ handle-size="14"
27
+ block-size="14"
28
+ show-value
29
+ activeColor="white"
30
+ style="padding: 3px"
31
+ @changing="_sliderChanging"
32
+ @change="_sliderChange"
33
+ />
34
+ </view>
35
+ <view v-if="color" class="_tooltip_contain" :style="'top:' + color.top + 'px'">
36
+ <view class="_tooltip" style="overflow-y: hidden">
37
+ <view
38
+ v-for="(item, index) in color.items"
39
+ v-bind:key="index"
40
+ class="_color_item"
41
+ :style="'background-color:' + item"
42
+ :data-i="index"
43
+ @tap="_colorTap"
44
+ ></view>
45
+ </view>
46
+ </view>
47
+ </view>
48
+ </template>
49
+
50
+ <script>
51
+ /**
52
+ * mp-html v2.5.2
53
+ * @description 富文本组件
54
+ * @tutorial https://github.com/jin-yufeng/mp-html
55
+ * @property {String} container-style 容器的样式
56
+ * @property {String} content 用于渲染的 html 字符串
57
+ * @property {Boolean} copy-link 是否允许外部链接被点击时自动复制
58
+ * @property {String} domain 主域名,用于拼接链接
59
+ * @property {String} error-img 图片出错时的占位图链接
60
+ * @property {Boolean} lazy-load 是否开启图片懒加载
61
+ * @property {string} loading-img 图片加载过程中的占位图链接
62
+ * @property {Boolean} pause-video 是否在播放一个视频时自动暂停其他视频
63
+ * @property {Boolean} preview-img 是否允许图片被点击时自动预览
64
+ * @property {Boolean} scroll-table 是否给每个表格添加一个滚动层使其能单独横向滚动
65
+ * @property {Boolean | String} selectable 是否开启长按复制
66
+ * @property {Boolean} set-title 是否将 title 标签的内容设置到页面标题
67
+ * @property {Boolean} show-img-menu 是否允许图片被长按时显示菜单
68
+ * @property {Object} tag-style 标签的默认样式
69
+ * @property {Boolean | Number} use-anchor 是否使用锚点链接
70
+ * @event {Function} load dom 结构加载完毕时触发
71
+ * @event {Function} ready 所有图片加载完毕时触发
72
+ * @event {Function} imgtap 图片被点击时触发
73
+ * @event {Function} linktap 链接被点击时触发
74
+ * @event {Function} play 音视频播放时触发
75
+ * @event {Function} error 媒体加载出错时触发
76
+ * @event {Function} pause 音视频暂停时触发
77
+ * @event {Function} fullscreenchange 视频全屏状态变化时触发
78
+ */
79
+ // #ifndef APP-PLUS-NVUE
80
+ import node from './node/node'
81
+ // #endif
82
+ import Parser from './parser'
83
+ import markdown from './markdown/index.js'
84
+ import highlight from './highlight/index.js'
85
+ import latex from './latex/index.js'
86
+ import style from './style/index.js'
87
+ import editable from './editable/index.js'
88
+ const plugins = [markdown, highlight, latex, style, editable]
89
+ // #ifdef APP-PLUS-NVUE
90
+ const dom = weex.requireModule('dom')
91
+ // #endif
92
+ export default {
93
+ name: 'mp-html',
94
+ data() {
95
+ return {
96
+ tooltip: null,
97
+ slider: null,
98
+ color: null,
99
+ nodes: [],
100
+ // #ifdef APP-PLUS-NVUE
101
+ height: 3
102
+ // #endif
103
+ }
104
+ },
105
+ props: {
106
+ editable: [Boolean, String],
107
+ placeholder: String,
108
+ markdown: Boolean,
109
+ containerStyle: {
110
+ type: String,
111
+ default: ''
112
+ },
113
+ content: {
114
+ type: String,
115
+ default: ''
116
+ },
117
+ copyLink: {
118
+ type: [Boolean, String],
119
+ default: true
120
+ },
121
+ domain: String,
122
+ errorImg: {
123
+ type: String,
124
+ default: ''
125
+ },
126
+ lazyLoad: {
127
+ type: [Boolean, String],
128
+ default: false
129
+ },
130
+ loadingImg: {
131
+ type: String,
132
+ default: ''
133
+ },
134
+ pauseVideo: {
135
+ type: [Boolean, String],
136
+ default: true
137
+ },
138
+ previewImg: {
139
+ type: [Boolean, String],
140
+ default: true
141
+ },
142
+ scrollTable: [Boolean, String],
143
+ selectable: [Boolean, String],
144
+ setTitle: {
145
+ type: [Boolean, String],
146
+ default: true
147
+ },
148
+ showImgMenu: {
149
+ type: [Boolean, String],
150
+ default: true
151
+ },
152
+ tagStyle: Object,
153
+ useAnchor: [Boolean, Number]
154
+ },
155
+ // #ifdef VUE3
156
+ emits: ['load', 'ready', 'imgtap', 'linktap', 'play', 'error'],
157
+ // #endif
158
+ // #ifndef APP-PLUS-NVUE
159
+ components: {
160
+ node
161
+ },
162
+ // #endif
163
+ watch: {
164
+ editable(val) {
165
+ this.setContent(val ? this.content : this.getContent())
166
+ if (!val) this._maskTap()
167
+ },
168
+ content(content) {
169
+ this.setContent(content)
170
+ }
171
+ },
172
+ created() {
173
+ this.plugins = []
174
+ for (let i = plugins.length; i--; ) {
175
+ this.plugins.push(new plugins[i](this))
176
+ }
177
+ },
178
+ mounted() {
179
+ if ((this.content || this.editable) && !this.nodes.length) {
180
+ this.setContent(this.content)
181
+ }
182
+ },
183
+ beforeDestroy() {
184
+ this._hook('onDetached')
185
+ },
186
+ methods: {
187
+ _containTap() {
188
+ if (!this._lock && !this.slider && !this.color) {
189
+ this._edit = undefined
190
+ this._maskTap()
191
+ }
192
+ },
193
+ _tooltipTap(e) {
194
+ this._tooltipcb(e.currentTarget.dataset.i)
195
+ this.$set(this, 'tooltip', null)
196
+ },
197
+ _sliderChanging(e) {
198
+ this._slideringcb(e.detail.value)
199
+ },
200
+ _sliderChange(e) {
201
+ this._slidercb(e.detail.value)
202
+ },
203
+ _colorTap(e) {
204
+ this._colorcb(e.currentTarget.dataset.i)
205
+ this.$set(this, 'color', null)
206
+ },
207
+ /**
208
+ * @description 将锚点跳转的范围限定在一个 scroll-view 内
209
+ * @param {Object} page scroll-view 所在页面的示例
210
+ * @param {String} selector scroll-view 的选择器
211
+ * @param {String} scrollTop scroll-view scroll-top 属性绑定的变量名
212
+ */
213
+ in(page, selector, scrollTop) {
214
+ // #ifndef APP-PLUS-NVUE
215
+ if (page && selector && scrollTop) {
216
+ this._in = {
217
+ page,
218
+ selector,
219
+ scrollTop
220
+ }
221
+ }
222
+ // #endif
223
+ },
224
+
225
+ /**
226
+ * @description 锚点跳转
227
+ * @param {String} id 要跳转的锚点 id
228
+ * @param {Number} offset 跳转位置的偏移量
229
+ * @returns {Promise}
230
+ */
231
+ navigateTo(id, offset) {
232
+ id = this._ids[decodeURI(id)] || id
233
+ return new Promise((resolve, reject) => {
234
+ if (!this.useAnchor) {
235
+ reject(Error('Anchor is disabled'))
236
+ return
237
+ }
238
+ offset = offset || parseInt(this.useAnchor) || 0
239
+ // #ifdef APP-PLUS-NVUE
240
+ if (!id) {
241
+ dom.scrollToElement(this.$refs.web, {
242
+ offset
243
+ })
244
+ resolve()
245
+ } else {
246
+ this._navigateTo = {
247
+ resolve,
248
+ reject,
249
+ offset
250
+ }
251
+ this.$refs.web.evalJs('uni.postMessage({data:{action:"getOffset",offset:(document.getElementById(' + id + ')||{}).offsetTop}})')
252
+ }
253
+ // #endif
254
+ // #ifndef APP-PLUS-NVUE
255
+ let deep = ' '
256
+ // #ifdef MP-WEIXIN || MP-QQ || MP-TOUTIAO
257
+ deep = '>>>'
258
+ // #endif
259
+ const selector = uni
260
+ .createSelectorQuery()
261
+ // #ifndef MP-ALIPAY
262
+ .in(this._in ? this._in.page : this)
263
+ // #endif
264
+ .select((this._in ? this._in.selector : '._root') + (id ? `${deep}#${id}` : ''))
265
+ .boundingClientRect()
266
+ if (this._in) {
267
+ selector.select(this._in.selector).scrollOffset().select(this._in.selector).boundingClientRect()
268
+ } else {
269
+ // 获取 scroll-view 的位置和滚动距离
270
+ selector.selectViewport().scrollOffset() // 获取窗口的滚动距离
271
+ }
272
+ selector.exec((res) => {
273
+ if (!res[0]) {
274
+ reject(Error('Label not found'))
275
+ return
276
+ }
277
+ const scrollTop = res[1].scrollTop + res[0].top - (res[2] ? res[2].top : 0) + offset
278
+ if (this._in) {
279
+ // scroll-view 跳转
280
+ this._in.page[this._in.scrollTop] = scrollTop
281
+ } else {
282
+ // 页面跳转
283
+ uni.pageScrollTo({
284
+ scrollTop,
285
+ duration: 300
286
+ })
287
+ }
288
+ resolve()
289
+ })
290
+ // #endif
291
+ })
292
+ },
293
+
294
+ /**
295
+ * @description 获取文本内容
296
+ * @return {String}
297
+ */
298
+ getText(nodes) {
299
+ let text = ''
300
+ ;(function traversal(nodes) {
301
+ for (let i = 0; i < nodes.length; i++) {
302
+ const node = nodes[i]
303
+ if (node.type === 'text') {
304
+ text += node.text.replace(/&amp;/g, '&')
305
+ } else if (node.name === 'br') {
306
+ text += '\n'
307
+ } else {
308
+ // 块级标签前后加换行
309
+ const isBlock =
310
+ node.name === 'p' ||
311
+ node.name === 'div' ||
312
+ node.name === 'tr' ||
313
+ node.name === 'li' ||
314
+ (node.name[0] === 'h' && node.name[1] > '0' && node.name[1] < '7')
315
+ if (isBlock && text && text[text.length - 1] !== '\n') {
316
+ text += '\n'
317
+ }
318
+ // 递归获取子节点的文本
319
+ if (node.children) {
320
+ traversal(node.children)
321
+ }
322
+ if (isBlock && text[text.length - 1] !== '\n') {
323
+ text += '\n'
324
+ } else if (node.name === 'td' || node.name === 'th') {
325
+ text += '\t'
326
+ }
327
+ }
328
+ }
329
+ })(nodes || this.nodes)
330
+ return text
331
+ },
332
+
333
+ /**
334
+ * @description 获取内容大小和位置
335
+ * @return {Promise}
336
+ */
337
+ getRect() {
338
+ return new Promise((resolve, reject) => {
339
+ uni
340
+ .createSelectorQuery()
341
+ // #ifndef MP-ALIPAY
342
+ .in(this)
343
+ // #endif
344
+ .select('#_root')
345
+ .boundingClientRect()
346
+ .exec((res) => (res[0] ? resolve(res[0]) : reject(Error('Root label not found'))))
347
+ })
348
+ },
349
+
350
+ /**
351
+ * @description 暂停播放媒体
352
+ */
353
+ pauseMedia() {
354
+ for (let i = (this._videos || []).length; i--; ) {
355
+ this._videos[i].pause()
356
+ }
357
+ // #ifdef APP-PLUS
358
+ const command = 'for(var e=document.getElementsByTagName("video"),i=e.length;i--;)e[i].pause()'
359
+ // #ifndef APP-PLUS-NVUE
360
+ let page = this.$parent
361
+ while (!page.$scope) page = page.$parent
362
+ page.$scope.$getAppWebview().evalJS(command)
363
+ // #endif
364
+ // #ifdef APP-PLUS-NVUE
365
+ this.$refs.web.evalJs(command)
366
+ // #endif
367
+ // #endif
368
+ },
369
+
370
+ /**
371
+ * @description 设置媒体播放速率
372
+ * @param {Number} rate 播放速率
373
+ */
374
+ setPlaybackRate(rate) {
375
+ this.playbackRate = rate
376
+ for (let i = (this._videos || []).length; i--; ) {
377
+ this._videos[i].playbackRate(rate)
378
+ }
379
+ // #ifdef APP-PLUS
380
+ const command = 'for(var e=document.getElementsByTagName("video"),i=e.length;i--;)e[i].playbackRate=' + rate
381
+ // #ifndef APP-PLUS-NVUE
382
+ let page = this.$parent
383
+ while (!page.$scope) page = page.$parent
384
+ page.$scope.$getAppWebview().evalJS(command)
385
+ // #endif
386
+ // #ifdef APP-PLUS-NVUE
387
+ this.$refs.web.evalJs(command)
388
+ // #endif
389
+ // #endif
390
+ },
391
+
392
+ /**
393
+ * @description 设置内容
394
+ * @param {String} content html 内容
395
+ * @param {Boolean} append 是否在尾部追加
396
+ */
397
+ setContent(content, append) {
398
+ if (!append || !this.imgList) {
399
+ this.imgList = []
400
+ }
401
+ const nodes = new Parser(this).parse(content)
402
+ // #ifdef APP-PLUS-NVUE
403
+ if (this._ready) {
404
+ this._set(nodes, append)
405
+ }
406
+ // #endif
407
+ this.$set(this, 'nodes', append ? (this.nodes || []).concat(nodes) : nodes)
408
+
409
+ // #ifndef APP-PLUS-NVUE
410
+ this._videos = []
411
+ this.$nextTick(() => {
412
+ this._hook('onLoad')
413
+ this.$emit('load')
414
+ })
415
+
416
+ if (this.lazyLoad || this.imgList._unloadimgs < this.imgList.length / 2) {
417
+ // 设置懒加载,每 350ms 获取高度,不变则认为加载完毕
418
+ let height = 0
419
+ const callback = (rect) => {
420
+ if (!rect || !rect.height) rect = {}
421
+ // 350ms 总高度无变化就触发 ready 事件
422
+ if (rect.height === height) {
423
+ this.$emit('ready', rect)
424
+ } else {
425
+ height = rect.height
426
+ setTimeout(() => {
427
+ this.getRect().then(callback).catch(callback)
428
+ }, 350)
429
+ }
430
+ }
431
+ this.getRect().then(callback).catch(callback)
432
+ } else {
433
+ // 未设置懒加载,等待所有图片加载完毕
434
+ if (!this.imgList._unloadimgs) {
435
+ this.getRect()
436
+ .then((rect) => {
437
+ this.$emit('ready', rect)
438
+ })
439
+ .catch(() => {
440
+ this.$emit('ready', {})
441
+ })
442
+ }
443
+ }
444
+ // #endif
445
+ },
446
+
447
+ /**
448
+ * @description 调用插件钩子函数
449
+ */
450
+ _hook(name) {
451
+ for (let i = plugins.length; i--; ) {
452
+ if (this.plugins[i][name]) {
453
+ this.plugins[i][name]()
454
+ }
455
+ }
456
+ },
457
+
458
+ // #ifdef APP-PLUS-NVUE
459
+ /**
460
+ * @description 设置内容
461
+ */
462
+ _set(nodes, append) {
463
+ this.$refs.web.evalJs(
464
+ 'setContent(' +
465
+ JSON.stringify(nodes).replace(/%22/g, '') +
466
+ ',' +
467
+ JSON.stringify([
468
+ this.containerStyle.replace(/(?:margin|padding)[^;]+/g, ''),
469
+ this.errorImg,
470
+ this.loadingImg,
471
+ this.pauseVideo,
472
+ this.scrollTable,
473
+ this.selectable
474
+ ]) +
475
+ ',' +
476
+ append +
477
+ ')'
478
+ )
479
+ },
480
+
481
+ /**
482
+ * @description 接收到 web-view 消息
483
+ */
484
+ _onMessage(e) {
485
+ const message = e.detail.data[0]
486
+ switch (message.action) {
487
+ // web-view 初始化完毕
488
+ case 'onJSBridgeReady':
489
+ this._ready = true
490
+ if (this.nodes) {
491
+ this._set(this.nodes)
492
+ }
493
+ break
494
+ // 内容 dom 加载完毕
495
+ case 'onLoad':
496
+ this.height = message.height
497
+ this._hook('onLoad')
498
+ this.$emit('load')
499
+ break
500
+ // 所有图片加载完毕
501
+ case 'onReady':
502
+ this.getRect()
503
+ .then((res) => {
504
+ this.$emit('ready', res)
505
+ })
506
+ .catch(() => {
507
+ this.$emit('ready', {})
508
+ })
509
+ break
510
+ // 总高度发生变化
511
+ case 'onHeightChange':
512
+ this.height = message.height
513
+ break
514
+ // 图片点击
515
+ case 'onImgTap':
516
+ this.$emit('imgtap', message.attrs)
517
+ if (this.previewImg) {
518
+ uni.previewImage({
519
+ current: parseInt(message.attrs.i),
520
+ urls: this.imgList
521
+ })
522
+ }
523
+ break
524
+ // 链接点击
525
+ case 'onLinkTap': {
526
+ const href = message.attrs.href
527
+ this.$emit('linktap', message.attrs)
528
+ if (href) {
529
+ // 锚点跳转
530
+ if (href[0] === '#') {
531
+ if (this.useAnchor) {
532
+ dom.scrollToElement(this.$refs.web, {
533
+ offset: message.offset
534
+ })
535
+ }
536
+ } else if (href.includes('://')) {
537
+ // 打开外链
538
+ if (this.copyLink) {
539
+ plus.runtime.openWeb(href)
540
+ }
541
+ } else {
542
+ uni.navigateTo({
543
+ url: href,
544
+ fail() {
545
+ uni.switchTab({
546
+ url: href
547
+ })
548
+ }
549
+ })
550
+ }
551
+ }
552
+ break
553
+ }
554
+ case 'onPlay':
555
+ this.$emit('play')
556
+ break
557
+ // 获取到锚点的偏移量
558
+ case 'getOffset':
559
+ if (typeof message.offset === 'number') {
560
+ dom.scrollToElement(this.$refs.web, {
561
+ offset: message.offset + this._navigateTo.offset
562
+ })
563
+ this._navigateTo.resolve()
564
+ } else {
565
+ this._navigateTo.reject(Error('Label not found'))
566
+ }
567
+ break
568
+ // 点击
569
+ case 'onClick':
570
+ this.$emit('tap')
571
+ this.$emit('click')
572
+ break
573
+ // 出错
574
+ case 'onError':
575
+ this.$emit('error', {
576
+ source: message.source,
577
+ attrs: message.attrs
578
+ })
579
+ }
580
+ }
581
+ // #endif
582
+ }
583
+ }
584
+ </script>
585
+
586
+ <style>
587
+ /* #ifndef APP-PLUS-NVUE */
588
+ /* 根节点样式 */
589
+ ._root {
590
+ padding: 1px 0;
591
+ overflow-x: auto;
592
+ overflow-y: hidden;
593
+ -webkit-overflow-scrolling: touch;
594
+ }
595
+
596
+ /* 长按复制 */
597
+ ._select {
598
+ user-select: text;
599
+ }
600
+ /* #endif */
601
+
602
+ /* 提示条 */
603
+ ._tooltip_contain {
604
+ position: absolute;
605
+ right: 20px;
606
+ left: 20px;
607
+ text-align: center;
608
+ }
609
+
610
+ ._tooltip {
611
+ box-sizing: border-box;
612
+ display: inline-block;
613
+ width: auto;
614
+ max-width: 100%;
615
+ height: 30px;
616
+ padding: 0 3px;
617
+ overflow-x: auto;
618
+ overflow-y: hidden;
619
+ font-size: 14px;
620
+ line-height: 30px;
621
+ white-space: nowrap;
622
+ padding-bottom: 2px;
623
+ border: 1px solid transparent;
624
+ }
625
+
626
+ ._tooltip::-webkit-scrollbar {
627
+ height: 4px;
628
+ }
629
+
630
+ ._tooltip::-webkit-scrollbar-track {
631
+ background: rgba(255, 255, 255, 0.1);
632
+ border-radius: 2px;
633
+ }
634
+
635
+ ._tooltip::-webkit-scrollbar-thumb {
636
+ background: rgba(255, 255, 255, 1);
637
+ border-radius: 2px;
638
+ }
639
+
640
+ ._tooltip::-webkit-scrollbar-thumb:hover {
641
+ background: rgba(255, 255, 255, 0.7);
642
+ }
643
+
644
+ ._tooltip_item {
645
+ display: inline-block;
646
+ width: auto;
647
+ padding: 0 2vw;
648
+ line-height: 30px;
649
+ background-color: black;
650
+ color: white;
651
+ }
652
+
653
+ ._color_item {
654
+ display: inline-block;
655
+ width: 18px;
656
+ height: 18px;
657
+ margin: 5px 2vw;
658
+ border: 1px solid #dfe2e5;
659
+ border-radius: 50%;
660
+ }
661
+
662
+ /* 图片宽度滚动条 */
663
+ ._slider {
664
+ position: absolute;
665
+ left: 20px;
666
+ width: 220px;
667
+ }
668
+
669
+ ._tooltip,
670
+ ._slider {
671
+ background-color: black;
672
+ border-radius: 3px;
673
+ opacity: 0.75;
674
+ }
675
+ </style>