自定义组件
可以通过defineComponentMaker
这个工具函数自定义组件资源。
定义组件
以自定义一个按钮组件为例,假设现在有一个用Vue
写的按钮组件
// Button.vue
<template>
<button>我是按钮</button>
</template>
2
3
4
通过defineComponentMaker
把它低代码化
// ButtonMaker.ts
import { defineComponentMaker } from 'vue-cook'
import Button from "./Button.vue";
export default defineComponentMaker({
name: "按钮",
pkg: "test-pkg",
make: () => Button
})
2
3
4
5
6
7
8
在cookEditorState
中放入这个按钮组件资源
import { createCookEditorState, defaultMakerList } from "vue-cook"
const cookEditorState = createCookEditorState({
makerList: [
ButtonMaker, // import ButtonMaker from "./ButtonMaker.ts"
...defaultMakerList
]
})
2
3
4
5
6
7
打开示例页面-定义组件,可以在最下方的资源面板
中找到新增加的按钮组件,按照下面的步骤,创建一个拥有按钮的页面。
- 在左侧的
页面组件树
中点击+
- 点击新增的页面,中间会打开一个
页面编辑
面板 - 鼠标移到
页面编辑
面板中间,可以看到一个高亮的矩形框,点击选中这个矩形框 - 左边的
组件编辑器
面板显示当前选中组件的一些可配置项,其中插槽
一栏中,有一个名称为default
的框,上面写着拖拽组件到此处添加
- 从下方的
资源面板
中,将按钮
拖到右上编辑器的框中,可以看到下方的表格发生了变化,出现了一行数据,它就是添加好的按钮组件 - 在中间的
页面编辑
面板中,应该可以看到一个有按钮的页面
添加属性配置
通过defineComponentMaker
的中的makePropOptions
参数,可以为自定义的组件添加属性配置。
假设现在有一个按钮组件,它有一个text
属性
// Button.vue
<template>
<button>{{ text ? text : '我是默认文字' }}</button>
</template>
<script lang="ts" setup>
defineProps({
text: {
type: String
}
})
</script>
2
3
4
5
6
7
8
9
10
11
添加makePropOptions
// ButtonMaker.ts
import { defineComponentMaker } from 'vue-cook'
import Button from "./Button.vue";
export default defineComponentMaker({
name: "按钮",
pkg: "test-pkg",
makePropOptions: () => ["text"],
make: () => Button
})
2
3
4
5
6
7
8
9
打开示例页面-组件添加属性配置,按照下面的步骤,配置组件的属性
- 创建一个拥有按钮的页面
- 选中添加的按钮
- 可以看到它的
属性
一栏有一个名称为text
的输入框 - 输入文字后,对应按钮的文字会变成相应的内容
添加事件配置
通过defineComponentMaker
的中的makeEventOptions
参数,可以为自定义的组件添加事件配置。可以添加如点击、双击这种原生DOM事件,也可以添加使用Vue
自定义的事件。
原生DOM事件配置
假设现在有一个按钮组件
// Button.vue
<template>
<button>点我</button>
</template>
2
3
4
添加makeEventOptions
,click
代表的是DOM事件的点击事件
// ButtonMaker.ts
import { defineComponentMaker } from 'vue-cook'
import Button from "./Button.vue";
export default defineComponentMaker({
name: "按钮",
pkg: "test-pkg",
makeEventOptions: () => ["click"],
make: () => Button
})
2
3
4
5
6
7
8
9
此处,需要自定义一个逻辑
来绑定按钮点击后的行为
// AlertMaker.ts
import { defineLogicMaker } from "vue-cook";
export default defineLogicMaker({
name: "alert",
pkg: "test-pkg",
make: () => {
return () => {
alert("你好,按钮被点击了")
}
}
})
2
3
4
5
6
7
8
9
10
11
在cookEditorState
中放入这个自定义逻辑资源
import { createCookEditorState, defaultMakerList } from "vue-cook"
const cookEditorState = createCookEditorState({
makerList: [
ButtonMaker, // import ButtonMaker from "./ButtonMaker.ts"
AlertMaker, // import AlertMaker from "./AlertMaker.ts"
...defaultMakerList
]
})
2
3
4
5
6
7
8
打开示例页面-组件添加DOM事件配置,按照下面的步骤,配置组件的DOM事件
- 创建一个拥有按钮的页面
- 选中添加的按钮
- 可以看到它的
事件
一栏有一个名称为click
的框,上面写着拖拽逻辑到此处添加
- 从
资源面板
中找到之前放入的AlertMaker
,将其拖入到上面的框里,可以看到下方的表格发生了变化,出现了一行数据,它就是添加好的行为逻辑。 - 关闭
页面编辑器
的组件选中模式,否则没法触发按钮的点击事件。 - 点击按钮,可以看到绑定的行为逻辑被成功触发
多个根节点组件DOM事件配置
假设,有一个多根节点组件需要配置DOM事件,则需要在组件中显示指定事件的绑定
// Button.vue
<template>
<button>点我不触发事件</button>
<button v-bind="attrs">点我触发事件</button>
</template>
<script setup lang="ts">
import { useAttrs } from 'vue'
const attrs = useAttrs()
</script>
2
3
4
5
6
7
8
9
打开示例页面-多个根节点组件DOM事件配置,按照下面的步骤,配置多个根节点组件的DOM事件
- 创建一个拥有按钮的页面
- 选中添加的按钮,配置事件的逻辑行为
- 关闭
页面编辑器
的组件选中模式 - 点击右边的按钮可以正常触发事件,点击左侧的按钮则不会触发
Vue中自定义事件配置
假设,有一个自定义了事件的组件
// Button.vue
<template>
<button @click="delayClick">点我,2秒后触发事件</button>
</template>
<script setup lang="ts">
const emits = defineEmits(["delayClick"])
const delayClick = (e: MouseEvent) => {
setTimeout(() => {
emits("delayClick", e)
}, 2000)
}
</script>
2
3
4
5
6
7
8
9
10
11
12
在makeEventOptions
中配置delayClick
// ButtonMaker.ts
import { defineComponentMaker } from 'vue-cook'
import Button from "./Button.vue";
export default defineComponentMaker({
name: "按钮",
pkg: "test-pkg",
makeEventOptions: () => ["delayClick"],
make: () => Button
})
2
3
4
5
6
7
8
9
打开示例页面-Vue中自定义事件配置,按照下面的步骤,配置Vue中自定义的事件
- 创建一个拥有按钮的页面
- 选中添加的按钮,配置事件的逻辑行为
- 关闭
页面编辑器
的组件选中模式 - 点击按钮,可以在延迟了一段时间后,逻辑被成功执行
事件传参
默认参数传递
可以在自定义逻辑的里面直接接收事件传递的默认参数
// AlertMaker.ts
import { defineLogicMaker } from "vue-cook";
export default defineLogicMaker({
name: "alert",
pkg: "test-pkg",
make: () => {
return (event: MouseEvent) => {
alert(`你好,按钮被点击了,位置在${event.x},${event.y}`)
}
}
})
2
3
4
5
6
7
8
9
10
11
打开示例页面-事件传参,按照下面的步骤,可以看到事件参数的传递
- 创建一个拥有按钮的页面
- 选中添加的按钮,配置事件的逻辑行为
- 关闭
页面编辑器
的组件选中模式 - 点击按钮,可以看到事件的默认参数被正常传递
额外参数传递
也可以传递一些额外的参数
// Button.vue
<template>
<button @click="overwriteClick">点我</button>
</template>
<script setup lang="ts">
const emits = defineEmits(["overwriteClick"])
const overwriteClick = (e: MouseEvent) => {
emits("overwriteClick", e, "你好", "世界")
}
</script>
2
3
4
5
6
7
8
9
10
在自定义的逻辑中接收这些参数
// AlertMaker.ts
import { defineLogicMaker } from "vue-cook";
export default defineLogicMaker({
name: "alert",
pkg: "test-pkg",
make: () => {
return (event: MouseEvent, a: string, b: string) => {
alert(`
你好,按钮被点击了,位置在${event.x},${event.y}
额外信息:${a},${b}
`)
}
}
})
2
3
4
5
6
7
8
9
10
11
12
13
14
打开示例页面-向事件传递额外参数,按照下面的步骤,可以看到事件参数的传递
- 创建一个拥有按钮的页面
- 选中添加的按钮,配置事件的逻辑行为
- 关闭
页面编辑器
的组件选中模式 - 点击按钮,可以看到事件的额外参数被正常传递
添加插槽配置
通过defineComponentMaker
的中的makeSlotOptions
参数字段,可以为自定义的组件添加插槽配置。插槽是组件之间相互结合的纽带,使用它可以很方便的在组件之间进行嵌套。
假设,有一个前置图标插槽的按钮组件,在Vue
中,slot
可以指定名字,如果不指定的话有一个默认的名字default
// Button.vue
<template>
<button>
<span class="icon">
<slot></slot>
</span>
<span>我是按钮</span>
</button>
</template>
2
3
4
5
6
7
8
9
添加makeSlotOptions
// ButtonMaker.ts
import { defineComponentMaker } from 'vue-cook'
import Button from "./Button.vue";
export default defineComponentMaker({
name: "按钮",
pkg: "test-pkg",
makeSlotOptions: () => ["default"],
make: () => Button
})
2
3
4
5
6
7
8
9
创建一个图标组件,这里为了方便演示,直接使用emoji表情作为图标
// EmojiMaker.ts
import { defineComponent, h } from 'vue';
import { defineComponentMaker } from 'vue-cook'
export default defineComponentMaker({
name: "emoji",
pkg: "test-pkg",
make: () => defineComponent({
render: () => h(
'span',
'😀'
)
})
})
2
3
4
5
6
7
8
9
10
11
12
13
打开示例页面-组件添加插槽配置,按照下面的步骤,配置组件的插槽
- 创建一个带按钮的页面
- 选中添加的按钮
- 可以看到它的
插槽
一栏,有一个名称为default
的框,上面写着拖拽组件到此处添加
, - 将资源面板中的图标组件拖入,可以看到按钮中添加了一个图标
多个插槽配置
可以添加多个插槽配置
// Button.vue
<template>
<button>
<span class="pre-icon">
<slot name="preIcon"></slot>
</span>
<span>我是按钮</span>
<span class="post-icon">
<slot name="postIcon"></slot>
</span>
</button>
</template>
2
3
4
5
6
7
8
9
10
11
12
添加makeSlotOptions
// ButtonMaker.ts
import { defineComponentMaker } from 'vue-cook'
import Button from "./Button.vue";
export default defineComponentMaker({
name: "按钮",
pkg: "test-pkg",
makeSlotOptions: () => ["preIcon", "postIcon"],
make: () => Button
})
2
3
4
5
6
7
8
9
打开示例页面-组件添加多个插槽配置,按照下面的步骤,配置组件的插槽
- 创建一个带按钮的页面
- 选中添加的按钮
- 可以看到它的
插槽
一栏,出现了两个配置项,可以同时配置前置图标和后置图标, - 将资源面板中的图标组件拖入,配置组件的前置图标和后置图标
插槽与属性联动:创建一个动态布局组件
假设,有这样一个布局组件,它根据传入不同的行列值,拥有不同的插槽数量
// Layout.vue
<template>
<div class="layout">
<div v-for="m in rowNumber" class="row">
<div v-for="n in colNumber" class="col">
<slot :name="getSlotName(m, n)">{{ m }}-{{ n }}</slot>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import { computed, toRefs } from 'vue';
const props = defineProps({
row: String,
col: String
})
const { row, col } = toRefs(props)
const rowNumber = computed(() => Number(row?.value) || 1)
const colNumber = computed(() => Number(col?.value) || 1)
const getSlotName = (m: number, n: number) => `${m}-${n}`
</script>
<style lang="less">
.layout {
display: flex;
width: 300px;
flex-direction: column;
border: 1px solid black;
box-sizing: border-box;
.row {
display: flex;
justify-content: space-around;
border-bottom: 1px solid black;
box-sizing: border-box;
&:last-child {
border-bottom: none;
}
.col {
display: flex;
flex: 1;
border-right: 1px solid black;
box-sizing: border-box;
&:last-child {
border-right: none;
}
}
}
}
</style>
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
添加makeSlotOptions
// LayoutMaker.ts
import { defineComponentMaker } from 'vue-cook'
import Layout from "./Layout.vue";
export default defineComponentMaker({
name: "布局",
pkg: "test-pkg",
makePropOptions: () => ["row", "col"],
makeSlotOptions: (cookState, componentConfig) => {
const getSlotName = (m: number, n: number) => `${m}-${n}`
const rowNumber = Number(componentConfig?.props?.row) || 1
const colNumber = Number(componentConfig?.props?.col) || 1
const slots = []
for (let m = 1; m <= rowNumber; m++) {
for (let n = 1; n <= colNumber; n++) {
slots.push(getSlotName(m, n))
}
}
return slots
},
make: () => Layout
})
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
打开示例页面-创建一个布局组件,按照下面的步骤,配置布局组件
- 创建一个带布局组件的页面
- 选中布局组件
- 可以看到它的属性栏有两个配置,分别是行和列的数量
- 修改它的行列数,可以看到它的
插槽
数量会不断的更改 - 将按钮组件放入不同的插槽查看效果
更多defineComponentMaker
的参数,参考defineComponentMaker