소스 검색

feat: 添加`AnimateCss`选择器组件`ReAnimateSelector` (#764)

* feat: 添加`AnimateCss`选择器组件`ReAnimateSelector`

* chore: update
xiaoming 1 년 전
부모
커밋
59fcac86c4

+ 1 - 0
locales/en.yaml

@@ -46,6 +46,7 @@ menus:
   hssplitPane: Split Pane
   hsbutton: Button Components
   hscropping: Picture Cropping
+  hsanimatecss: AnimateCss Selector
   hscountTo: Digital Animation
   hsselector: Selector Components
   hsflowChart: Flow Chart

+ 1 - 0
locales/zh-CN.yaml

@@ -46,6 +46,7 @@ menus:
   hssplitPane: 切割面板
   hsbutton: 按钮组件
   hscropping: 图片裁剪
+  hsanimatecss: AnimateCss选择器组件
   hscountTo: 数字动画
   hsselector: 选择器组件
   hsflowChart: 流程图

+ 7 - 0
src/components/ReAnimateSelector/index.ts

@@ -0,0 +1,7 @@
+import reAnimateSelector from "./src/index.vue";
+import { withInstall } from "@pureadmin/utils";
+
+/** [animate.css](https://animate.style/) 选择器组件 */
+export const ReAnimateSelector = withInstall(reAnimateSelector);
+
+export default ReAnimateSelector;

+ 114 - 0
src/components/ReAnimateSelector/src/animate.ts

@@ -0,0 +1,114 @@
+export const animates = [
+  /* Attention seekers  */
+  "bounce",
+  "flash",
+  "pulse",
+  "rubberBand",
+  "shakeX",
+  "headShake",
+  "swing",
+  "tada",
+  "wobble",
+  "jello",
+  "heartBeat",
+  /* Back entrances */
+  "backInDown",
+  "backInLeft",
+  "backInRight",
+  "backInUp",
+  /* Back exits */
+  "backOutDown",
+  "backOutLeft",
+  "backOutRight",
+  "backOutUp",
+  /* Bouncing entrances  */
+  "bounceIn",
+  "bounceInDown",
+  "bounceInLeft",
+  "bounceInRight",
+  "bounceInUp",
+  /* Bouncing exits  */
+  "bounceOut",
+  "bounceOutDown",
+  "bounceOutLeft",
+  "bounceOutRight",
+  "bounceOutUp",
+  /* Fading entrances  */
+  "fadeIn",
+  "fadeInDown",
+  "fadeInDownBig",
+  "fadeInLeft",
+  "fadeInLeftBig",
+  "fadeInRight",
+  "fadeInRightBig",
+  "fadeInUp",
+  "fadeInUpBig",
+  "fadeInTopLeft",
+  "fadeInTopRight",
+  "fadeInBottomLeft",
+  "fadeInBottomRight",
+  /* Fading exits */
+  "fadeOut",
+  "fadeOutDown",
+  "fadeOutDownBig",
+  "fadeOutLeft",
+  "fadeOutLeftBig",
+  "fadeOutRight",
+  "fadeOutRightBig",
+  "fadeOutUp",
+  "fadeOutUpBig",
+  "fadeOutTopLeft",
+  "fadeOutTopRight",
+  "fadeOutBottomRight",
+  "fadeOutBottomLeft",
+  /* Flippers */
+  "flip",
+  "flipInX",
+  "flipInY",
+  "flipOutX",
+  "flipOutY",
+  /* Lightspeed */
+  "lightSpeedInRight",
+  "lightSpeedInLeft",
+  "lightSpeedOutRight",
+  "lightSpeedOutLeft",
+  /* Rotating entrances */
+  "rotateIn",
+  "rotateInDownLeft",
+  "rotateInDownRight",
+  "rotateInUpLeft",
+  "rotateInUpRight",
+  /* Rotating exits */
+  "rotateOut",
+  "rotateOutDownLeft",
+  "rotateOutDownRight",
+  "rotateOutUpLeft",
+  "rotateOutUpRight",
+  /* Specials */
+  "hinge",
+  "jackInTheBox",
+  "rollIn",
+  "rollOut",
+  /* Zooming entrances */
+  "zoomIn",
+  "zoomInDown",
+  "zoomInLeft",
+  "zoomInRight",
+  "zoomInUp",
+  /* Zooming exits */
+  "zoomOut",
+  "zoomOutDown",
+  "zoomOutLeft",
+  "zoomOutRight",
+  "zoomOutUp",
+  /* Sliding entrances */
+  "slideInDown",
+  "slideInLeft",
+  "slideInRight",
+  "slideInUp",
+  /* Sliding exits */
+  "slideOutDown",
+  "slideOutLeft",
+  "slideOutRight",
+  "slideOutUp"
+];

+ 127 - 0
src/components/ReAnimateSelector/src/index.vue

@@ -0,0 +1,127 @@
+<script setup lang="ts">
+import { animates } from "./animate";
+import { ref, computed, toRef } from "vue";
+import { cloneDeep } from "@pureadmin/utils";
+
+defineOptions({
+  name: "ReAnimateSelector"
+});
+
+const props = defineProps({
+  modelValue: {
+    require: false,
+    type: String
+  }
+});
+const emit = defineEmits<{ (e: "update:modelValue", v: string) }>();
+
+const inputValue = toRef(props, "modelValue");
+const animatesList = ref(animates);
+const copyAnimatesList = cloneDeep(animatesList);
+
+const animateClass = computed(() => {
+  return [
+    "mt-1",
+    "flex",
+    "border",
+    "w-[130px]",
+    "h-[100px]",
+    "items-center",
+    "cursor-pointer",
+    "transition-all",
+    "justify-center",
+    "border-[#e5e7eb]",
+    "hover:text-primary",
+    "hover:duration-[700ms]"
+  ];
+});
+
+const animateStyle = computed(
+  () => (i: string) =>
+    inputValue.value === i
+      ? {
+          borderColor: "var(--el-color-primary)",
+          color: "var(--el-color-primary)"
+        }
+      : ""
+);
+
+function onChangeIcon(animate: string) {
+  emit("update:modelValue", animate);
+}
+
+function onClear() {
+  emit("update:modelValue", "");
+}
+
+function filterMethod(value: any) {
+  animatesList.value = copyAnimatesList.value.filter((i: string | any[]) =>
+    i.includes(value)
+  );
+}
+
+const animateMap = ref({});
+function onMouseEnter(index: string | number) {
+  animateMap.value[index] = animateMap.value[index]?.loading
+    ? Object.assign({}, animateMap.value[index], {
+        loading: false
+      })
+    : Object.assign({}, animateMap.value[index], {
+        loading: true
+      });
+}
+function onMouseleave() {
+  animateMap.value = {};
+}
+</script>
+
+<template>
+  <el-select
+    :model-value="inputValue"
+    placeholder="请选择动画"
+    clearable
+    filterable
+    @clear="onClear"
+    :filter-method="filterMethod"
+  >
+    <template #empty>
+      <div class="w-[280px]">
+        <el-scrollbar
+          noresize
+          height="212px"
+          :view-style="{ overflow: 'hidden' }"
+          class="border-t border-[#e5e7eb]"
+        >
+          <ul class="flex flex-wrap justify-around mb-1">
+            <li
+              v-for="(animate, index) in animatesList"
+              :key="index"
+              :class="animateClass"
+              :style="animateStyle(animate)"
+              @mouseenter.prevent="onMouseEnter(index)"
+              @mouseleave.prevent="onMouseleave"
+              @click="onChangeIcon(animate)"
+            >
+              <h4
+                :class="[
+                  `animate__animated animate__${
+                    animateMap[index]?.loading
+                      ? animate + ' animate__infinite'
+                      : ''
+                  } `
+                ]"
+              >
+                {{ animate }}
+              </h4>
+            </li>
+          </ul>
+          <el-empty
+            v-show="animatesList.length === 0"
+            description="暂无动画"
+            :image-size="60"
+          />
+        </el-scrollbar>
+      </div>
+    </template>
+  </el-select>
+</template>

+ 9 - 0
src/router/modules/components.ts

@@ -105,6 +105,15 @@ export default {
         title: $t("menus.hscropping")
       }
     },
+    {
+      path: "/components/animatecss",
+      name: "AnimateCss",
+      component: () => import("@/views/components/animatecss/index.vue"),
+      meta: {
+        title: $t("menus.hsanimatecss"),
+        extraIcon: "IF-pure-iconfont-new svg"
+      }
+    },
     {
       path: "/components/countTo",
       name: "CountTo",

+ 32 - 0
src/views/components/animatecss/index.vue

@@ -0,0 +1,32 @@
+<script setup lang="ts">
+import { ref, watch } from "vue";
+import ReAnimateSelector from "@/components/ReAnimateSelector";
+
+defineOptions({
+  name: "AnimateCss"
+});
+
+const icon = ref("");
+
+watch(icon, () => console.log("icon", icon.value));
+</script>
+
+<template>
+  <el-card shadow="never">
+    <template #header>
+      <div class="card-header">
+        <span class="font-medium">
+          <el-link
+            href="https://animate.style/"
+            target="_blank"
+            style="margin: 0 4px 5px; font-size: 16px"
+          >
+            animate.css
+          </el-link>
+          选择器组件
+        </span>
+      </div>
+    </template>
+    <ReAnimateSelector v-model="icon" />
+  </el-card>
+</template>