uview-plus 3.8.113 → 3.8.119
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.
- package/changelog.md +83 -0
- package/components/u-cascader/u-cascader.vue +1 -1
- package/components/u-cropper/u-cropper.vue +8 -8
- package/components/u-datetime-picker/u-datetime-picker.vue +44 -8
- package/components/u-float-button/u-float-button.vue +1 -1
- package/components/u-goods-sku/u-goods-sku.vue +2 -2
- package/components/u-list-item/u-list-item.vue +4 -0
- package/components/u-navbar/theme-vars.scss +14 -0
- package/components/u-notice-bar/theme-vars.scss +16 -0
- package/components/u-parse/node/node.vue +23 -4
- package/components/u-select/u-select.vue +31 -11
- package/components/u-subsection/theme-vars.scss +24 -0
- package/components/u-switch/theme-vars.scss +24 -0
- package/components/u-tabbar/u-tabbar.vue +17 -6
- package/components/u-tabbar-item/midButtonGeometry.js +19 -0
- package/components/u-tabbar-item/u-tabbar-item.vue +118 -41
- package/components/u-tag/theme-vars.scss +14 -0
- package/components/u-transition/u-transition.vue +0 -1
- package/components/u-waterfall/u-waterfall.vue +181 -162
- package/libs/function/index.js +33 -0
- package/libs/mixin/mixin.js +3 -0
- package/package.json +2 -2
package/changelog.md
CHANGED
|
@@ -1,3 +1,86 @@
|
|
|
1
|
+
## 3.8.119
|
|
2
|
+
fix: 修复 datetime-picker format 兼容性与 tabbar 边框切页丢失
|
|
3
|
+
|
|
4
|
+
本版修复两个独立问题,均不涉及组件 API 变更。
|
|
5
|
+
|
|
6
|
+
fix: datetime-picker format 兼容库自身的 yyyy-mm-dd 写法,字符串绑定值不再退回 minDate (#537)
|
|
7
|
+
|
|
8
|
+
库内置的日期格式化工具 `timeFormat` 支持 `yyyy-mm-dd` 写法(全小写),但 u-datetime-picker 的 format 解析只识别 `YYYY-MM-DD`(全大写),导致用户按文档示例传入小写 format 时,传入的字符串绑定值无法被正确解析,组件退回到 minDate 而非用户期望的日期。
|
|
9
|
+
|
|
10
|
+
- format 解析逻辑补充小写月日模式 `mm` / `dd`,与库自身的 timeFormat 对齐
|
|
11
|
+
- 保持对原有大写 `MM` / `DD` 的兼容
|
|
12
|
+
- 新增 `verify:datetime-picker-format` 回归校验
|
|
13
|
+
|
|
14
|
+
fix: tabbar 顶部边框改为组件内联绘制,修复切换页面后边框丢失 (#873)
|
|
15
|
+
|
|
16
|
+
u-tabbar 的顶部边框原先靠模板上的全局工具类 `u-border-top` 绘制,组件自身 scoped 样式表没有任何 border 声明。该类只存在于宿主项目的全局样式表,而小程序自定义组件有样式隔离,能否命中取决于宿主引入全局样式的方式,于是出现同一个 tabbar 在首页有边框、切到另一个 tab 页边框消失。
|
|
17
|
+
|
|
18
|
+
- 改为在 tabbarStyle 里内联 borderTopWidth/Style/Color,边框跟着组件走
|
|
19
|
+
- 去掉 borderColor 上用来压全局类 !important 的 hack(nvue/weex 无法解析)
|
|
20
|
+
- 让 borderColor 为空时的主题边框色回退真正生效
|
|
21
|
+
- 新增 `verify:tabbar-border` 回归校验
|
|
22
|
+
|
|
23
|
+
## 3.8.118
|
|
24
|
+
修复 u-waterfall 在强制解锁后旧分配循环误释放新循环分发锁的问题。
|
|
25
|
+
|
|
26
|
+
旧循环在 await 后恢复时,现仅当前运行令牌的持有者可释放分发锁,避免接管循环与旧循环并发分配造成数据重复、列高错乱及回调重复触发。
|
|
27
|
+
|
|
28
|
+
## 3.8.117
|
|
29
|
+
fix: 修复瀑布流分发锁死、u-image 置于 u-swiper 内无法滑动、u-list-item 挂载竞态
|
|
30
|
+
|
|
31
|
+
本版为三个问题的集中修复,均不涉及组件 API 变更。
|
|
32
|
+
|
|
33
|
+
fix: 修复 u-waterfall 在 App 切换 tabbar 后不再消费新数据(#1056)
|
|
34
|
+
|
|
35
|
+
App 端切换 tabbar 时,原生层会挂起隐藏页面的 setTimeout,`await sleep()` 永不 resolve,`runDistributionQueue` 的 finally 块无法执行,`distributionRunning` 永久为 true;切回页面后新数据只能入队,永远不会被分发。
|
|
36
|
+
|
|
37
|
+
- `clear()` 强制重置 `distributionRunning` 与 `distributionPromise`
|
|
38
|
+
- `redistributeData()` 在调用 clear 之前先解锁
|
|
39
|
+
- 新增 `verify:waterfall-lock-reset` 回归校验
|
|
40
|
+
|
|
41
|
+
fix: 修复 u-image 置于 u-swiper 内导致手势滑动失效(#894)
|
|
42
|
+
|
|
43
|
+
u-transition 根节点绑定的 `@touchmove="noop"` 会执行 `e.stopPropagation()`,使 touchmove 无法冒泡到父级;u-image 以 u-transition 作为根节点,放进 u-swiper 的 slot 后 swiper 收不到 touchmove,滑动手势失效。该拦截对淡入、滑入等过渡动画本身没有作用,仅会阻断父组件的正常手势,故直接移除。
|
|
44
|
+
|
|
45
|
+
fix: 修复 u-list-item 在 parent 未初始化时调用 updateOffsetFromChild 报错(#875)
|
|
46
|
+
|
|
47
|
+
列表数据由后台异步返回、u-list-item 数量随之变化时,`uList.innerScrollTop` 的 watch 可能在 `mounted()` 之前触发;此时 `this.parent` 仍是 `created()` 中赋值的空对象,调用 `this.parent.updateOffsetFromChild` 会抛出 "is not a function"。
|
|
48
|
+
|
|
49
|
+
- watch 回调中增加守卫,parent 未就绪时直接返回
|
|
50
|
+
- 新增 `verify:list-item-parent-race` 回归校验
|
|
51
|
+
|
|
52
|
+
## 3.8.116
|
|
53
|
+
fix: 修复组件卸载后查询节点导致 APP 与鸿蒙端报错(#1057)
|
|
54
|
+
|
|
55
|
+
页面切换时 APP 与鸿蒙端会出现大面积 `Uncaught TypeError: Cannot read properties of undefined (reading '$') at uni-app-view.umd.js`,功能不受影响但日志被淹没,H5 端不出现。
|
|
56
|
+
|
|
57
|
+
原因是组件卸载后仍在执行的异步回调继续发起节点查询:APP 端 service 层取的是已失效的 `$el.nodeId`,视图层按该 id 查映射表时,对应条目在元素移除时已被删除,读到 undefined 再取 `.$` 即抛错。H5 端直接取 `$el`,没有这层 nodeId 映射,因此不复现。
|
|
58
|
+
|
|
59
|
+
- 在 `upGetRect` 与 `upCreateIntersectionObserver` 中集中拦截,覆盖全部三十余处调用方,卸载后不再把组件交给原生查询
|
|
60
|
+
- 卸载后 `upGetRect` 返回零尺寸节点信息,`upCreateIntersectionObserver` 返回空观察器,均保持原有调用形态,不需要调用方改写
|
|
61
|
+
- 卸载标记由公共 mixin 的 `beforeUnmount` 同步置位,早于 Vue 内部异步置位的 `isUnmounted`;未套用公共 mixin 的组件退回 Vue 自身标记
|
|
62
|
+
- 守卫置于条件编译之外,确保 app-harmony 端同样生效
|
|
63
|
+
- 新增 `verify:unmounted-node-query` 回归校验,同时断言挂载期间必须正常发起查询、卸载后必须完全不发起,并逐平台校验守卫存在
|
|
64
|
+
|
|
65
|
+
该问题在 tabs、sticky、subsection、waterfall、index-list 等所有依赖节点测量的组件上成因相同,本次为统一修复。
|
|
66
|
+
|
|
67
|
+
## 3.8.115
|
|
68
|
+
feat: u-select 遮罩默认可见并支持点击遮罩关闭开关
|
|
69
|
+
|
|
70
|
+
- overlayOpacity 默认由 0.01 调整为 0.3,遮罩真正可见,仍比 up-overlay 自身的 0.5 更浅
|
|
71
|
+
- overlayOpacity 类型放宽为 String / Number,可直接以普通属性方式传值
|
|
72
|
+
- 展开状态下把触发区抬到遮罩之上,避免下拉面板亮着而它的锚点被压暗
|
|
73
|
+
- 新增 closeOnClickOverlay 属性(默认 true),与 u-popup 命名一致;此前点击遮罩关闭为硬编码行为,现在可显式禁用
|
|
74
|
+
- 遮罩标签统一为 up-overlay,并补充 verify:select-overlay 回归校验
|
|
75
|
+
|
|
76
|
+
nvue 端对 z-index 支持有限,若被忽略则触发区可能落在遮罩之下,该端建议按需关闭 overlay。
|
|
77
|
+
|
|
78
|
+
## 3.8.114
|
|
79
|
+
fix: 修复 tabbar 中间按钮圆弧越界(#1052)
|
|
80
|
+
|
|
81
|
+
- 根据 tabbar 与中间按钮的实际位置计算圆弧裁剪高度
|
|
82
|
+
- 兼容文字、偏移、边框和动画场景,并补充回归校验
|
|
83
|
+
|
|
1
84
|
## 3.8.113(2026-08-27)
|
|
2
85
|
fix: 修复启用uniUpRoot,在root组件存在components选项时组件插入错误
|
|
3
86
|
|
|
@@ -7,25 +7,25 @@
|
|
|
7
7
|
<view class="oper-wrapper" :style="{ display: styleDisplay }">
|
|
8
8
|
<view class="oper">
|
|
9
9
|
<view class="btn-wrapper" v-if="showOper">
|
|
10
|
-
<view @click="select" hover-class="hover" :style="{ width: btnWidth }">
|
|
10
|
+
<view class="u-cropper__action" @click="select" hover-class="hover" :style="{ width: btnWidth }">
|
|
11
11
|
<text>{{ t("up.common.re-select") }}</text>
|
|
12
12
|
</view>
|
|
13
|
-
<view @click="close" hover-class="hover" :style="{ width: btnWidth }">
|
|
13
|
+
<view class="u-cropper__action" @click="close" hover-class="hover" :style="{ width: btnWidth }">
|
|
14
14
|
<text>{{ t("up.common.close") }}</text>
|
|
15
15
|
</view>
|
|
16
|
-
<view @click="rotate" hover-class="hover" :style="{ width: btnWidth, display: btnDsp }">
|
|
16
|
+
<view class="u-cropper__action" @click="rotate" hover-class="hover" :style="{ width: btnWidth, display: btnDsp }">
|
|
17
17
|
<text>{{ t("up.common.rotate") }}</text>
|
|
18
18
|
</view>
|
|
19
|
-
<view @click="preview" hover-class="hover" :style="{ width: btnWidth }">
|
|
19
|
+
<view class="u-cropper__action" @click="preview" hover-class="hover" :style="{ width: btnWidth }">
|
|
20
20
|
<text>{{ t("up.common.preview") }}</text>
|
|
21
21
|
</view>
|
|
22
|
-
<view @click="confirm" hover-class="hover" :style="{ width: btnWidth }">
|
|
22
|
+
<view class="u-cropper__action" @click="confirm" hover-class="hover" :style="{ width: btnWidth }">
|
|
23
23
|
<text>{{ t("up.common.confirm") }}</text>
|
|
24
24
|
</view>
|
|
25
25
|
</view>
|
|
26
26
|
<view class="clr-wrapper" v-else>
|
|
27
27
|
<slider class="my-slider" @change="colorChange" block-size="25" value="0" min="-100" max="100" activeColor="red" backgroundColor="green" block-color="grey" show-value></slider>
|
|
28
|
-
<view @click="prvUpload" hover-class="hover" :style="{ width: btnWidth }">
|
|
28
|
+
<view class="u-cropper__action" @click="prvUpload" hover-class="hover" :style="{ width: btnWidth }">
|
|
29
29
|
<text>{{ t("up.common.confirm") }}</text>
|
|
30
30
|
</view>
|
|
31
31
|
</view>
|
|
@@ -1267,7 +1267,7 @@
|
|
|
1267
1267
|
justify-content: space-between;
|
|
1268
1268
|
}
|
|
1269
1269
|
|
|
1270
|
-
.btn-wrapper
|
|
1270
|
+
.btn-wrapper .u-cropper__action {
|
|
1271
1271
|
display: flex;
|
|
1272
1272
|
align-items: center;
|
|
1273
1273
|
justify-content: center;
|
|
@@ -1288,7 +1288,7 @@
|
|
|
1288
1288
|
flex-grow: 1;
|
|
1289
1289
|
}
|
|
1290
1290
|
|
|
1291
|
-
.clr-wrapper
|
|
1291
|
+
.clr-wrapper .u-cropper__action {
|
|
1292
1292
|
display: flex;
|
|
1293
1293
|
align-items: center;
|
|
1294
1294
|
justify-content: center;
|
|
@@ -63,8 +63,7 @@
|
|
|
63
63
|
import { mpMixin } from '../../libs/mixin/mpMixin';
|
|
64
64
|
import { mixin } from '../../libs/mixin/mixin';
|
|
65
65
|
import dayjs from './dayjs.esm.min.js';
|
|
66
|
-
import { range, error, padZero } from '../../libs/function/index';
|
|
67
|
-
import test from '../../libs/function/test';
|
|
66
|
+
import { range, error, padZero, timeFormat } from '../../libs/function/index';
|
|
68
67
|
/**
|
|
69
68
|
* DatetimePicker 时间日期选择器
|
|
70
69
|
* @description 此选择器用于时间日期
|
|
@@ -72,6 +71,8 @@
|
|
|
72
71
|
* @property {Boolean} show 用于控制选择器的弹出与收起 ( 默认 false )
|
|
73
72
|
* @property {Boolean} showToolbar 是否显示顶部的操作栏 ( 默认 true )
|
|
74
73
|
* @property {String | Number} modelValue 绑定值
|
|
74
|
+
* @property {Boolean} hasInput 是否自带input输入框 ( 默认 false )
|
|
75
|
+
* @property {String} format hasInput模式下输入框的日期显示格式,同时支持 yyyy-mm-dd(uview-plus timeFormat 写法) 与 YYYY-MM-DD(dayjs 写法)
|
|
75
76
|
* @property {String} title 顶部标题
|
|
76
77
|
* @property {String} mode 展示格式 mode=date为日期选择,mode=time为时间选择,mode=year-month为年月选择,mode=datetime为日期时间选择,mode=datehour为日期小时选择,mode=timesecond为时分秒选择,mode=datetimesecond为日期时分秒选择 ( 默认 ‘datetime )
|
|
77
78
|
* @property {Number} maxDate 可选的最大时间 默认值为后10年
|
|
@@ -210,6 +211,16 @@
|
|
|
210
211
|
const value = column[index]
|
|
211
212
|
return value == null ? fallback : value
|
|
212
213
|
},
|
|
214
|
+
// format 有两种写法:uview-plus 自身 timeFormat($u.timeFormat) 的规则(yyyy-mm-dd hh:MM:ss,
|
|
215
|
+
// 小写 y 表示年、MM 表示分钟),以及 dayjs 的规则(YYYY-MM-DD HH:mm:ss)。
|
|
216
|
+
// dayjs 没有小写 y 的 token,以此区分两者:否则按库里通用写法传 'yyyy-mm-dd',
|
|
217
|
+
// dayjs 只认得其中的 mm(分钟)与 dd(星期),会得到 'yyyy-00-Th' 这种结果(issue #537)
|
|
218
|
+
formatByPattern(value, pattern) {
|
|
219
|
+
if (/y/.test(pattern)) {
|
|
220
|
+
return timeFormat(value, pattern)
|
|
221
|
+
}
|
|
222
|
+
return dayjs(value).format(pattern)
|
|
223
|
+
},
|
|
213
224
|
getInputValue(newValue) {
|
|
214
225
|
if (newValue == '' || !newValue || newValue == undefined) {
|
|
215
226
|
this.inputValue = ''
|
|
@@ -219,7 +230,7 @@
|
|
|
219
230
|
this.inputValue = newValue
|
|
220
231
|
} else {
|
|
221
232
|
if (this.format) {
|
|
222
|
-
this.inputValue =
|
|
233
|
+
this.inputValue = this.formatByPattern(newValue, this.format)
|
|
223
234
|
} else {
|
|
224
235
|
let format = ''
|
|
225
236
|
switch (this.mode) {
|
|
@@ -529,14 +540,39 @@
|
|
|
529
540
|
generateArray(start, end) {
|
|
530
541
|
return Array.from(new Array(end + 1).keys()).slice(start)
|
|
531
542
|
},
|
|
543
|
+
// 把绑定值统一解析成毫秒时间戳,识别不出日期时返回null
|
|
544
|
+
// 支持毫秒时间戳(number或纯数字字符串),以及'2024-10-24'、'2024/10/24 15:08:09'这类
|
|
545
|
+
// 文档里写明支持的String绑定值
|
|
546
|
+
parseDateValue(value) {
|
|
547
|
+
if (value === '' || value === null || value === undefined) {
|
|
548
|
+
return null
|
|
549
|
+
}
|
|
550
|
+
if (typeof value === 'number') {
|
|
551
|
+
return Number.isFinite(value) ? value : null
|
|
552
|
+
}
|
|
553
|
+
const text = String(value).trim()
|
|
554
|
+
if (!text) {
|
|
555
|
+
return null
|
|
556
|
+
}
|
|
557
|
+
// 纯数字按时间戳处理,避免dayjs把'1729699200000'当成日期字符串去解析
|
|
558
|
+
if (/^-?\d+$/.test(text)) {
|
|
559
|
+
const timestamp = Number(text)
|
|
560
|
+
return Number.isFinite(timestamp) ? timestamp : null
|
|
561
|
+
}
|
|
562
|
+
const parsed = dayjs(text)
|
|
563
|
+
return parsed.isValid() ? parsed.valueOf() : null
|
|
564
|
+
},
|
|
532
565
|
// 得出合法的时间
|
|
533
566
|
correctValue(value) {
|
|
534
567
|
const isDateMode = !['time', 'timesecond'].includes(this.mode)
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
//
|
|
538
|
-
|
|
539
|
-
|
|
568
|
+
if (isDateMode) {
|
|
569
|
+
// 日期类型统一解析成毫秒时间戳,没有设置合法的当前时间时才使用最小时间。
|
|
570
|
+
// 这里不能用dayjs.unix(value).isValid()判断:dayjs.unix只接受秒级数字,
|
|
571
|
+
// 日期字符串乘1000后是NaN,'2024-10-24'这类合法值会被判为非法并被替换成
|
|
572
|
+
// minDate(默认当前年份-10),选择器于是停在十年前(issue #537)
|
|
573
|
+
const timestamp = this.parseDateValue(value)
|
|
574
|
+
value = timestamp === null ? this.minDate : timestamp
|
|
575
|
+
} else if (!value) {
|
|
540
576
|
// 如果是时间类型,而又没有默认值的话,就用最小时间
|
|
541
577
|
value = this.mode === 'timesecond'
|
|
542
578
|
? `${padZero(this.minHour)}:${padZero(this.minMinute)}:${padZero(this.minSecond)}`
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
<view class="up-goods-sku__header">
|
|
17
17
|
<slot name="header">
|
|
18
18
|
<view class="up-goods-sku__header__image">
|
|
19
|
-
<image :src="goodsInfo.image || goodsInfo.picture" mode="aspectFill"></image>
|
|
19
|
+
<image class="up-goods-sku__header__image-element" :src="goodsInfo.image || goodsInfo.picture" mode="aspectFill"></image>
|
|
20
20
|
</view>
|
|
21
21
|
<view class="up-goods-sku__header__info">
|
|
22
22
|
<view class="up-goods-sku__header__info__price">
|
|
@@ -333,7 +333,7 @@
|
|
|
333
333
|
overflow: hidden;
|
|
334
334
|
margin-right: 20rpx;
|
|
335
335
|
|
|
336
|
-
|
|
336
|
+
&-element {
|
|
337
337
|
width: 100%;
|
|
338
338
|
height: 100%;
|
|
339
339
|
}
|
|
@@ -49,6 +49,10 @@
|
|
|
49
49
|
watch: {
|
|
50
50
|
// #ifndef APP-NVUE
|
|
51
51
|
'uList.innerScrollTop'(n) {
|
|
52
|
+
// 确保parent已正确初始化,避免在mounted之前触发watch导致报错
|
|
53
|
+
if (!this.parent || !this.parent.updateOffsetFromChild) {
|
|
54
|
+
return
|
|
55
|
+
}
|
|
52
56
|
const preLoadScreen = this.uList.preLoadScreen
|
|
53
57
|
const windowHeight = this.sys.windowHeight
|
|
54
58
|
if(n <= windowHeight * preLoadScreen) {
|
|
@@ -1,3 +1,16 @@
|
|
|
1
|
+
/* #ifdef MP-WEIXIN */
|
|
2
|
+
:host {
|
|
3
|
+
--up-navbar-bg-color: #ffffff;
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
@media (prefers-color-scheme: dark) {
|
|
7
|
+
:host {
|
|
8
|
+
--up-navbar-bg-color: #1c1c1e;
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
/* #endif */
|
|
12
|
+
|
|
13
|
+
/* #ifndef MP-WEIXIN */
|
|
1
14
|
:root,
|
|
2
15
|
page,
|
|
3
16
|
body {
|
|
@@ -24,3 +37,4 @@ body {
|
|
|
24
37
|
--up-navbar-bg-color: #1c1c1e;
|
|
25
38
|
--up-navbar-glass-bg-color: rgba(28, 28, 30, 0.82);
|
|
26
39
|
}
|
|
40
|
+
/* #endif */
|
|
@@ -1,3 +1,18 @@
|
|
|
1
|
+
/* #ifdef MP-WEIXIN */
|
|
2
|
+
:host {
|
|
3
|
+
--up-notice-bar-color: #f9ae3d;
|
|
4
|
+
--up-notice-bar-bg-color: #fdf6ec;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
@media (prefers-color-scheme: dark) {
|
|
8
|
+
:host {
|
|
9
|
+
--up-notice-bar-color: #f9ae3d;
|
|
10
|
+
--up-notice-bar-bg-color: #3d2f1b;
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
/* #endif */
|
|
14
|
+
|
|
15
|
+
/* #ifndef MP-WEIXIN */
|
|
1
16
|
:root,
|
|
2
17
|
page,
|
|
3
18
|
body {
|
|
@@ -23,3 +38,4 @@ body {
|
|
|
23
38
|
--up-notice-bar-color: #f9ae3d;
|
|
24
39
|
--up-notice-bar-bg-color: #3d2f1b;
|
|
25
40
|
}
|
|
41
|
+
/* #endif */
|
|
@@ -53,14 +53,14 @@
|
|
|
53
53
|
<!-- #endif -->
|
|
54
54
|
<view v-else-if="(n.name==='table'&&n.c)||n.name==='li'" :id="n.attrs.id" :class="'_'+n.name+' '+n.attrs.class" :style="n.attrs.style">
|
|
55
55
|
<node v-if="n.name==='li'" :childs="n.children" :opts="opts" />
|
|
56
|
-
<view v-else v-for="(tbody, x) in n.children" v-bind:key="x" :class="'_'+tbody.name+' '+tbody.attrs.class" :style="tbody.attrs.style">
|
|
56
|
+
<view v-else v-for="(tbody, x) in (n && n.children || [])" v-bind:key="x" :class="'_'+tbody.name+' '+tbody.attrs.class" :style="tbody.attrs.style">
|
|
57
57
|
<node v-if="tbody.name==='td'||tbody.name==='th'" :childs="tbody.children" :opts="opts" />
|
|
58
|
-
<block v-else v-for="(tr, y) in tbody.children" v-bind:key="y">
|
|
58
|
+
<block v-else v-for="(tr, y) in (tbody && tbody.children || [])" v-bind:key="y">
|
|
59
59
|
<view v-if="tr.name==='td'||tr.name==='th'" :class="'_'+tr.name+' '+tr.attrs.class" :style="tr.attrs.style">
|
|
60
60
|
<node :childs="tr.children" :opts="opts" />
|
|
61
61
|
</view>
|
|
62
62
|
<view v-else :class="'_'+tr.name+' '+tr.attrs.class" :style="tr.attrs.style">
|
|
63
|
-
<view v-for="(td, z) in tr.children" v-bind:key="z" :class="'_'+td.name+' '+td.attrs.class" :style="td.attrs.style">
|
|
63
|
+
<view v-for="(td, z) in (tr && tr.children || [])" v-bind:key="z" :class="'_'+td.name+' '+td.attrs.class" :style="td.attrs.style">
|
|
64
64
|
<node :childs="td.children" :opts="opts" />
|
|
65
65
|
</view>
|
|
66
66
|
</view>
|
|
@@ -70,7 +70,7 @@
|
|
|
70
70
|
<!-- insert -->
|
|
71
71
|
<!-- 富文本 -->
|
|
72
72
|
<!-- #ifdef H5 || ((MP-WEIXIN || MP-QQ || APP-PLUS || MP-360) && VUE2) -->
|
|
73
|
-
<rich-text v-else-if="!n.c&&!
|
|
73
|
+
<rich-text v-else-if="!n.c&&!isInlineTag(n.name, n.attrs.style)" :id="n.attrs.id" :style="n.f" :user-select="opts[4]" :nodes="[n]" />
|
|
74
74
|
<!-- #endif -->
|
|
75
75
|
<!-- #ifndef H5 || ((MP-WEIXIN || MP-QQ || APP-PLUS || MP-360) && VUE2) -->
|
|
76
76
|
<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]" />
|
|
@@ -185,6 +185,25 @@ export default {
|
|
|
185
185
|
// #ifdef MP-WEIXIN
|
|
186
186
|
toJSON () { return this },
|
|
187
187
|
// #endif
|
|
188
|
+
isInlineTag (tagName, style) {
|
|
189
|
+
return {
|
|
190
|
+
abbr: true,
|
|
191
|
+
b: true,
|
|
192
|
+
big: true,
|
|
193
|
+
code: true,
|
|
194
|
+
del: true,
|
|
195
|
+
em: true,
|
|
196
|
+
i: true,
|
|
197
|
+
ins: true,
|
|
198
|
+
label: true,
|
|
199
|
+
q: true,
|
|
200
|
+
small: true,
|
|
201
|
+
span: true,
|
|
202
|
+
strong: true,
|
|
203
|
+
sub: true,
|
|
204
|
+
sup: true
|
|
205
|
+
}[tagName] || (style || '').indexOf('display:inline') !== -1
|
|
206
|
+
},
|
|
188
207
|
/**
|
|
189
208
|
* @description 规范化链接地址
|
|
190
209
|
* @param {any} href
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<view class="u-select">
|
|
3
3
|
<view :class="['u-select__content', disabled && 'disabled']">
|
|
4
|
-
<view :class="['u-select__label', border && 'u-select__label--border']" :style="selectLabelStyle" @click="
|
|
4
|
+
<view :class="['u-select__label', border && 'u-select__label--border']" :style="selectLabelStyle" @click="labelClick">
|
|
5
5
|
<slot name="text" :currentLabel="currentLabel">
|
|
6
6
|
<text class="u-select__text" :style="{ color: resolvedTextColor }" v-if="showOptionsLabel">
|
|
7
7
|
{{ currentLabel }}
|
|
@@ -14,8 +14,8 @@
|
|
|
14
14
|
<up-icon name="arrow-down" :size="iconSize" :color="resolvedIconColor"></up-icon>
|
|
15
15
|
</slot>
|
|
16
16
|
</view>
|
|
17
|
-
<
|
|
18
|
-
:customStyle="overlayStyle" :opacity="overlayOpacity" @touchmove.stop.prevent="noop"></
|
|
17
|
+
<up-overlay :show="isOpen" @click="overlayClick" v-if="overlay" :zIndex="zIndex" :duration="duration + 50"
|
|
18
|
+
:customStyle="overlayStyle" :opacity="overlayOpacity" @touchmove.stop.prevent="noop"></up-overlay>
|
|
19
19
|
<view class="u-select__options__wrap" :style="optionsWrapStyle">
|
|
20
20
|
<view class="u-select__options" :style="optionsStyle" v-if="isOpen">
|
|
21
21
|
<slot name="options">
|
|
@@ -59,8 +59,8 @@
|
|
|
59
59
|
default: true
|
|
60
60
|
},
|
|
61
61
|
overlayOpacity: {
|
|
62
|
-
type: Number,
|
|
63
|
-
default: 0.
|
|
62
|
+
type: [String, Number],
|
|
63
|
+
default: 0.3
|
|
64
64
|
},
|
|
65
65
|
overlayStyle: {
|
|
66
66
|
type: Object,
|
|
@@ -68,6 +68,11 @@
|
|
|
68
68
|
return {}
|
|
69
69
|
}
|
|
70
70
|
},
|
|
71
|
+
// 点击遮罩是否关闭下拉面板
|
|
72
|
+
closeOnClickOverlay: {
|
|
73
|
+
type: Boolean,
|
|
74
|
+
default: true
|
|
75
|
+
},
|
|
71
76
|
duration: {
|
|
72
77
|
type: Number,
|
|
73
78
|
default: 300
|
|
@@ -157,11 +162,17 @@
|
|
|
157
162
|
return this.optionsWidth;
|
|
158
163
|
},
|
|
159
164
|
selectLabelStyle() {
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
borderColor
|
|
163
|
-
backgroundColor
|
|
164
|
-
}
|
|
165
|
+
const style = {};
|
|
166
|
+
if (this.border) {
|
|
167
|
+
style.borderColor = this.upThemeVar('--up-border-color', '#dadbde');
|
|
168
|
+
style.backgroundColor = this.upThemeVar('--up-card-bg-color', '#ffffff');
|
|
169
|
+
}
|
|
170
|
+
// 遮罩可见时把触发区抬到遮罩之上,避免下拉面板亮着而它的锚点被压暗
|
|
171
|
+
if (this.isOpen && this.overlay) {
|
|
172
|
+
style.position = 'relative';
|
|
173
|
+
style.zIndex = this.zIndex + 1;
|
|
174
|
+
}
|
|
175
|
+
return style;
|
|
165
176
|
},
|
|
166
177
|
optionsWrapStyle() {
|
|
167
178
|
const style = {
|
|
@@ -195,6 +206,14 @@
|
|
|
195
206
|
}
|
|
196
207
|
},
|
|
197
208
|
methods: {
|
|
209
|
+
labelClick() {
|
|
210
|
+
// 触发区被抬到遮罩之上后,遮罩不再代收这次点击,需要自己处理收起
|
|
211
|
+
if (this.isOpen) {
|
|
212
|
+
this.closeSelect();
|
|
213
|
+
return;
|
|
214
|
+
}
|
|
215
|
+
this.openSelect();
|
|
216
|
+
},
|
|
198
217
|
openSelect() {
|
|
199
218
|
if (this.disabled) return;
|
|
200
219
|
this.isOpen = true;
|
|
@@ -208,7 +227,8 @@
|
|
|
208
227
|
this.isOpen = false;
|
|
209
228
|
},
|
|
210
229
|
overlayClick() {
|
|
211
|
-
this.
|
|
230
|
+
if (!this.closeOnClickOverlay) return;
|
|
231
|
+
this.closeSelect();
|
|
212
232
|
},
|
|
213
233
|
selectItem(item) {
|
|
214
234
|
this.isOpen = false;
|
|
@@ -1,3 +1,26 @@
|
|
|
1
|
+
/* #ifdef MP-WEIXIN */
|
|
2
|
+
:host {
|
|
3
|
+
--up-subsection-bg-color: #eeeeef;
|
|
4
|
+
--up-subsection-bar-color: #ffffff;
|
|
5
|
+
--up-subsection-inactive-color: #303133;
|
|
6
|
+
--up-subsection-disabled-text-color: #c8c9cc;
|
|
7
|
+
--up-subsection-disabled-border-color: #d4d4d4;
|
|
8
|
+
--up-subsection-disabled-bar-color: #f5f5f5;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
@media (prefers-color-scheme: dark) {
|
|
12
|
+
:host {
|
|
13
|
+
--up-subsection-bg-color: #2b2c30;
|
|
14
|
+
--up-subsection-bar-color: #3a3b40;
|
|
15
|
+
--up-subsection-inactive-color: #d1d5db;
|
|
16
|
+
--up-subsection-disabled-text-color: #6b7280;
|
|
17
|
+
--up-subsection-disabled-border-color: #3a3a3c;
|
|
18
|
+
--up-subsection-disabled-bar-color: #3a3a3c;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
/* #endif */
|
|
22
|
+
|
|
23
|
+
/* #ifndef MP-WEIXIN */
|
|
1
24
|
:root,
|
|
2
25
|
page,
|
|
3
26
|
body {
|
|
@@ -39,3 +62,4 @@ body {
|
|
|
39
62
|
--up-subsection-disabled-border-color: #3a3a3c;
|
|
40
63
|
--up-subsection-disabled-bar-color: #3a3a3c;
|
|
41
64
|
}
|
|
65
|
+
/* #endif */
|
|
@@ -1,3 +1,26 @@
|
|
|
1
|
+
/* #ifdef MP-WEIXIN */
|
|
2
|
+
:host {
|
|
3
|
+
--up-switch-active-color: #3c9cff;
|
|
4
|
+
--up-switch-inactive-color: #ffffff;
|
|
5
|
+
--up-switch-dot-active-color: #ffffff;
|
|
6
|
+
--up-switch-dot-inactive-color: #ffffff;
|
|
7
|
+
--up-switch-loading-inactive-color: #aaabad;
|
|
8
|
+
--up-switch-border-color: rgba(0, 0, 0, 0.12);
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
@media (prefers-color-scheme: dark) {
|
|
12
|
+
:host {
|
|
13
|
+
--up-switch-active-color: #3c9cff;
|
|
14
|
+
--up-switch-inactive-color: #3a3a3c;
|
|
15
|
+
--up-switch-dot-active-color: #ffffff;
|
|
16
|
+
--up-switch-dot-inactive-color: #d1d5db;
|
|
17
|
+
--up-switch-loading-inactive-color: #9ca3af;
|
|
18
|
+
--up-switch-border-color: #4b5563;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
/* #endif */
|
|
22
|
+
|
|
23
|
+
/* #ifndef MP-WEIXIN */
|
|
1
24
|
:root,
|
|
2
25
|
page,
|
|
3
26
|
body {
|
|
@@ -39,3 +62,4 @@ body {
|
|
|
39
62
|
--up-switch-loading-inactive-color: #9ca3af;
|
|
40
63
|
--up-switch-border-color: #4b5563;
|
|
41
64
|
}
|
|
65
|
+
/* #endif */
|
|
@@ -5,7 +5,6 @@
|
|
|
5
5
|
ref="u-tabbar__content"
|
|
6
6
|
@touchmove.stop.prevent="noop"
|
|
7
7
|
:class="[
|
|
8
|
-
border && 'u-border-top',
|
|
9
8
|
fixed && 'u-tabbar--fixed',
|
|
10
9
|
`u-tabbar--${styleType}`,
|
|
11
10
|
textMode === 'active' && 'u-tabbar--text-active'
|
|
@@ -67,6 +66,10 @@
|
|
|
67
66
|
}
|
|
68
67
|
},
|
|
69
68
|
computed: {
|
|
69
|
+
// 顶部边框颜色,未指定borderColor时回退到主题边框色
|
|
70
|
+
tabbarBorderColor() {
|
|
71
|
+
return this.borderColor || this.upThemeVar('--up-border-color', '#dadbde')
|
|
72
|
+
},
|
|
70
73
|
tabbarStyle() {
|
|
71
74
|
const style = {
|
|
72
75
|
zIndex: this.zIndex,
|
|
@@ -75,10 +78,13 @@
|
|
|
75
78
|
'--up-tabbar-inactive-bg': this.inactiveBackgroundColor || 'transparent',
|
|
76
79
|
'--up-tabbar-icon-scale': `${this.iconScale}`
|
|
77
80
|
}
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
81
|
+
// 顶部边框由组件自身内联样式绘制,不再依赖全局的u-border-top工具类。
|
|
82
|
+
// 小程序自定义组件存在样式隔离,全局类名是否能作用到组件内部节点取决于宿主项目
|
|
83
|
+
// 引入全局样式的方式,会出现同一个tabbar在部分页面有边框、切换页面后边框丢失的问题。
|
|
84
|
+
if (this.border) {
|
|
85
|
+
style.borderTopWidth = '0.5px'
|
|
86
|
+
style.borderTopStyle = 'solid'
|
|
87
|
+
style.borderTopColor = this.tabbarBorderColor
|
|
82
88
|
}
|
|
83
89
|
if (['pill', 'card', 'glow', 'convex'].includes(this.styleType)) {
|
|
84
90
|
style.padding = '8rpx 12rpx 12rpx'
|
|
@@ -99,9 +105,14 @@
|
|
|
99
105
|
this.itemShape,
|
|
100
106
|
this.iconScale,
|
|
101
107
|
this.textMode,
|
|
102
|
-
this.borderColor
|
|
108
|
+
this.borderColor,
|
|
109
|
+
this.border,
|
|
110
|
+
this.customStyle
|
|
103
111
|
]
|
|
104
112
|
},
|
|
113
|
+
midButtonBorderTopOffset() {
|
|
114
|
+
return this.border ? 0.25 : 0
|
|
115
|
+
},
|
|
105
116
|
updatePlaceholder() {
|
|
106
117
|
return [this.fixed, this.placeholder]
|
|
107
118
|
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
const MID_BUTTON_SIZE = 64
|
|
2
|
+
|
|
3
|
+
export function clampMidButtonBorderClipHeight(value) {
|
|
4
|
+
const height = Number(value)
|
|
5
|
+
if (!Number.isFinite(height)) return 0
|
|
6
|
+
return Math.min(Math.max(height, 0), MID_BUTTON_SIZE)
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export function calculateMidButtonBorderClipHeight({
|
|
10
|
+
contentTop,
|
|
11
|
+
circleTop,
|
|
12
|
+
borderTopOffset = 0
|
|
13
|
+
}) {
|
|
14
|
+
const targetTop = Number(contentTop)
|
|
15
|
+
const currentTop = Number(circleTop)
|
|
16
|
+
const borderOffset = Number(borderTopOffset)
|
|
17
|
+
if (![targetTop, currentTop, borderOffset].every(Number.isFinite)) return 0
|
|
18
|
+
return clampMidButtonBorderClipHeight(targetTop + borderOffset - currentTop)
|
|
19
|
+
}
|