Drawer组件封装

组件封装

任务描述

这个drawer做个二次封装。
要求:使用useDrawer打开Drawer,打开后使用useDrawerInner获取打开Drawer的参数。

【最好组件参数也可以使用hook传进去,返回一个参数挂载到组件上】

任务分析

  1. 打开Drawer时使用useDrawer中提供的openDrawer方法,此方法可以传递初始化Drawer的配置项【属性】,同时提供getDrawerParams方法获取所传的所有参数。[这感觉有点怪怪的😂]

    import { ref, reactive } from 'vue';
    import { Drawer } from 'hui';
    
    interface DrawerOptions {
      title?: string;
      visible?: boolean;
    }
    
    export function useDrawer():any {
      const drawerRef = ref<InstanceType<typeof Drawer>>()
      const drawerOptions = reactive<DrawerOptions>({ visible: false })
    
    /**
     * 打开抽屉功能
     * 
     * 该函数用于配置并打开抽屉组件,允许通过传递部分抽屉选项来定制抽屉的行为和外观。
     * 抽屉选项是一个对象,其中包含控制抽屉的各种属性,如是否可见、抽屉的位置等。
     * 通过将传递的选项与当前抽屉选项合并,并将可见性设置为true,来实现打开抽屉的效果。
     * 
     * @param options 部分抽屉选项的对象。
     * 
     */
    const openDrawer = (options: Partial<DrawerOptions>) => {
      Object.assign(drawerOptions, options, { visible: true })
    };
    
      const closeDrawer = () => {
        drawerOptions.visible = false
      };
    
    /**
     * 获取抽屉配置参数。
     * 
     * 返回选项可能包括抽屉的大小、位置、可见性等。
     * 通过调用此函数,可以获取到配置抽屉所需的所有参数,以便根据这些参数来动态展示或隐藏抽屉,或者调整抽屉的其他属性。
     * 
     */
    const getDrawerParams = () => drawerOptions
    
      return {
        drawerRef,
        drawerOptions,
        openDrawer,
        closeDrawer,
        getDrawerParams,
      }
    }
    

    组件内使用:

    <template>
        <div>
            <HButton @click="openDrawer_">打开抽屉</HButton>
            <HDrawer v-model="drawerOptions.visible" :title="drawerOptions.title" :direction="drawerOptions.direction">
            </HDrawer>
    
        </div>
    </template>
    
    <script setup lang="ts">
    import { ref, reactive, toRefs, onMounted } from 'vue'
    import { useDrawer } from '../utils/useDrawer'
    
    const {
        drawerRef,
        drawerOptions,
        openDrawer,
        closeDrawer,
        getDrawerParams
    } = useDrawer()
    
    const openDrawer_ = () => {
        openDrawer({
            title: '这是一个抽屉',
            direction: 'ltr'
        })
    }
    </script>
    <style scoped lang="less"></style>
    

任务完善(7.9)

思路:

  1. 首先要把那个组件封装一下,用的时候直接用所封装的(比如叫XDrawer),不用原来的;
  2. 在封装的组件setup的时候抛出一个事件,事件参数就是一个函数(比如叫setParams),函数可以修改你所封装的组件里的参数,比如isVisible;
  3. 那么这个事件被谁接收呢,可以在useinnerDrawerInner里返回一个事件处理函数比如叫register,这样在useDrawerInner内部就拿到了setParams,可以控制组件内部比如显示与隐藏,那么useDrawerInner里面又可以返回closeDrawer函数,可以给XDrawer内部的关闭按钮使用;
  4. 在上面的register事件函数执行时,再抛出一个register事件,参数也为刚刚那个修改XDrawer属性的函数,那么这个事件可以被外部使用(比如你写了一个业务组件叫UserDrawer,里面用到了XDrawer,UserDrawer在首页被使用,那么在首页使用useDrawer),useDrawer返回一个register事件处理函数,处理前面的事件。那个在外面也可以做同样的时间控制打开与否,传递参数;
  5. 在此基础上可以扩展,比如XDrawer里面的loading遮罩层。
代码

XDrawer.vue

<template>
  <div>
    <HDrawer
      v-model="internalState.isVisible"
      v-bind="internalState"
    ></HDrawer>
  </div>
</template>

<script setup lang="ts">
import { ref, reactive, toRefs, onMounted } from "vue";
import { useDrawerInner } from "../utils/useInnerDrawer";
import { isVisible } from "hui/lib/es/utils/index.js";
const emits = defineEmits(["setParams"]);
const { register } = useDrawerInner();
const internalState = ref({
  isVisible: false,
  title: "Default Title",
});

const setParams = (params: any) => {
  Object.assign(internalState.value, params)
  return internalState.value
}
emits("setParams", setParams);


</script>
<style scoped lang="less"></style>

UserDrawer.vue

<template>
    <div>
        <p>封装组件</p>
        <XDrawer @setParams="setparams"></XDrawer>
    </div>
</template>

<script setup lang="ts">
import { ref, reactive, toRefs, onMounted } from 'vue'
import XDrawer from './XDrawer.vue';
import { useDrawerInner } from '../utils/useInnerDrawer';

const emits = defineEmits(['register'])

const { register } = useDrawerInner()
const setparams = (fn: any) => {
    register(fn, { isVisible: true })
    emits('register', fn)
}

</script>
<style scoped lang="less"></style>

useInnerDrawer钩子

import { ref } from "vue";
interface Params {
  isVisible?: boolean,
  title?: string,
}

export function useDrawerInner() {
  const paramsInner = ref<Params>()
  const register = (fn: any, params: any) => {
    paramsInner.value = fn(params)
  }

  const closeDrawer = () => {
    console.log("closeDrawer")
  }

  return {
    register,
    closeDrawer
  };
}

优化地方
  1. emit放到useDrawerInner里面,每个业务组件都要写这个,这是重复的。

    hook内无法使用emit函数啊!【defineEmits不行】

    解决:可以使用getCurrentInstance方法获取实例后在使用.emit方法进行抛出。

  2. 这个在里面处理一下,是不是可以直接做事件函数。

任务完善(7.10)

内容

  1. 完成组件封装任务

    完成抽屉关闭和抽屉打开的事件,同时可以控制loading的显示与否。

代码
  1. XDrawer.vue

    <template>
    <div>
      <HDrawer v-model="internalState.isVisible" v-bind="internalState" @open="internalState.handleOpenFun"
        @close="internalState.handleCloseFun">
        <template #default>
          <div v-loading="internalState.loadingShow" style="width: 100%;height:200px">
            loading
          </div>
        </template>
      </HDrawer>
    </div>
    </template>
    
    <script setup lang="ts">
    import { ref } from "vue";
    const emits = defineEmits(["setParams"]);
    const internalState = ref({
    isVisible: false,
    title: "Default Title",
    handleOpenFun: null,
    handleCloseFun: null,
    loadingShow: false
    });
    
    // const loadingShow = ref(true)
    
    const setParams = (params: any) => {
    Object.assign(internalState.value, params)
    return internalState.value
    }
    emits("setParams", setParams);
    </script>
    <style scoped lang="less"></style>
    
  2. UserDrawer.vue

<template>
    <div>
        <p>封装组件</p>
        <XDrawer @setParams="handleParams"></XDrawer>
    </div>
</template>

<script setup lang="ts">
import XDrawer from './XDrawer.vue';
import { useDrawerInner } from '../utils/useInnerDrawer';

const { showLoading } = useDrawerInner()
const handleParams = (fn: any) => {
    showLoading(fn)
}
</script>
<style scoped lang="less"></style>
  1. Home.vue

    <template>
    <div>
      <!-- <HButton @click="clickOpen">点击打开</HButton> -->
      <UserDrawer @register="(fn: any) => openDrawer(fn, () => { console.log('open') })"></UserDrawer>
    </div>
    </template>
    
    <script setup lang="ts">
    import UserDrawer from './UserDrawer.vue'
    import { useDrawer } from '../utils/useDrawer';
    const { openDrawer } = useDrawer()
    </script>
    <style scoped lang="less"></style>
    
  2. useDrawer.ts

import { ref, getCurrentInstance } from "vue";

interface Params {
  isVisible?: boolean;
  title?: string;
  handleOpenFun?: Function;
}

export function useDrawer() {
  const instance = getCurrentInstance();
  const paramsInner = ref<Params>();
  /**
   * 注册函数。
   * @param fn 内部组件所抛出的修改配置函数。
   * @param params 函数调用的参数。这是可选的,允许在调用注册的函数时传递额外的数据。
   */
  const register = (fn: any, params?: any) => {
    // 应用传入的函数到参数上,并更新内部参数的值
    paramsInner.value = fn(params);

    // 如果实例存在,则触发 'register' 事件,并传递函数作为参数
    instance?.emit("register", fn);
  };

  /**
   * 该函数用于触发打开抽屉的操作,并注册一个回调函数以处理相关的打开事件。
   */
  const openDrawer = (fn: any, handleFunction: Function) => {
    paramsInner.value = {
      isVisible: true,
      handleOpenFun: handleFunction,
    };
    register(fn, paramsInner.value);
  };

  return {
    register,
    openDrawer,
  };
}
  1. useInnerDrawer.ts

    import { ref, getCurrentInstance } from "vue";
    
    export function useDrawerInner() {
    const instance = getCurrentInstance();
    const paramsInner = ref();
    /**
     * 注册函数。
     */
    const register = (fn: any, params?: any) => {
      paramsInner.value = fn(params);
      instance?.emit("register", fn);
    };
    /**
     * 关闭抽屉的操作,同时并注册一个回调函数以处理相关的关闭事件。
     */
    const closeDrawer = (fn: any, handleClose: Function) => {
      register(fn, {
        isVisible: false,
        handleCloseFun: handleClose,
      });
    };
    
    /**
     * 控制loading的展示功能
     */
    const showLoading = (fn: any) => {
      register(fn, { loadingShow: true });
    };
    
    return {
      register,
      closeDrawer,
      showLoading,
    };
    }
    

  • 15
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值