呛再首
title: 关于组件二次封装的又一步思考 date: 2023-09-13 16:04:06 tags:
- Vue
- 技巧 categories:
- Vue
以二次封装一个 el-dialog 为例
# 利用 computed
父组件使用
<template>
<div>
<Dialog v-model="visible">
<template #header>132132132</template>
<span>Open the dialog from the center from the screen</span>
</Dialog>
</div>
</template>
<script setup>
import { ref } from 'vue'
import Dialog from './components/Dialog.vue'
const visible = ref(false)
const onClick = () => {
console.log(form.value)
}
const open = () => {
visible.value = true
}
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
利用 computed get set
<template>
<el-dialog v-model="visible" v-on="$attrs">
<template v-for="(_value, name) in $slots" #[name]="slotData">
<slot :name="name" v-bind="slotData || {}" />
</template>
</el-dialog>
</template>
<script setup>
const props = defineProps({
/**
* 是否显示
*/
modelValue: {
type: Boolean,
default: false,
},
})
const emit = defineEmits(['update:modelValue'])
const visible = computed({
get() {
return props.modelValue
},
set(newValue) {
emit('update:modelValue', newValue)
},
})
</script>
<style lang="scss" scoped></style>
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
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
# 利用 Proxy 代理
如果是 visible 是一个对象的话单单只用 computed 的 get set 就显得乏力了,这个时候可以考虑利用 Proxy 代理整个对象,这里以封装一个form 为例
父组件使用
<template>
<div>
<Form v-model="form"></Form>
</div>
</template>
<script setup>
import { ref } from 'vue'
import Form from './components/form.vue'
const form = ref({
name: '张麻子',
age: 18,
sex: 'man',
})
watch(
form,
(newValue) => {
console.log(newValue)
},
{
deep: true,
}
)
</script>
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
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
使用 proxy 代理
// Form.vue
<template>
<div>
<el-input v-model="form.name"></el-input>
<el-input v-model="form.age"></el-input>
<el-input v-model="form.sex"></el-input>
</div>
</template>
<script setup>
const props = defineProps({
modelValue: {
type: Object,
default: () => ({}),
},
})
const emit = defineEmits(['update:modelValue'])
const form = computed({
get() {
return new Proxy(props.modelValue, {
get(target, key) {
return Reflect.get(target, key)
},
set(target, key, value, receiver) {
emit('update:modelValue', {
...target,
[key]: value,
})
return true
},
})
},
set(newValue) {
emit('update:modelValue', newValue)
},
})
</script>
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
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
# 封装为一个 useVModel 的 hook
// useVModel.js
import { computed } from "vue";
export default function useVModle(props, propName, emit) {
return computed({
get() {
return new Proxy(props[propName], {
get(target, key) {
return Reflect.get(target, key)
},
set(target, key, newValue) {
emit('update:' + propName, {
...target,
[key]: newValue
})
return true
}
})
},
set(value) {
emit('update:' + propName, value)
}
})
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
使用:
<!-- 子组件使用 -->
<template>
<div>
<el-input v-model="form.name"></el-input>
<el-input v-model="form.age"></el-input>
<el-input v-model="form.sex"></el-input>
</div>
</template>
<script setup>
import useVModel from "../hooks/useVModel";
// 使用 vueuse 封装的 useVModel
// import { useVModel } from '@vueuse/core'
const props = defineProps({
modelValue: {
type: Object,
default: () => {},
},
});
const emit = defineEmits(["update:modelValue"]);
const form = useVModel(props, "modelValue", emit);
</script>
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
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
useVModel 可以换成 vueuse 里对应 hook,其实现更完备
# 参考
妙用computed拦截v-model,面试管都夸我细 (opens new window)