极简旋转loading动画编辑器

问题分类


loading 动画的可编辑

 

问题描述


电子课本之前的书本加载 loading 不满足章节之间的跳转 loading动画的要求,需要制作新的 loading 动画

 

 

 

原因分析


 

 

 

 

 

解决方案


制作一个 loading 动画并能编辑其最终效果:

下面是最终实现调用的代码:

    const _obj = {
    interval: "0.15s",
    bgColor: "#1bf",
    size: "20px",
    shrink: 3.75,
    };
    const config = mkResponsive(_obj);
 
    // 至此实现了数据到视图层的绑定
    //   setTimeout(() => {
    //     config.bgColor = "#f00";
    //     config.size = "50px";
    //     config.shrink = 5;
    //     config.interval = "0.2s";
    //   }, 2000);
 
    // 至此实现编辑器视图到数据的绑定
    editor.append(config,"interval","","速度:","text");
    editor.append(config,"shrink","","伸缩度:","range",1,10);
    editor.append(config,"size","px","点直径:","range",10,100);
    editor.append(config,"bgColor","","点颜色:","color");

 

大体分两步,第一步实现数据到动画的绑定,这里特意做了多个属性同步更改只实现一次重刷的效果,类似 React 使用 SetState 收集帧前状态,但是因为这里使用类似 Vue3 的 Proxy 对象,因此可以直接通过点操作符实现,当然具体实现要简单很多。

第二步是编辑器到数据的绑定,也就是 css3 自带 input 类元素的变动会反射到数据上。

这样,最终效果就是:编辑器 => 数据 => 动画

 

首先实现 css 动画,一个 div 包含四个小球,此 div 旋转 45 度后得到另一个 div:

每个小圆给到一个不断循环 scale 的 animation 播放,8 个小球依次具备 interval 时长的播放时差,因为单个 html 文件,直接用 css 变量:

      .dots2 > li:nth-child(1) {
        animation-delaycalc(var(--interval) * -7);
      }
      .dots1 > li:nth-child(2) {
        animation-delaycalc(var(--interval) * -6);
      }
      .dots2 > li:nth-child(2) {
        animation-delaycalc(var(--interval) * -5);
      }
      .dots1 > li:nth-child(3) {
        animation-delaycalc(var(--interval) * -4);
      }
      .dots2 > li:nth-child(3) {
        animation-delaycalc(var(--interval) * -3);
      }
      .dots1 > li:nth-child(4) {
        animation-delaycalc(var(--interval) * -2);
      }
      .dots2 > li:nth-child(4) {
        animation-delaycalc(var(--interval) * -1);
      }

然后是 css 中定义的动画相关的变量,用来方便 js 统一修改:

      :root {
        --interval0.2s;
        --shrink3.75;
        --bgColor#1bf;
        --size20px;
      }

 

接下是数据响应式的实现:

      // 响应式处理器生成工厂
      const responsiveHandlerFactory = () => {
        const setPropHandlers = [];
        const setPropHandlerCtxMap = new Map();
        
        const addSetPropHandler = (f=> {
          setPropHandlers.push(f);
          setPropHandlerCtxMap.set(fObject.create(null));
        };
        const delSetPropHandler = (f=> {
          const index = setPropHandlers.indexOf(f);
          if (index !== -1) {
            setPropHandlers.splice(index1);
            setPropHandlerCtxMap.delete(f);
          }
        };
        const responsiveHandler = {
          set(objpropval) {
            for (let f of setPropHandlers) {
              f(setPropHandlerCtxMap.get(f), objpropval);
            }
            obj[prop] = val;
            return true;
          },
        };
 
        return {
          responsiveHandler,
          addSetPropHandler,
          delSetPropHandler,
        };
      };

这里是一个极其简单粗糙的实现,给每个注册进来的 handler 创建一个独立的上下文,且使用 Map 记录。

这样做的原因是为了实现每个代理对象属性修改后的延迟响应。

这样使用 addSetPropHandler 就可以注册对象属性变更后的 UI 渲染逻辑了。

 

最后再实现一个极简编辑器:

      // 编辑器
      const editor = {
        edbox: null,
        init() {
          this.edbox = document.createElement("div");
          const style = {
            position: "fixed",
            left: "20px",
            top: "20px",
            width: "300px",
            height: "200px",
            border: "1px solid #ccc",
            borderRadius: "5px",
            padding: "10px"
          };
          ((obj=> {
            for (let key in obj) {
              this.edbox.style[key] = obj[key];
            }
          })(style);
          document.body.appendChild(this.edbox);
        },
        handlers: {},
        append(objpropunitshowTexttypeminmax) {
          let str = "";
          // 生成随机函数名
          const fname = "f" + Math.random().toString().slice(-5);
          this.handlers[fname] = (val=> {
            obj[prop] = val + unit;
          };
          str = `<div><span>${showText}</span><input type="${type}${
            type === "range" && ` min=${min || 0} max=${max || 1}`
          } value="${obj[prop]}" on${type === "range" ? "change" : "blur"}="editor.handlers.${fname}(event.target.value)" /></div>`;
          this.edbox.innerHTML += str;
        },
      };

 

 

 

纠正措施


 

 

 

案例推广


本案例可推广到XXX项目(XXX项目也存在本案例的问题)

 

技术支持


对本案例的解决方案如有疑问或改进建议,请与作者联系。

posted on 2021-03-05 21:25  Lowki  阅读(137)  评论(0编辑  收藏  举报