通过vue3下Dialog组件说下函数式开发解决的痛点
- 先用vue3写一个vue2常见的Dialog组件的伪代码:
<template>
<Dialog :state="state">
<div>我是弹窗内容</div>
<button @click="submit">提交</button>
</Dialog>
</template>
<script setup>
import Dialog from '@/component/Dialog'
import { ref } from 'vue'
const state = ref(false)
function open(id) {
state.value = true
if(id) {
// ...
}
}
const emit = defineEmits(['update'])
function submit() {
state.value = false
emit('update')
}
defineExpose({
open
})
</script>
- 父组件在使用的时候:
<template>
<button @click="openDialog">打开弹窗</button>
<MyDialog :ref="dialog" @update="getData">
</template>
<script setup>
import MyDialog from './MyDialog.vue'
import { ref } from 'vue'
const dialog = ref()
function openDialog() {
dialog.value.open()
}
</script>
父组件通过调用子组件暴露的open
方法去控制状态,并且还能通过参数就行初数据交互,子组件通过emit
暴露方法给父组件交互.
痛点
MyDialog
组件一般是对组件库的Model
组件进行的二次封窗,假如我想修改或响应Model
配置和事件,我要在一级父组件下去调用MyDialog
下的定义的方法和属性,然后再传给三级组件.
这样当业务和UI变的越来越复杂的时候,MyDialog
组件也许会有多个props
,emits
,exposes
.
如果我们让想父组件直接和三级组件通讯,略过MyDialog
转手的繁琐,怎么办呢.
vue3万能的hook
我们把MyDialog
和Dialog
组件都用jsx use
的形式去写.
// Dialog.jsx
import { reactive, toRefs } from 'vue'
export function useDialog(/*init参数*/) {
const config = reactive({
state: false,
title: '',
loadingL false
})
const Dialog = defineComponent({
setup(_props, { emit, slots }) {
return () => <NModel v-model:show={config.state}>
{slots.default()}
</NModel>
}
})
return {
...toRefs(config),
Dialog
}
}
// MyDialog.jsx
import { useDialog } from '@/component/Dialog'
export function useMyDialog(...props) {
const { Dialog, ...config } = useDialog(...props)
const MyDialog = defineComponent({
setup(_props, { emit, slots }) {
return () => <Dialog>
// ...
</Dialog>
})
return {
...config,
MyDialog
}
}
当我们父组件去调用弹窗组件的时候,通过useMyDialog
传入的参数,就能控制最底层的封装组件,通过返回的refs
获取最原始的响应值.
总结
这样的一个demo
也许并不实用,例如二级组件是需要经常手写的,用jsx
比template
麻烦一些.
但是函数式开发的思路还是要掌握的,通过参数和返回值代替vue2的prop
和emit
我认为是大势所趋.vue3的prox代理模式也许比react更适合useHook
.
转载自:https://juejin.cn/post/7176842885818482745