移动端实用小组件----函数式调用picker弹窗

36 阅读2分钟

可扩展为其他弹窗组件

import { render, createVNode, ref, nextTick } from "vue";
import PopupPicker from "@/components/popup-picker.vue";
import { CustomToast } from "@/utils";
interface ICustom {
  text: string;
  value: string;
  children?: string;
}

interface IPicker {
  dictKey?: string;
  columns?: Array<any>;
  confirm: (e: any) => void;
  title?: string;
  show?: boolean;
  maskClick?: boolean;
  value?: Array<any>;
  confirmText?: string;
  hasAll?: boolean;
  dictApi?: boolean;
  customFieldName?: ICustom;
  optionNum?: number;
  change?: (e: any) => void;
  cancel?: () => void;
}
/**
 * showPicker 函数式调用picker弹窗
 * @param { string } dictKey 字典key 与columns 二者取其一
 * @param { Array<any> } columns 数据列表, 与dictKey 二者取其一
 * @param { Function } confirm 确定回调,必传
 * @param { string } title picker标题
 * @param { Array<string> } value 回显value值
 * @param { string } confirmText 确认按钮文字
 * @param { boolean } maskClick 点击遮罩关闭
 * @param { boolean } hasAll 数据列表内是否增加全部,也可自己在数据列表内增加,仅支持单列
 * @param { boolean } dictApi 是否获取接口字典的数据,需要传dictKey
 * @param { Object } customFieldName 自定义 columns 结构中的字段
 * @param { Object } optionNum 可见的选项个数,默认5
 * @param { Function } change 选中的选项改变时触发回调
 * @param { Function } cancel 点击取消时触发回调
 * @returns
  showPicker({
    title: "picker组件",
    value: ['0'],
    columns: [{text:'选项1', value:'0'}],
    confirm: (e: any) => {},
  });
 */
const showPicker = (props: IPicker) => {
  const {
    value,
    dictKey,
    columns,
    title,
    confirmText,
    maskClick,
    hasAll,
    customFieldName,
    optionNum,
    dictApi,
    confirm,
    change,
    cancel,
  } = props;
  if (value && !Array.isArray(value)) return CustomToast("value值必须为数组");
  if (!columns && !dictKey) return CustomToast("未获取到数据");
  if (
    customFieldName &&
    (!("text" in customFieldName) || !("value" in customFieldName))
  )
    return CustomToast("customFieldName传入类型错误");

  // 数据增加全部
  let processedColumns = [] as Array<any>;
  if (columns) {
    processedColumns = [...columns];
    if (hasAll && !processedColumns.some((item) => "children" in item)) {
      processedColumns.unshift({
        [customFieldName?.text ?? "text"]: "全部",
        [customFieldName?.value ?? "value"]: "",
      });
    }
  }

  const container = document.createElement("div");
  document.body.appendChild(container);
  // 增加popup动画
  const show = ref(false);
  const onConfirm = (e: any) => {
    confirm && confirm(e);
    show.value = false;
    cleanup();
  };
  const onChange = (e: any) => {
    change && change(e);
  };
  const onCancel = () => {
    cancel && cancel();
    show.value = false;
    cleanup();
  };
  const vNode = createVNode(PopupPicker, {
    show: show.value,
    maskClick: maskClick ?? false,
    columns: processedColumns,
    dictKey: dictKey,
    title,
    value: value ?? [],
    confirmText: confirmText ?? "确认",
    customFieldName: customFieldName ?? {
      text: "text",
      value: "value",
      children: "children",
    },
    optionNum: optionNum ?? 5,
    dictApi: dictApi ?? false,
    hasAll:
      (hasAll && !processedColumns.some((item) => "children" in item)) ?? false,
    onConfirm,
    onChange: onChange,
    onCancel: onCancel,
    "onUpdate:show": (val: boolean) => {
      show.value = val;
    },
  });
  render(vNode, container);
  nextTick(() => {
    show.value = true;
    if (vNode.component) {
      vNode.component.props.show = true;
      vNode.component.proxy?.$forceUpdate();
    }
  });
  const cleanup = () => {
    setTimeout(() => {
      render(null, container);
      document.body.removeChild(container);
    }, 300); // 这里增加延迟,是为了popup关闭动画展示
  };
};
export default showPicker;