learn-vue 动态组件
动态组件
1 | <component :is="comp"></component> |
1 | import tree from "../../components/tree/index.vue"; |
在setup语法糖下,is绑定的必须是组件实例,而不能是组件名。
采用vue2的写法才会使组件名直接关联到组件,可以用组件名。
一个实例
代码稍微复杂点,主要是结合了父子组件的传参,直接把全部代码贴在这里了~
menu
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<template>
<div class="menu">
Menu
<div style="display: flex; flex-direction: column">
<div @click="switchComp(item)" v-for="(item,index) in comps" :key="index">{{item.name}}</div>
</div>
<hr>
<component ref="compIns" :is="curComp.comp" :data="curComp.data" @on-mounted="curComp.onMounted" @on-click="curComp.onClick"></component>
</div>
</template>
<script setup lang="ts">
import {markRaw, reactive, Ref, ref} from "vue";
import tree from "../../components/tree/index.vue";
import folder from "../../components/folder/index.vue"
type TreeList = {
name:string,
icon?:string,
children?:TreeList[] | [],
hover:boolean
}
let data = reactive<TreeList[]>([
{
name:'no.1',
hover:false,
children:[
{
name:'no.1-1',
hover:false,
children:[
{
name:'no.1-1-1',
hover:false,
children:[]
}
]
}
]
},
{
name:'no.2',
hover:false,
children:[
{
name:'no.2-1',
hover:false,
children: []
}
]
},
{
name:'no.3',
hover:false
}
])
const clickTreeItem = (treeItem:TreeList) => {
console.log(treeItem)
}
type Folder = {
id:number,
name:string,
isFolder:boolean,
children?:Folder[]
}
type FolderIns = {
data:Folder
}
let folders = ref(null)
let folderIns = folders.value as unknown as FolderIns
let folderData = reactive<Folder>({
id:0,
name:'folder.0',
isFolder:true,
children:[
{
id:1,
name:'folder.1',
isFolder:true,
children:[
{
id:2,
name:'folder.1-1',
isFolder:false,
},
{
id:4,
name:'folder.1-2',
isFolder:false
}
]
},
{
id:3,
name:'folder.2',
isFolder:true
}
]
})
const clickFolder = (folder:Folder) => {
if (folder.isFolder) {
folderIns.data = folder
}
console.log(folderIns)
}
const initFolder = () => {
folderIns = compIns.value as unknown as FolderIns
folderIns.data = folderData
}
type Comp = {
name:string,
comp:any,
onClick?:any,
onMounted?:any,
data?:any,
ref?:any
}
let compIns = ref(null)
let comps = reactive([
{
name:"tree",
comp:markRaw(tree),
onClick:clickTreeItem,
data:data
},
{
name:"folder",
comp:markRaw(folder),
onClick:clickFolder,
onMounted:initFolder,
ref:ref(null)
}
])
let curComp:Ref<Comp> = ref(comps[0])
const switchComp = (item:Comp) => {
curComp.value = item
console.log(curComp.value.ref)
}
</script>
<style lang="less" scoped>
.menu{
width: 200px;
border-right: 1px solid #213547;
}
</style>tree
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<template>
<div>
<div @click.stop="clickTreeItem(item)" :key="index" v-for="(item,index) in data" class="tree">
{{item.name}}
<TreeItem @on-click="clickTreeItem" v-if="item?.children?.length" :data="item.children"></TreeItem>
</div>
</div>
</template>
<script setup lang="ts">
import {Ref, ref} from "vue";
type TreeList = {
name:string,
icon?:string,
children?:TreeList[] | [],
hover:boolean
}
type Props = {
data?:TreeList[]
}
defineProps<Props>()
const emit = defineEmits(['on-click'])
const clickTreeItem = (treeItem: TreeList) => {
emit('on-click', treeItem)
}
</script>
<script lang="ts">
export default {
name: "TreeItem"
}
</script>
<style scoped lang="less">
.tree{
margin-left: 10px;
}
</style>folder
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<template>
folder
<button "backup">back up</button> =
<div v-for="(item, index) in path" :key="index" @dblclick="clickPath(index)">
{{item.name}}
</div>
<hr>
<div v-for="(item, index) in data.children" :key="index" @dblclick="clickFolder(item)">
{{item.name}}
</div>
</template>
<script setup lang="ts">
import { onMounted, ref} from "vue";
type Folder = {
id:number,
name:string,
isFolder:boolean,
children?:Folder[],
}
let path = ref<Folder[]>([])
let data = ref<Folder>({
id:0,
name:'0',
isFolder:true,
children:[]
})
defineExpose({
data,
})
const emit = defineEmits(['on-click', 'on-mounted'])
const clickFolder = (folder:Folder) => {
if (folder.isFolder) {
emit('on-click', folder)
if (data.value) {
path.value.push(data.value)
} else {
console.log('a folder loss children')
}
}
}
const backup = () => {
if (path.value.length > 1) {
path.value.pop()
data.value = path.value.at(path.value.length-1) as Folder
}
}
const clickPath = (index:number) => {
while (path.value.length > index + 1) {
path.value.pop()
}
data.value = path.value.at(path.value.length-1) as Folder
}
onMounted(() => {
emit('on-mounted')
console.log(data)
if (data.value) {
path.value.push(data.value)
} else {
console.log('folder data is empty')
}
})
</script>
<style scoped lang="less">
</style>
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 李文豪の博客!