/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
/* eslint-disable @typescript-eslint/no-non-null-assertion */
/* eslint-disable @typescript-eslint/no-unused-vars */
/* eslint-disable @typescript-eslint/ban-types */
/* eslint-disable @typescript-eslint/no-explicit-any */
/*
目标
1. 一般使用到 v-model 就会从外面传值进来,也就是 props,
1. 可以使用 watch 方式
2. 可以使用 computed 方式
2. 到底是哪个字段
3. 要 emits 出去
4. const data = useOVModel(props, key, emits, {
isWatch: true 是为 watch, false 为 computed
deep: true 是否为深度监听
cloned: true 是否深层拷贝
})
5. data.value
*/
import { watch, computed, ref, getCurrentInstance } from 'vue'
export interface IUseOVModelOptions<T> {
/*
isWatch 如果为 true,则使用 watch, 如果为 false 则使用 computed
*/
isWatch?: boolean
/*
是否进行深度监听,结合 isWatch 为 true 时使用
*/
deep?: boolean
/*
是否需要深度拷贝
*/
isCloned?: boolean
/*
是否有默认值
*/
defaultValue?: T
/*
事件名称
*/
eventName?: string
}
/**
* @description: 规定类型
* @param {P} props
* @param {K} key
* @param {function} emit
* @param {IUseOVModelOptions} options
* @return {*}
*/
export function useOVModel<P extends Object, K extends keyof P, emitName extends string>(
props: P,
key: K,
emit: any,
options: IUseOVModelOptions<P[K]> = {}
) {
// 拿到 vm
const vm = getCurrentInstance()
// 兼容 emit
const _emit = emit || vm?.emit || vm?.proxy?.$emit?.bind(vm?.proxy)
// 首先拿到 options
const { isWatch, deep, isCloned, defaultValue, eventName } = options
// 暂时使用 JSON.parse, JSON.stringify 来实现深度克隆
const deepCloned = (val: any) => JSON.parse(JSON.stringify(val))
// 如果 key 存在,则使用 key, 否则默认使用 modelValue
const _key = (key ? key : 'modelValue') as K
// 兼容 event
const _event = (eventName || `update:${_key!.toString()}`) as emitName
// 如果 key 不存在,或者是空字符串,说明外面默认是 modelValue
if (isWatch === true) {
// 兼容是否深度克隆
const _defaultValue = defaultValue ? props[_key] : props[_key]
const _data = isCloned ? deepCloned(_defaultValue) : _defaultValue
const data = ref<any>(_data)
// 则使用 watch 监听
watch(
props,
(v) => {
data.value = v[_key]
},
{ deep }
)
_emit(_event, data[_key])
return data
} else {
// 则使用 computed 监听
return computed({
get: () =>
isCloned
? deepCloned(defaultValue ? props[_key] : props[_key])
: defaultValue
? props[_key]
: props[_key],
set: (v) => _emit(_event, v),
})
}
}
用起来吧