• 博客
  • 项目
  • 碎碎念
  • 留言板
  • 关于我
Quasar template 后台组件优化
更新时间:2025/11/03 分类:编程技术
之前的组件封装写的很low,最近在接手别人项目的还是,发现别人的写法很优雅。深入学习并总结了下
dialog封装示例
 @Prop({
   default: '50vw'
 }) width!: string;
 @Prop({
   default: () => ({})
 }) option!: IOption;

 @Watch('option', {
   deep: true
 })
 onOptionChange(newVal: IOption) {
   // 检查哪些属性发生了变化,并执行相应的逻辑
   if (newVal.visible !== this.prevOption!.visible) {
     AppModule.SET_DIALOG_VISIBLE(newVal.visible);
     if (newVal.visible) {
       this.$nextTick(() => {
         this.$refs[this.myDialogParams.id] && this.$refs[this.myDialogParams.id].resetValidation();
       });
     }
     this.myDialogParams.visible = newVal.visible;
   }
   if (newVal.dialogType !== this.prevOption!.dialogType) {
     this.myDialogParams.dialogType = newVal.dialogType;
   }
   if (newVal.clickLoading !== this.prevOption!.clickLoading) {
     this.myDialogParams.clickLoading = newVal.clickLoading;
   }
   if (newVal.getDataLoading !== this.prevOption!.getDataLoading) {
     this.myDialogParams.getDataLoading = newVal.getDataLoading;
   }
   if (newVal.title !== this.prevOption!.title) {
     this.myDialogParams.title = newVal.title;
   }
   if (newVal.showConfirm !== this.prevOption!.showConfirm) {
     this.myDialogParams.showConfirm = newVal.showConfirm;
   }
   if (newVal.rightPanel !== this.prevOption!.rightPanel) {
     this.myDialogParams.rightPanel = newVal.rightPanel;
   }
   if (newVal.confirmButtonText !== this.prevOption!.confirmButtonText) {
     this.myDialogParams.confirmButtonText = newVal.confirmButtonText;
   }
   if (newVal.cancelButtonText !== this.prevOption!.cancelButtonText) {
     this.myDialogParams.cancelButtonText = newVal.cancelButtonText;
   }
   this.prevOption = cloneDeep(newVal);
 }

 get calcMyDialogWidth() {
   if (this.width.toString().endsWith('px')) {
     return {
       width: this.width,
       maxWidth: '100vw',
     };
   }
   const width = Number(this.width.replace('vw', ''));
   if (width !== 50) {
     if (width === 40) {
       const documentWidth = document.body.clientWidth;
       if (documentWidth > 2160) {
         return {
           width: '30vw',
           maxWidth: '768px',
         };
       } else {
         return {
           width: '45vw',
           maxWidth: '50vw',
         };
       }
     }
     return {
       width: `${width}vw`,
       maxWidth: '100vw',
     };
   } else {
     //   根据document width计算dialog width
     const documentWidth = document.body.clientWidth;
     const isRightPanel = this.myDialogParams.rightPanel;
     if (!isRightPanel) {
       return {
         width: '50vw',
         maxWidth: '768px',
       };
     } else {
       if (documentWidth < 1920) {
         return {
           width: this.myDialogParams.maxWidth || '768px',
           maxWidth: this.myDialogParams.maxWidth || '768px',
         };
       } else {
         return {
           width: '50vw',
           maxWidth: '50vw',
         };
       }
     }
   }
 }

 get dialogStyle() {
   return {
     transform: `translate(${this.myDialogParams.dialogPos!.x}px, ${this.myDialogParams.dialogPos!.y}px)`,
   };
 }
新的写法
import {
  computed,
  defineComponent,
  getCurrentInstance,
  ref
} from 'vue';
import {
  DialogProvider
} from './index';

export default defineComponent({
  name: 'SQDialog',
  props: {
    allowFocusOutside: {
      type: Boolean,
      default: true
    },
    showFooter: {
      type: Boolean,
      default: true
    },
    component: {},
    componentBind: {
      type: Object
    },
    componentOn: {
      type: Object
    },
    closeOnEsc: {
      type: Boolean,
      default: true
    },
    closeOnMask: {
      type: Boolean,
      default: true
    },
    dialogId: {
      type: String
    },
    position: {
      type: String,
      default: 'standard'
    },
    showHeader: {
      type: Boolean,
      default: true
    },
    title: {
      type: String
    },
    width: {
      type: String,
      default: 'auto'
    },
  },
  emits: {},
  mounted() {},
  setup(props, {
    emit,
    expose
  }) {
    const visible = ref(false);
    const cancelText = ref('action.cancel');
    const confirmText = ref('action.confirm');
    const getDataLoading = ref(false);
    const dynamicCompRef = ref(null);
    const currentDialogInstance = getCurrentInstance();
    const computedComponentBind = computed(() => ({
      ...props.componentBind,
      dialogInstance: {
        open,
        close,
        setLoading,
        changeCancelText,
        changeConfirmText
      },
    }));
    const changeCancelText = (text: string) => {
      cancelText.value = text;
    };
    const changeConfirmText = (text: string) => {
      confirmText.value = text;
    };
    const handleClickCancel = () => {
      (currentDialogInstance?.refs?.dynamicCompRef as any).handleClickCancel && (currentDialogInstance?.refs?.dynamicCompRef as any).handleClickCancel();
      if (!(currentDialogInstance?.refs?.dynamicCompRef as any).handleClickCancel) {
        close();
      }
    };
    const handleClickConfirm = () => {
      (currentDialogInstance?.refs?.dynamicCompRef as any).handleClickConfirm && (currentDialogInstance?.refs?.dynamicCompRef as any).handleClickConfirm();
    };
    const open = () => {
      visible.value = true;
    };
    const close = () => {
      visible.value = false;
    };
    const setLoading = (data: boolean) => {
      getDataLoading.value = data;
    };
    const destroy = () => {
      props.dialogId && DialogProvider.destroy(props.dialogId);
    };
    expose({
      open,
      close,
      setLoading,
      changeCancelText,
      changeConfirmText
    });
    return {
      dynamicCompRef,
      cancelText,
      confirmText,
      visible,
      getDataLoading,
      computedComponentBind,
      open,
      close,
      destroy,
      handleClickCancel,
      handleClickConfirm,
    };
  },
});

使用
DialogProvider.register({
  title: 'Add',
  component: defineAsyncComponent(() => import('./components/add-update.vue')),
  componentBind: {
    type: 'add',
    data: []
  },
  componentOn: {
    getData: () => {
      console.log('getData');
    },
  },
});
相对比之前使用了异步组件,组件之前通讯和互相调用颗粒度更细了
文件地址

组件优化
联系我