@tplc/business 0.2.37 → 0.2.39
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 +25 -0
- package/components/lcb-list/lcb-list.vue +7 -2
- package/components/lcb-product/lcb-product.vue +88 -157
- package/components/lcb-product/types.ts +1 -0
- package/components/lcb-product-item/components/ItemValue.vue +14 -2
- package/components/lcb-product-item/lcb-product-item.vue +14 -3
- package/components/lcb-product-item/types.ts +3 -0
- package/components/lcb-rich-text/lcb-rich-text.vue +0 -1
- package/components/lcb-waterfall/lcb-waterfall-item.vue +191 -0
- package/components/lcb-waterfall/lcb-waterfall.vue +550 -0
- package/components/lcb-waterfall/types.ts +3 -0
- package/global.d.ts +1 -0
- package/package.json +2 -2
- package/types/components/lcb-product/lcb-product.vue.d.ts +1 -0
- package/types/components/lcb-product/types.d.ts +1 -0
- package/types/components/lcb-product-item/components/ItemValue.vue.d.ts +4 -0
- package/types/components/lcb-product-item/lcb-product-item.vue.d.ts +7 -0
- package/types/components/lcb-product-item/types.d.ts +3 -0
- package/types/components/lcb-waterfall/lcb-waterfall-item.vue.d.ts +73 -0
- package/types/components/lcb-waterfall/lcb-waterfall.vue.d.ts +192 -0
|
@@ -0,0 +1,550 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<view class="miran-waterfall">
|
|
3
|
+
<!-- #ifndef APP-NVUE -->
|
|
4
|
+
<view class="miran-waterfall__gap_left" :style="[gapLeftStyle]"></view>
|
|
5
|
+
<template v-if="columnNum >= 1">
|
|
6
|
+
<view id="miran-waterfall-1" class="miran-waterfall__column">
|
|
7
|
+
<slot name="list1"></slot>
|
|
8
|
+
</view>
|
|
9
|
+
</template>
|
|
10
|
+
<template v-if="columnNum >= 2">
|
|
11
|
+
<view class="miran-waterfall__gap_center" :style="[gapCenterStyle]"></view>
|
|
12
|
+
<view id="miran-waterfall-2" class="miran-waterfall__column">
|
|
13
|
+
<slot name="list2"></slot>
|
|
14
|
+
</view>
|
|
15
|
+
</template>
|
|
16
|
+
<template v-if="columnNum >= 3">
|
|
17
|
+
<view class="miran-waterfall__gap_center" :style="[gapCenterStyle]"></view>
|
|
18
|
+
<view id="miran-waterfall-3" class="miran-waterfall__column">
|
|
19
|
+
<slot name="list3"></slot>
|
|
20
|
+
</view>
|
|
21
|
+
</template>
|
|
22
|
+
<template v-if="columnNum >= 4">
|
|
23
|
+
<view class="miran-waterfall__gap_center" :style="[gapCenterStyle]"></view>
|
|
24
|
+
<view id="miran-waterfall-4" class="miran-waterfall__column">
|
|
25
|
+
<slot name="list4"></slot>
|
|
26
|
+
</view>
|
|
27
|
+
</template>
|
|
28
|
+
<template v-if="columnNum >= 5">
|
|
29
|
+
<view class="miran-waterfall__gap_center" :style="[gapCenterStyle]"></view>
|
|
30
|
+
<view id="miran-waterfall-5" class="miran-waterfall__column">
|
|
31
|
+
<slot name="list5"></slot>
|
|
32
|
+
</view>
|
|
33
|
+
</template>
|
|
34
|
+
<view class="miran-waterfall__gap_right" :style="[gapRightStyle]"></view>
|
|
35
|
+
<!-- #endif -->
|
|
36
|
+
<!-- #ifdef APP-NVUE -->
|
|
37
|
+
<view class="waterfall-warapper">
|
|
38
|
+
<waterfall
|
|
39
|
+
:column-count="columnNum"
|
|
40
|
+
:show-scrollbar="false"
|
|
41
|
+
column-width="auto"
|
|
42
|
+
:column-gap="columnGap"
|
|
43
|
+
:left-gap="leftGap"
|
|
44
|
+
:right-gap="rightGap"
|
|
45
|
+
:always-scrollable-vertical="true"
|
|
46
|
+
:style="[nvueWaterfallStyle]"
|
|
47
|
+
@loadmore="scrollToBottom"
|
|
48
|
+
>
|
|
49
|
+
<slot></slot>
|
|
50
|
+
</waterfall>
|
|
51
|
+
</view>
|
|
52
|
+
<!-- #endif -->
|
|
53
|
+
</view>
|
|
54
|
+
</template>
|
|
55
|
+
<script>
|
|
56
|
+
/**
|
|
57
|
+
* 瀑布流
|
|
58
|
+
* @description
|
|
59
|
+
* @tutorial
|
|
60
|
+
* @property {Array} value/modelValue 瀑布流数组数据,非nvue生效 (默认 [] )
|
|
61
|
+
* @property {String} idKey 数据的id值,根据id值对数据执行删除操作,如数据为:{id: 1, name: 'uv-ui'},那么该值设置为id,非nvue有效 (默认 '' )
|
|
62
|
+
* @property {String | Number} addTime 每次插入数据的事件间隔,间隔越长能保证两列高度相近,但是用户体验不好,单位ms,非nvue生效(默认 200 )
|
|
63
|
+
* @property {String | Number} columnCount 瀑布流的列数(默认 2 )
|
|
64
|
+
* @property {String | Number} columnGap 列与列的间隙(默认 0 )
|
|
65
|
+
* @property {String | Number} leftGap 左边和列表的间隙(默认 0 )
|
|
66
|
+
* @property {String | Number} rightGap 右边和列表的间隙(默认 0 )
|
|
67
|
+
* @property {Boolean} showScrollbar 控制是否出现滚动条,仅nvue有效 (默认 false )
|
|
68
|
+
* @property {String | Number} width 瀑布流的宽度,nvue生效 (默认 屏幕宽 )
|
|
69
|
+
* @property {String | Number} height 瀑布流的高度,nvue生效 (默认 屏幕高 )
|
|
70
|
+
* @property {Object} customStyle 定义需要用到的外部样式
|
|
71
|
+
*
|
|
72
|
+
* @example <miran-waterfall v-model="list"></miran-waterfall>
|
|
73
|
+
*/
|
|
74
|
+
export default {
|
|
75
|
+
name: 'miran-waterfall',
|
|
76
|
+
props: {
|
|
77
|
+
// 瀑布流数据
|
|
78
|
+
// #ifdef VUE2
|
|
79
|
+
value: {
|
|
80
|
+
type: Array,
|
|
81
|
+
default: () => [],
|
|
82
|
+
},
|
|
83
|
+
// #endif
|
|
84
|
+
// #ifdef VUE3
|
|
85
|
+
modelValue: {
|
|
86
|
+
type: Array,
|
|
87
|
+
default: () => [],
|
|
88
|
+
},
|
|
89
|
+
// #endif
|
|
90
|
+
// 数据的id值,根据id值对数据执行删除操作
|
|
91
|
+
// 如数据为:{id: 1, name: 'uv-ui'},那么该值设置为id
|
|
92
|
+
idKey: {
|
|
93
|
+
type: String,
|
|
94
|
+
default: 'id',
|
|
95
|
+
},
|
|
96
|
+
// 每次插入数据的事件间隔,间隔越长能保证两列高度相近,但是用户体验不好,单位ms
|
|
97
|
+
addTime: {
|
|
98
|
+
type: Number,
|
|
99
|
+
default: 200,
|
|
100
|
+
},
|
|
101
|
+
// 瀑布流的列数,默认2,最高为5
|
|
102
|
+
columnCount: {
|
|
103
|
+
type: [Number, String],
|
|
104
|
+
default: 2,
|
|
105
|
+
},
|
|
106
|
+
// 列与列的间隙,默认20
|
|
107
|
+
columnGap: {
|
|
108
|
+
type: [Number, String],
|
|
109
|
+
default: 10,
|
|
110
|
+
},
|
|
111
|
+
// 左边和列表的间隙
|
|
112
|
+
leftGap: {
|
|
113
|
+
type: [Number, String],
|
|
114
|
+
default: 15,
|
|
115
|
+
},
|
|
116
|
+
// 右边和列表的间隙
|
|
117
|
+
rightGap: {
|
|
118
|
+
type: [Number, String],
|
|
119
|
+
default: 15,
|
|
120
|
+
},
|
|
121
|
+
// 是否显示滚动条,仅nvue生效
|
|
122
|
+
showScrollbar: {
|
|
123
|
+
type: [Boolean],
|
|
124
|
+
default: false,
|
|
125
|
+
},
|
|
126
|
+
// 瀑布流的宽度,nvue生效
|
|
127
|
+
width: {
|
|
128
|
+
type: [Number, String],
|
|
129
|
+
default: '',
|
|
130
|
+
},
|
|
131
|
+
// 瀑布流的高度,nvue生效
|
|
132
|
+
height: {
|
|
133
|
+
type: [Number, String],
|
|
134
|
+
default: '',
|
|
135
|
+
},
|
|
136
|
+
},
|
|
137
|
+
|
|
138
|
+
computed: {
|
|
139
|
+
// 破坏value变量引用,否则数据会保持不变
|
|
140
|
+
valueCom() {
|
|
141
|
+
// #ifdef VUE2
|
|
142
|
+
return this.value
|
|
143
|
+
// #endif
|
|
144
|
+
},
|
|
145
|
+
copyValue() {
|
|
146
|
+
return uni.$g.obj.deepClone(this.valueCom)
|
|
147
|
+
},
|
|
148
|
+
columnNum() {
|
|
149
|
+
return this.columnCount <= 0 ? 0 : this.columnCount >= 5 ? 5 : this.columnCount
|
|
150
|
+
},
|
|
151
|
+
gapLeftStyle() {
|
|
152
|
+
const style = {}
|
|
153
|
+
style.width = this.addUnit(this.leftGap)
|
|
154
|
+
return style
|
|
155
|
+
},
|
|
156
|
+
gapRightStyle() {
|
|
157
|
+
const style = {}
|
|
158
|
+
style.width = this.addUnit(this.rightGap)
|
|
159
|
+
return style
|
|
160
|
+
},
|
|
161
|
+
gapCenterStyle() {
|
|
162
|
+
const style = {}
|
|
163
|
+
style.width = this.addUnit(this.columnGap)
|
|
164
|
+
return style
|
|
165
|
+
},
|
|
166
|
+
nvueWaterfallStyle() {
|
|
167
|
+
const style = {}
|
|
168
|
+
if (this.width !== 0) style.width = this.addUnit(this.width)
|
|
169
|
+
if (this.height !== 0) style.height = this.addUnit(this.height)
|
|
170
|
+
// 如果没有定义列表高度,则默认使用屏幕高度
|
|
171
|
+
const sysInfo = uni.getSystemInfoSync()
|
|
172
|
+
if (!style.width) style.width = this.addUnit(sysInfo.windowWidth, 'px')
|
|
173
|
+
if (!style.height) style.height = this.addUnit(sysInfo.windowHeight, 'px')
|
|
174
|
+
return uni.$g.obj.deepMerge(style, this.$uv.addStyle(this.customStyle))
|
|
175
|
+
},
|
|
176
|
+
},
|
|
177
|
+
watch: {
|
|
178
|
+
copyValue: {
|
|
179
|
+
// #ifndef APP-NVUE
|
|
180
|
+
handler(nVal, oVal) {
|
|
181
|
+
if (nVal.length !== 0) {
|
|
182
|
+
// 取出数组发生变化的部分
|
|
183
|
+
const startIndex = Array.isArray(oVal) && oVal.length > 0 ? oVal.length : 0
|
|
184
|
+
// 拼接原有数据
|
|
185
|
+
this.tempList = this.tempList.concat(uni.$g.obj.deepClone(nVal.slice(startIndex)))
|
|
186
|
+
this.splitData()
|
|
187
|
+
}
|
|
188
|
+
},
|
|
189
|
+
immediate: true,
|
|
190
|
+
deep: true,
|
|
191
|
+
// #endif
|
|
192
|
+
},
|
|
193
|
+
},
|
|
194
|
+
data() {
|
|
195
|
+
return {
|
|
196
|
+
list1: [],
|
|
197
|
+
list2: [],
|
|
198
|
+
list3: [],
|
|
199
|
+
list4: [],
|
|
200
|
+
list5: [],
|
|
201
|
+
// 临时列表
|
|
202
|
+
tempList: [],
|
|
203
|
+
columnWidth: 0,
|
|
204
|
+
columnHeights: [],
|
|
205
|
+
}
|
|
206
|
+
},
|
|
207
|
+
created() {
|
|
208
|
+
this.columnHeights = new Array(this.columnNum).fill(0)
|
|
209
|
+
this.columnWidth =
|
|
210
|
+
(uni.upx2px(750) - this.leftGap - this.rightGap - (this.columnNum - 1) * this.columnGap) /
|
|
211
|
+
this.columnNum
|
|
212
|
+
},
|
|
213
|
+
methods: {
|
|
214
|
+
/**
|
|
215
|
+
* 添加单位
|
|
216
|
+
*/
|
|
217
|
+
addUnit: function (value = 'auto', unit = 'px') {
|
|
218
|
+
value = String(value)
|
|
219
|
+
// 用uvui内置验证规则中的number判断是否为数值
|
|
220
|
+
return uni.$g.valid.number(value) ? `${value}${unit}` : value
|
|
221
|
+
},
|
|
222
|
+
/**
|
|
223
|
+
* 进行延时
|
|
224
|
+
*/
|
|
225
|
+
sleep: function (value = 30) {
|
|
226
|
+
return new Promise((resolve) => {
|
|
227
|
+
setTimeout(() => {
|
|
228
|
+
resolve()
|
|
229
|
+
}, value)
|
|
230
|
+
})
|
|
231
|
+
},
|
|
232
|
+
/**
|
|
233
|
+
* 媒体查询
|
|
234
|
+
* @param {Object} selector
|
|
235
|
+
* @param {Object} context
|
|
236
|
+
*/
|
|
237
|
+
getRect: function (selector, context) {
|
|
238
|
+
return new Promise((resolve) => {
|
|
239
|
+
const query = uni.createSelectorQuery().in(context)
|
|
240
|
+
query
|
|
241
|
+
.select(selector)
|
|
242
|
+
.boundingClientRect((rect) => {
|
|
243
|
+
rect ? resolve(rect) : resolve(false)
|
|
244
|
+
})
|
|
245
|
+
.exec()
|
|
246
|
+
})
|
|
247
|
+
},
|
|
248
|
+
/**
|
|
249
|
+
* 去除空格
|
|
250
|
+
*/
|
|
251
|
+
trim: function (str, pos = 'both') {
|
|
252
|
+
str = String(str)
|
|
253
|
+
if (pos === 'both') {
|
|
254
|
+
return str.replace(/^\s+|\s+$/g, '')
|
|
255
|
+
}
|
|
256
|
+
if (pos === 'left') {
|
|
257
|
+
return str.replace(/^\s*/, '')
|
|
258
|
+
}
|
|
259
|
+
if (pos === 'right') {
|
|
260
|
+
return str.replace(/(\s*$)/g, '')
|
|
261
|
+
}
|
|
262
|
+
if (pos === 'all') {
|
|
263
|
+
return str.replace(/\s+/g, '')
|
|
264
|
+
}
|
|
265
|
+
return str
|
|
266
|
+
},
|
|
267
|
+
/**
|
|
268
|
+
* 样式转换
|
|
269
|
+
*/
|
|
270
|
+
addStyle: function (customStyle, target = 'object') {
|
|
271
|
+
// 字符串转字符串,对象转对象情形,直接返回
|
|
272
|
+
if (
|
|
273
|
+
uni.$g.valid.empty(customStyle) ||
|
|
274
|
+
(typeof customStyle === 'object' && target === 'object') ||
|
|
275
|
+
(target === 'string' && typeof customStyle === 'string')
|
|
276
|
+
) {
|
|
277
|
+
return customStyle
|
|
278
|
+
}
|
|
279
|
+
// 字符串转对象
|
|
280
|
+
if (target === 'object') {
|
|
281
|
+
// 去除字符串样式中的两端空格(中间的空格不能去掉,比如padding: 20px 0如果去掉了就错了),空格是无用的
|
|
282
|
+
customStyle = this.trim(customStyle)
|
|
283
|
+
// 根据";"将字符串转为数组形式
|
|
284
|
+
const styleArray = customStyle.split(';')
|
|
285
|
+
const style = {}
|
|
286
|
+
// 历遍数组,拼接成对象
|
|
287
|
+
for (let i = 0; i < styleArray.length; i++) {
|
|
288
|
+
// 'font-size:20px;color:red;',如此最后字符串有";"的话,会导致styleArray最后一个元素为空字符串,这里需要过滤
|
|
289
|
+
if (styleArray[i]) {
|
|
290
|
+
const item = styleArray[i].split(':')
|
|
291
|
+
style[this.trim(item[0])] = this.trim(item[1])
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
return style
|
|
295
|
+
}
|
|
296
|
+
// 这里为对象转字符串形式
|
|
297
|
+
let string = ''
|
|
298
|
+
for (const i in customStyle) {
|
|
299
|
+
// 驼峰转为中划线的形式,否则css内联样式,无法识别驼峰样式属性名
|
|
300
|
+
const key = i.replace(/([A-Z])/g, '-$1').toLowerCase()
|
|
301
|
+
string += `${key}:${customStyle[i]};`
|
|
302
|
+
}
|
|
303
|
+
// 去除两端空格
|
|
304
|
+
return this.trim(string)
|
|
305
|
+
},
|
|
306
|
+
/**
|
|
307
|
+
* 滚动到底部触发事件
|
|
308
|
+
* @param {Object} e
|
|
309
|
+
*/
|
|
310
|
+
scrollToBottom: function () {
|
|
311
|
+
this.sleep(30).then(() => {
|
|
312
|
+
this.$emit('scrollToBottom')
|
|
313
|
+
})
|
|
314
|
+
},
|
|
315
|
+
/**
|
|
316
|
+
* 媒体查询
|
|
317
|
+
*/
|
|
318
|
+
startObserver(selector) {
|
|
319
|
+
return new Promise((resolve) => {
|
|
320
|
+
this.intersectionObserver = uniselector.createIntersectionObserver(this, {
|
|
321
|
+
thresholds: [0, 1],
|
|
322
|
+
initialRatio: 0,
|
|
323
|
+
observeAll: false,
|
|
324
|
+
})
|
|
325
|
+
this.intersectionObserver.relativeToViewport()
|
|
326
|
+
this.intersectionObserver.observe(selector, (res) => {
|
|
327
|
+
const rect = res.boundingClientRect
|
|
328
|
+
this.intersectionObserver.disconnect()
|
|
329
|
+
this.intersectionObserver = null
|
|
330
|
+
rect ? resolve(rect) : resolve(false)
|
|
331
|
+
})
|
|
332
|
+
})
|
|
333
|
+
},
|
|
334
|
+
/**
|
|
335
|
+
* 拆分数据
|
|
336
|
+
*/
|
|
337
|
+
splitData: async function () {
|
|
338
|
+
if (!this.tempList.length) return
|
|
339
|
+
|
|
340
|
+
for (let i = 1; i <= this.columnNum; i++) {
|
|
341
|
+
const rect = await this.getRect(`#miran-waterfall-${i}`, this)
|
|
342
|
+
if (!rect) return this.splitData()
|
|
343
|
+
this.columnHeights[i - 1] = rect.height
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
let index = 999
|
|
347
|
+
|
|
348
|
+
// 判断数据是不是处理第一行
|
|
349
|
+
for (let i = 0; i < this.columnNum; i++) {
|
|
350
|
+
if (this.columnHeights[i] === 0) {
|
|
351
|
+
index = i
|
|
352
|
+
break
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
const emitList = {}
|
|
357
|
+
|
|
358
|
+
// 设置项的位置属性并更新列高
|
|
359
|
+
if (index < this.columnNum) {
|
|
360
|
+
// 设置列名称
|
|
361
|
+
emitList.name = `list${index + 1}`
|
|
362
|
+
} else {
|
|
363
|
+
// 获取列高数组中最低高度
|
|
364
|
+
const minHeight = Math.min(...this.columnHeights)
|
|
365
|
+
// 查找最低高度所在列序
|
|
366
|
+
const minIndex = this.columnHeights.indexOf(minHeight)
|
|
367
|
+
// 设置列名称
|
|
368
|
+
emitList.name = `list${minIndex + 1}`
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
const item = this.tempList[0]
|
|
372
|
+
|
|
373
|
+
if (!item) return this.splitData()
|
|
374
|
+
|
|
375
|
+
emitList.value = {
|
|
376
|
+
...item,
|
|
377
|
+
width: this.columnWidth,
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
this.$emit('changeList', emitList)
|
|
381
|
+
|
|
382
|
+
// 移除临时数组中已处理的数据
|
|
383
|
+
this.tempList.splice(0, 1)
|
|
384
|
+
|
|
385
|
+
// 如果还有数据则继续执行
|
|
386
|
+
if (this.tempList.length) {
|
|
387
|
+
let _timeout = this.addTime
|
|
388
|
+
// 部分平台在延时较短的情况会出现BUG
|
|
389
|
+
// #ifdef MP-BAIDU
|
|
390
|
+
_timeout = _timeout < 200 ? 200 : _timeout
|
|
391
|
+
// #endif
|
|
392
|
+
await this.sleep(_timeout)
|
|
393
|
+
|
|
394
|
+
this.splitData()
|
|
395
|
+
} else {
|
|
396
|
+
this.$emit('finish')
|
|
397
|
+
}
|
|
398
|
+
},
|
|
399
|
+
/**
|
|
400
|
+
* 暂存未用
|
|
401
|
+
*/
|
|
402
|
+
renderData() {
|
|
403
|
+
const {
|
|
404
|
+
// 列数量
|
|
405
|
+
columnCount,
|
|
406
|
+
// 列宽
|
|
407
|
+
columnWidth,
|
|
408
|
+
// 骨架高度
|
|
409
|
+
skeletonHeight,
|
|
410
|
+
// 间隙宽高
|
|
411
|
+
gutter,
|
|
412
|
+
// 左右宽度
|
|
413
|
+
lrPading,
|
|
414
|
+
// 唯一标识关键词
|
|
415
|
+
keyId,
|
|
416
|
+
// 缓存项
|
|
417
|
+
cache = {},
|
|
418
|
+
} = this
|
|
419
|
+
|
|
420
|
+
// 标识关键词为空
|
|
421
|
+
if (!keyId) return
|
|
422
|
+
|
|
423
|
+
// 临时数据集为空
|
|
424
|
+
if (!this.tempList.length) return
|
|
425
|
+
|
|
426
|
+
if (!this.columnHeights) {
|
|
427
|
+
this.columnHeights = new Array(columnCount).fill(0)
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
const item = this.tempList[0]
|
|
431
|
+
|
|
432
|
+
// 唯一标识
|
|
433
|
+
const itemKey = item[keyId]
|
|
434
|
+
|
|
435
|
+
// 缓存为空,初始化数据
|
|
436
|
+
if (!cache[itemKey]) {
|
|
437
|
+
cache[itemKey] = {
|
|
438
|
+
top: 0,
|
|
439
|
+
left: 0,
|
|
440
|
+
width: columnWidth,
|
|
441
|
+
height: skeletonHeight,
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
let index = 999
|
|
446
|
+
// 判断数据是不是处理第一行
|
|
447
|
+
for (let i = 0; i < columnCount; i++) {
|
|
448
|
+
if (this.columnHeights[i] === 0) {
|
|
449
|
+
index = i
|
|
450
|
+
break
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
// 设置项的位置属性并更新列高
|
|
455
|
+
if (index < columnCount) {
|
|
456
|
+
// 第一行数据处理
|
|
457
|
+
// 设置第一行项上边距为0
|
|
458
|
+
cache[itemKey].top = 0
|
|
459
|
+
// 设置第一行项左边距为左间隙+列序号*(列宽+间隙)
|
|
460
|
+
cache[itemKey].left = lrPading + index * (columnWidth + gutter)
|
|
461
|
+
// 设置列高数组中列序号为index的值为列高+项高度
|
|
462
|
+
this.columnHeights[index] += cache[itemKey].height
|
|
463
|
+
} else {
|
|
464
|
+
// 其它行数据处理
|
|
465
|
+
// 获取列高数组中最低高度
|
|
466
|
+
const minHeight = Math.min(...this.columnHeights)
|
|
467
|
+
// 查找最低高度所在列序
|
|
468
|
+
const minIndex = this.columnHeights.indexOf(minHeight)
|
|
469
|
+
// 设置项上边距为最小高度+间隙
|
|
470
|
+
cache[itemKey].top = minHeight + gutter
|
|
471
|
+
// 设置项左边距为左间隙+列序号*(列宽+间隙)
|
|
472
|
+
cache[itemKey].left = lrPading + minIndex * (columnWidth + gutter)
|
|
473
|
+
// 设置列高数组中列序号为minIndex的值为列高+项高度+间隙
|
|
474
|
+
this.columnHeights[minIndex] += cache[itemKey].height + gutter
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
// 获取列高数组中最大高度
|
|
478
|
+
this.waterfallBoxHeight = Math.max(...this.columnHeights)
|
|
479
|
+
|
|
480
|
+
// 添加项数据到数组中
|
|
481
|
+
this.$emit('changeList', {
|
|
482
|
+
...item,
|
|
483
|
+
_layoutRect: cache[itemKey],
|
|
484
|
+
_renderKey: itemKey,
|
|
485
|
+
})
|
|
486
|
+
|
|
487
|
+
// 移除临时数组中已处理的数据
|
|
488
|
+
this.tempList.splice(0, 1)
|
|
489
|
+
|
|
490
|
+
// 如果还有数据则继续执行
|
|
491
|
+
if (this.tempList.length) {
|
|
492
|
+
this.renderData()
|
|
493
|
+
} else {
|
|
494
|
+
this.$emit('finish')
|
|
495
|
+
}
|
|
496
|
+
},
|
|
497
|
+
/**
|
|
498
|
+
* 清空数据列表
|
|
499
|
+
*/
|
|
500
|
+
async clear() {
|
|
501
|
+
// #ifdef VUE2
|
|
502
|
+
this.$emit('input', [])
|
|
503
|
+
// #endif
|
|
504
|
+
// #ifdef VUE3
|
|
505
|
+
this.$emit('update:modelValue', [])
|
|
506
|
+
// #endif
|
|
507
|
+
this.tempList = []
|
|
508
|
+
await this.sleep(300)
|
|
509
|
+
this.$emit('clear')
|
|
510
|
+
},
|
|
511
|
+
/**
|
|
512
|
+
* 移除某条数据
|
|
513
|
+
* @param {Object} id
|
|
514
|
+
*/
|
|
515
|
+
remove(id) {
|
|
516
|
+
let index = -1
|
|
517
|
+
// 同时删除父组件对应的数据
|
|
518
|
+
// #ifdef VUE2
|
|
519
|
+
index = this.value.findIndex((item) => item[this.idKey] === id)
|
|
520
|
+
if (index !== -1) this.$emit('input', this.value.splice(index, 1))
|
|
521
|
+
// #endif
|
|
522
|
+
// #ifdef VUE3
|
|
523
|
+
index = this.modelValue.findIndex((item) => item[this.idKey] === id)
|
|
524
|
+
if (index !== -1) this.$emit('update:modelValue', this.modelValue.splice(index, 1))
|
|
525
|
+
// #endif
|
|
526
|
+
this.$emit('remove', id)
|
|
527
|
+
},
|
|
528
|
+
},
|
|
529
|
+
}
|
|
530
|
+
</script>
|
|
531
|
+
<style lang="scss" scoped>
|
|
532
|
+
.miran-waterfall {
|
|
533
|
+
/* #ifndef APP-NVUE */
|
|
534
|
+
display: flex;
|
|
535
|
+
/* #endif */
|
|
536
|
+
flex-direction: row;
|
|
537
|
+
align-items: flex-start;
|
|
538
|
+
|
|
539
|
+
&__column {
|
|
540
|
+
/* #ifndef APP-NVUE */
|
|
541
|
+
display: flex;
|
|
542
|
+
/* #endif */
|
|
543
|
+
flex-direction: column;
|
|
544
|
+
flex: 1;
|
|
545
|
+
// #ifndef APP-NVUE
|
|
546
|
+
height: auto;
|
|
547
|
+
// #endif
|
|
548
|
+
}
|
|
549
|
+
}
|
|
550
|
+
</style>
|
package/global.d.ts
CHANGED
|
@@ -33,6 +33,7 @@ declare module 'vue' {
|
|
|
33
33
|
'lcb-user-top': (typeof import('./types/components/lcb-user-top/lcb-user-top.vue'))['default']
|
|
34
34
|
'lcb-video': (typeof import('./types/components/lcb-video/lcb-video.vue'))['default']
|
|
35
35
|
'lcb-vip': (typeof import('./types/components/lcb-vip/lcb-vip.vue'))['default']
|
|
36
|
+
'lcb-waterfall': (typeof import('./types/components/lcb-waterfall/lcb-waterfall.vue'))['default']
|
|
36
37
|
}
|
|
37
38
|
}
|
|
38
39
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tplc/business",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.39",
|
|
4
4
|
"keywords": [
|
|
5
5
|
"业务组件"
|
|
6
6
|
],
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
},
|
|
12
12
|
"peerDependencies": {
|
|
13
13
|
"vue": ">=3.2.47",
|
|
14
|
-
"@tplc/wot": "0.1.
|
|
14
|
+
"@tplc/wot": "0.1.47"
|
|
15
15
|
},
|
|
16
16
|
"engines": {
|
|
17
17
|
"node": ">=18",
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
declare function __VLS_template(): Readonly<{
|
|
2
2
|
coverImg(props: { value: any }): any
|
|
3
|
+
headImg(props: { value: any }): any
|
|
4
|
+
userName(props: { value: any }): any
|
|
3
5
|
productName(props: { value: any }): any
|
|
4
6
|
subTitle(props: { value: any }): any
|
|
5
7
|
price(props: { value: any }): any
|
|
@@ -21,6 +23,8 @@ declare function __VLS_template(): Readonly<{
|
|
|
21
23
|
orderTips(props: { value: any }): any
|
|
22
24
|
}> & {
|
|
23
25
|
coverImg(props: { value: any }): any
|
|
26
|
+
headImg(props: { value: any }): any
|
|
27
|
+
userName(props: { value: any }): any
|
|
24
28
|
productName(props: { value: any }): any
|
|
25
29
|
subTitle(props: { value: any }): any
|
|
26
30
|
price(props: { value: any }): any
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { LcbProductItemProps } from './types'
|
|
2
2
|
declare function __VLS_template(): Readonly<{
|
|
3
3
|
coverImg(props: { value: any }): any
|
|
4
|
+
userName(props: { value: any }): any
|
|
5
|
+
headImg(props: { value: any }): any
|
|
4
6
|
productName(props: { value: any }): any
|
|
5
7
|
subTitle(props: { value: any }): any
|
|
6
8
|
price(props: { value: any }): any
|
|
@@ -30,6 +32,8 @@ declare function __VLS_template(): Readonly<{
|
|
|
30
32
|
contentSection(): any
|
|
31
33
|
}> & {
|
|
32
34
|
coverImg(props: { value: any }): any
|
|
35
|
+
userName(props: { value: any }): any
|
|
36
|
+
headImg(props: { value: any }): any
|
|
33
37
|
productName(props: { value: any }): any
|
|
34
38
|
subTitle(props: { value: any }): any
|
|
35
39
|
price(props: { value: any }): any
|
|
@@ -77,6 +81,7 @@ declare const __VLS_component: import('vue').DefineComponent<
|
|
|
77
81
|
titleVisible: boolean
|
|
78
82
|
subTitleVisible: boolean
|
|
79
83
|
priceVisible: boolean
|
|
84
|
+
userInfoVisible: boolean
|
|
80
85
|
priceTipsVisible: boolean
|
|
81
86
|
priceUnitVisible: boolean
|
|
82
87
|
priceSuffixVisible: boolean
|
|
@@ -125,6 +130,7 @@ declare const __VLS_component: import('vue').DefineComponent<
|
|
|
125
130
|
titleVisible: boolean
|
|
126
131
|
subTitleVisible: boolean
|
|
127
132
|
priceVisible: boolean
|
|
133
|
+
userInfoVisible: boolean
|
|
128
134
|
priceTipsVisible: boolean
|
|
129
135
|
priceUnitVisible: boolean
|
|
130
136
|
priceSuffixVisible: boolean
|
|
@@ -161,6 +167,7 @@ declare const __VLS_component: import('vue').DefineComponent<
|
|
|
161
167
|
coverImgVisible: boolean
|
|
162
168
|
titleVisible: boolean
|
|
163
169
|
subTitleVisible: boolean
|
|
170
|
+
userInfoVisible: boolean
|
|
164
171
|
priceVisible: boolean
|
|
165
172
|
priceUnitVisible: boolean
|
|
166
173
|
priceSuffixVisible: boolean
|
|
@@ -15,6 +15,8 @@ export interface LcbProductItemProps {
|
|
|
15
15
|
imageType?: 'square' | 'vertical' | 'horizontal'
|
|
16
16
|
coverImg?: any
|
|
17
17
|
productName?: any
|
|
18
|
+
headImg?: string
|
|
19
|
+
userName?: string
|
|
18
20
|
subTitle?: any
|
|
19
21
|
price?: any
|
|
20
22
|
priceUnit?: any
|
|
@@ -37,6 +39,7 @@ export interface LcbProductItemProps {
|
|
|
37
39
|
coverImgVisible?: boolean
|
|
38
40
|
titleVisible?: boolean
|
|
39
41
|
subTitleVisible?: boolean
|
|
42
|
+
userInfoVisible?: boolean
|
|
40
43
|
priceVisible?: boolean
|
|
41
44
|
priceUnitVisible?: boolean
|
|
42
45
|
priceSuffixVisible?: boolean
|