@fesjs/fes-design
Version:
fes-design for PC
102 lines (94 loc) • 4.07 kB
JavaScript
import _defineProperty from '@babel/runtime/helpers/esm/defineProperty';
import { ref, watch, computed } from 'vue';
import { isUndefined, isArray, isEqual } from 'lodash-es';
function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
const useNormalModel = function (props, emit) {
let config = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
const {
prop = 'modelValue',
deep = false,
isEqual: isEqual$1 = false,
defaultValue
} = config;
const usingProp = prop; // 实际使用中 'modelValue' 本就应该在 Key 中
// NOTE: 不可以使用 ref<Type> 的写法,currentValue 会被直接推导成 Props[Key]
const currentValue = ref(!isUndefined(props[usingProp]) ? props[usingProp] : defaultValue);
const pureUpdateCurrentValue = value => {
if (value === currentValue.value || isEqual$1 && isEqual(value, currentValue.value)) {
return;
}
currentValue.value = value;
};
const updateCurrentValue = value => {
pureUpdateCurrentValue(value);
// TODO: need a more proper way instead of `as`
emit(`update:${usingProp}`, currentValue.value);
};
watch(() => props[usingProp], val => {
if (val === currentValue.value) {
return;
}
currentValue.value = val;
}, {
deep
});
return [computed({
get() {
return currentValue.value;
},
set(value) {
updateCurrentValue(value);
}
}), updateCurrentValue];
};
// type IncludeArray<U> = U extends unknown[] ? U : never;
// type ExtractArray<U> = U extends unknown[] ? U : never;
/**
* TODO: 后续优化
* 使得 useArrayModel 在不传 config 使用 modelValue,且 modelValue 的类型不为数组的情况下,有更友好的类型报错提示
* 目前在上述情况下,modelValue 的类型被推导为 never,保证了部分场景。
*/
/* type UseArrayModelReturn<
Props extends Record<string, any>,
Key extends keyof Props,
> = Props[Key] extends never
? never
: [WritableComputedRef<Props[Key]>, (val: ArrayOrItem<Props[Key]>) => void]; */
const useArrayModel = function (props, emit) {
let config = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
const [computedValue, updateCurrentValue] = useNormalModel(props, emit, _objectSpread(_objectSpread({}, config), {}, {
defaultValue: []
}));
if (!isArray(computedValue.value)) {
console.warn('[useArrayModel] 绑定值类型不匹配, 仅支持数组类型, value:', props[(config === null || config === void 0 ? void 0 : config.prop) || 'modelValue']);
updateCurrentValue([]);
}
const updateItem = value => {
if (isArray(value)) {
updateCurrentValue(value);
return;
}
// 兼容重复赋值为不符合预期数据类型的场景
let val = [];
if (!isArray(computedValue.value)) {
console.warn('[useArrayModel] 绑定值类型不匹配, 仅支持数组类型, value:', computedValue.value);
val = [];
} else {
val = [...computedValue.value];
}
const index = val.indexOf(value);
if (index !== -1) {
val.splice(index, 1);
} else {
val.push(value);
}
updateCurrentValue(val);
};
return [computedValue, updateItem];
};
/**
* useArrayModel 的返回值
* 用于 modelValue 混杂了 useNormalModel 类型的情况,用于手动指明 useArrayModel 需要的 modelValue 类型
*/
export { useArrayModel, useNormalModel };