# 效果图

# 代码

<template>
    <label style="position: relative;">
        <div class="lbut" @click="convertedFunc">
            {{ count }} click and i will do the last time</div>
        <div ref="shader" class="lshader"></div>
    </label>
</template>

<script setup>
import {
    ref,
} from 'vue';
const count = ref(0);
const shader = ref(null);
const doLastTimeFunc = (func, time = 2000) => {
    let n = null
    return () => {
        clearTimeout(n)
        n = setTimeout(() => {
            func();
        }, time)
    }
}
const doClick = () => {
    count.value++;
}
const convertedFunc = doLastTimeFunc(doClick)
</script>

<style scoped>
label {
    overflow: hidden;
    display: block;
    height: 34px;
    width: 284px;
    border-radius: 1em;
}

.lbut {
    display: flex;
    justify-content: center;
    position: relative;
    width: 280px;
    height: 30px;
    margin-left: 2px;
    margin-top: 2px;
    font-weight: bolder;
    background-color: black;
    color: white;
    border-radius: 1em;
    cursor: pointer;
    z-index: 1;
}

.lbut:hover {
    background-color: white;
    color: black;
}

.lshader {
    position: absolute;
    top: -142px;
    left: -2px;
    height: 300px;
    width: 300px;
    border-radius: 1em;
    background: conic-gradient(from 180deg at 50% 50%, #00D1FF 0deg, #EE27FF 106.88deg, #205EFF 206.25deg, #00F0FF 286.87deg, #00D1FF 360deg);
    animation: rotate 3s linear infinite;
}

@keyframes rotate {
    from {
        transform: rotate(0deg);
    }

    to {
        transform: rotate(360deg);
    }
}
</style>

# 学习点

当学习了闭包后,我们可以封装一个独立的变量到函数中重复使用,例如在函数中return函数并使用外部函数的内部变量,此时返回出的函数同一个函数实例会拥有一个独立的外部变量,可以理解为形参,当触发这个返回方法实例总是会修改同一个函数变量,类似于这个变量永远为一个函数实例服务,也叫内存泄漏

  • 一个小知识:如果使用setTimeout或Interval在设置的时间间隔过小时会产生 js 来不及找到 dom 的 bug,这个 bug 大致原因是操作 dom 时下一个操作又要进入,因此最好使用requestAnimationFrame这个新的 api,这个 api 会自动寻找下一次渲染时机,因此所有由数值控制的移动,例如鼠标动画,或循环动画应该都由这个 api 接管,这样可以保证动画的流畅。注意这个 api 大致每秒执行 60 次,因此不必担心流畅程度,只需要控制好数值来让动画尽量以合适速度进行。

# 如何减缓requestAnimationFrame执行速度

这个函数的执行速度很快,但有时候需要减缓执行,可以使用下面的封装

function doNextFrame(callback, gapTimes = 1) {
  let last = Date.now(); // 最后一次执行时刻 ms
  let now = null; //现在 ms
  const interval = (1000 / 60) * gapTimes; // 时间间隔,ms
  draw();
  function draw() {
    requestAnimationFrame(draw);
    now = Date.now();
    if (now - last >= interval - 1000 / 120) {
      last = now;
      callback();
    }
  }
}

# BUG

如果发现 bug 或者其他需求可以联系作者 也十分欢迎 pr 前往 github (opens new window)