Vue3 + TS Slider组件,支持上下左右收起 - 戴向天

33 篇文章 0 订阅
14 篇文章 0 订阅

大家好!我叫戴向天

QQ群:602504799

如若有不理解的,可加QQ群进行咨询了解

Tips: 是在Element-UI的基础上进行更改操作的,原有的Element-UI是不支持方向性的处理,以及动画时间的设定,并且还需要通过CSS进行动画处理,当前改造过的该组件不需要CSS,可以直接进行复制使用。

使用方法:

	<Slider 
		:direction="sliderDirection"
	    :duration="duration"
	>
		<div style="width:50px;height:50px;background:red;position:absolute; top:0;" v-show="showSlider ">
			点击收起/展开
		<div>
	</Slider>

	<script setup lang="tsx">
	import { ref } from "@vue/runtime-core";
	// 动画时间
	const duration = ref(3000)
	// 动画方向
	const sliderDirection = ref('top'); // 可选值: ["ltr", "rtl", "ttb", "btt", "left", "right", "top", "bottom"]
	// 是否展开和显示
	const showSlider = ref(true)
	<script>
<template>
  <transition
    @beforeEnter="beforeEnter"
    @enter="enter"
    @afterEnter="afterEnter"
    @beforeLeave="beforeLeave"
    @leave="leave"
    @afterLeave="afterLeave"
  >
    <slot />
  </transition>
</template>
<script lang="ts">
import { defineComponent } from "@vue/runtime-core";
export default defineComponent({
  name: "Slider",
  props: {
    duration: {
      type: Number,
      default: 300,
      note: "收起展开的动画时间 毫秒 默认 300毫秒",
    },
    direction: {
      type: String,
      default: "ttb",
      note: "打开方向,主要还是需要根据插槽元素的position进行处理,例如:bottom,则就需要css设置bottom:0",
      types: {
        string: ["ltr", "rtl", "ttb", "btt", "left", "right", "top", "bottom"],
      },
    },
  },
  computed: {
    getColumns(): {
      scroll: "scrollWidth" | "scrollHeight";
      size: "width" | "height";
      offset: 'offsetWidth' | 'offsetHeight',
      padding: ["paddingLeft" | "paddingTop", "paddingRight" | "paddingBottom"];
      oldPadding: string[];
    } {
      if (["left", "right", "ltr", "rtl"].includes(this.direction)) {
        return {
          scroll: "scrollWidth",
          size: "width",
          offset: 'offsetWidth',
          padding: ["paddingLeft", "paddingRight"],
          oldPadding: ["oldPaddingLeft", "oldPaddingRight"],
        };
      }
      return {
        scroll: "scrollHeight",
        size: "height",
        offset: 'offsetHeight',
        padding: ["paddingTop", "paddingBottom"],
        oldPadding: ["oldPaddingTop", "oldPaddingBottom"],
      };
    },
  },
  methods: {
    beforeEnter(el: HTMLElement) {
      el.style.transition = `all ${this.duration}ms`;
      if (!el.dataset) {
        (el as any).dataset = {};
      }
      el.dataset[this.getColumns.oldPadding[0]] = el.style[this.getColumns.padding[0]];
      el.dataset[this.getColumns.oldPadding[1]] = el.style[this.getColumns.padding[1]];

      el.style[this.getColumns.size] = "0";
      el.style[this.getColumns.padding[0]] = "0";
      el.style[this.getColumns.padding[1]] = "0";

      this.$emit("beforeEnter");
    },

    enter(el: HTMLElement) {
      el.dataset.oldOverflow = el.style.overflow;
      // 该部分主要是用来获取元素的宽高
      const cloneEl = el.cloneNode(true) as HTMLElement
      cloneEl.style[this.getColumns.size] = '';
      (el.parentNode as HTMLElement).appendChild(cloneEl)
      const offset = cloneEl[this.getColumns.offset];
      (el.parentNode as HTMLElement).removeChild(cloneEl)

      if (el[this.getColumns.scroll] !== 0) {
        el.style[this.getColumns.size] = `${offset}px`;
        el.style[this.getColumns.padding[0]] = el.dataset[this.getColumns.oldPadding[0]] || "";
        el.style[this.getColumns.padding[1]] = el.dataset[this.getColumns.oldPadding[1]] || "";
      } else {
        el.style[this.getColumns.size] = `${offset}px`;
        el.style[this.getColumns.padding[0]] = el.dataset[this.getColumns.oldPadding[0]] || "";
        el.style[this.getColumns.padding[1]] = el.dataset[this.getColumns.oldPadding[1]] || "";
      }
      el.style.overflow = "hidden";

      this.$emit("enter");

    },

    afterEnter(el: HTMLElement) {
      el.style.transition = "";
      el.style[this.getColumns.size] = "";
      el.style.overflow = el.dataset.oldOverflow || "";
      this.$emit("afterEnter");
    },

    beforeLeave(el: HTMLElement) {
      if (!el.dataset) {
        (el as any).dataset = {};
      }
      el.dataset[this.getColumns.oldPadding[0]] =
        el.style[this.getColumns.padding[0]];
      el.dataset[this.getColumns.oldPadding[1]] =
        el.style[this.getColumns.padding[1]];
      el.dataset.oldOverflow = el.style.overflow;

      el.style[this.getColumns.size] = `${el[this.getColumns.scroll]}px`;
      el.style.overflow = "hidden";
      this.$emit("beforeLeave");
    },

    leave(el: HTMLElement) {
      if (el[this.getColumns.scroll] !== 0) {
        el.style.transition = `all ${this.duration}ms`;
        el.style[this.getColumns.size] = "0";
        el.style[this.getColumns.padding[0]] = "0";
        el.style[this.getColumns.padding[1]] = "0";
      }
      this.$emit("leave");
    },

    afterLeave(el: HTMLElement) {
      el.style.transition = "";
      el.style[this.getColumns.size] = "";
      el.style.overflow = el.dataset.oldOverflow || "";
      el.style[this.getColumns.padding[0]] =
        el.dataset[this.getColumns.oldPadding[0]] || "";
      el.style[this.getColumns.padding[1]] =
        el.dataset[this.getColumns.oldPadding[1]] || "";
      this.$emit("afterLeave");
    },
  },
});
</script>


</script>



  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值