props

父组件传给子组件的值。

App.vue:

1
2
3
4
5
6
7
8
9
10
11
12
<template>
<div>我是父级</div>
<hr>
<waterFall :title="name" :arr="[1,2,3]"></waterFall>
</template>

<script setup lang="ts">
import waterFall from "./components/WaterFall.vue"

// 传给子组件的值
const name = "yajue"
</script>

WaterFall.vue:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
<template>
<div>
我是子级
<!-- 定义的父传子传值可以直接在模板里使用 -->
<div>title:{{ title }}</div>
<div>arr{{ arr }}</div>
</div>
</template>

<script setup lang="ts">
// 接收父组件传的值

// 没有使用ts的情况
// const props = defineProps({
// // 接收一个title数据
// title: {
// // 规定该数据的类型为字符串
// type: String,
// // 默认值,如果父组件没有传就是这个值
// default: "默认值"
// },
// arr: {
// default: []
// }
// })

// 使用了ts的情况
// withDefaults是使用ts特有的函数,用于定义默认值
const props = withDefaults(defineProps<{
title: string
arr: number[]
}>(), {
title: "默认值",
// 如果是引用数据类型定义默认值,需要用一个匿名函数作返回
arr: ()=> [114514]
})

// 但是不能在代码里直接使用
// console.log(title)
// 需要通过defineProps的返回值获取
console.log(props.title, props.arr)
</script>

emit

子组件的自定义事件,可以用来传值。

App.vue:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<template>
<div>我是父级</div>
<hr>
<waterFall @on-click="getArgs"></waterFall>
</template>

<script setup lang="ts">
import waterFall from "./components/WaterFall.vue"

// 触发子组件自定义事件时的回调(能拿到子组件传的值)
const getArgs = (...args: any[])=> {
console.log(args)
}
</script>

WaterFall.vue:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<template>
<div>
我是子级
<button @click="send">给父组件传值</button>
</div>
</template>

<script setup lang="ts">
// 给父组件传值(定义自定义事件)

// 没有使用ts的情况
// const emit = defineEmits(["on-click"])

// 使用了ts的情况
const emit = defineEmits<{
(e: "on-click", title: string, ...rest: number[]): void
}>()

const send = ()=> {
// 触发自定义事件,可以顺便传值
emit("on-click", "子组件传的值", 114514, 1919810)
}
</script>

expose

给父组件暴露属性和方法。

App.vue:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<template>
<div>我是父级</div>
<hr>
<waterFall ref="wf"></waterFall>
</template>

<script setup lang="ts">
// 用ts读取wf的类型
const wf = ref<InstanceType<typeof waterFall>>()

onMounted(()=> {
console.log("~~~onMounted~~~")
console.log(wf.value?.name)
wf.value?.open()
})
</script>

WaterFall.vue:

1
2
3
4
5
6
7
8
9
10
11
12
13
<template>
<div>
我是子级
</div>
</template>

<script setup lang="ts">
// 给父组件暴露属性和方法
defineExpose({
name: "yjsp",
open: ()=> console.log("I am open function")
})
</script>

图片流布局实例

App.vue:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
<template>
<div>我是父级</div>
<waterFall ref="wf" :list="list"></waterFall>
</template>

<script setup lang="ts">
import waterFall from "./components/WaterFall.vue"

const list = [
{
height: 300,
background: 'red'
},
{
height: 400,
background: 'pink'
},
{
height: 500,
background: 'blue'
},
{
height: 200,
background: 'green'
},
{
height: 300,
background: 'gray'
},
{
height: 400,
background: '#CC00FF'
},
{
height: 200,
background: 'black'
},
{
height: 100,
background: '#996666'
},
{
height: 500,
background: 'skyblue'
},
{
height: 300,
background: '#993366'
},
{
height: 100,
background: '#33FF33'
},
{
height: 400,
background: 'skyblue'
},
{
height: 200,
background: '#6633CC'
},
{
height: 300,
background: '#666699'
},
{
height: 300,
background: '#66CCFF'
},
{
height: 300,
background: 'skyblue'
},
{
height: 200,
background: '#CC3366'
},
{
height: 200,
background: '#CC9966'
},
{
height: 200,
background: '#FF00FF'
},
{
height: 500,
background: '#990000'
},
{
height: 400,
background: 'red'
},
{
height: 100,
background: '#999966'
},
{
height: 200,
background: '#CCCC66'
},
{
height: 300,
background: '#FF33FF'
},
{
height: 400,
background: '#FFFF66'
},
{
height: 200,
background: 'red'
},
{
height: 100,
background: 'skyblue'
},
{
height: 200,
background: '#33CC00'
},
{
height: 300,
background: '#330033'
},
{
height: 100,
background: '#0066CC'
},
{
height: 200,
background: 'skyblue'
},
{
height: 100,
background: '#006666'
},
{
height: 200,
background: 'yellow'
},
{
height: 300,
background: 'yellow'
},
{
height: 100,
background: '#33CCFF'
},
{
height: 400,
background: 'yellow'
},
{
height: 400,
background: 'yellow'
},
{
height: 200,
background: '#33FF00'
},
{
height: 300,
background: 'yellow'
},
{
height: 100,
background: 'green'
}
]
</script>

WaterFall.vue:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
<template>
<div class="wraps">
<div
:style="{
height:item.height+'px',
backgroundColor:item.background,
left:item.left+'px',
top:item.top+'px'
}"
v-for="(item, index) in waterList"
:key="index"
class="items"></div>
</div>
</template>

<script setup lang="ts">
import { onMounted, reactive } from 'vue'

const props = defineProps<{
list: any[]
}>()

const waterList = reactive<any[]>([])

const heightList: number[] = []

const init = ()=> {
// 横向预留空隙
const width = 130
// 视口区宽度
const x = document.body.clientWidth
// 列数
const column = Math.floor(x/width)

console.log(width, x, column)
for(let i = 0; i < props.list.length; i++) {
// 第一列
if(i < column) {
waterList.push({
...props.list[i],
left: i * width,
top: 20
})

// 更新高度数组
heightList.push(props.list[i].height + 20)
}
// 后面的列
else {
// 最小的高度值
let current = heightList[0]
// 最小高度列的索引
let index = 0

// 找到最小高度列
heightList.forEach((h, i)=> {
if(current > h) {
current = h
index = i
}
})
waterList.push({
...props.list[i],
top: current + 20,
left: index * width
})

// 更新高度数组
heightList[index] = heightList[index] + props.list[i].height + 20
}
}
}

onMounted(()=> {
init()
console.log(waterList)
})
</script>

<style scoped lang="scss">
.wraps {
position: relative;

.items {
position: absolute;
width: 120px;
}
}
</style>