zoukankan      html  css  js  c++  java
  • [XState] Nested State

    When dragging, we want to have two modes, one in 'normal' mode, another one is 'locked', we enter the locked mode by holde on 'shift' key. 

    To achieve this, we need to use nested state:

        dragging: {
          initial: "normal",
          states: {
            normal: {
              on: {
                "keydown.shift": "locked",
              },
            },
            locked: { 
              on: {
                // overwrite mousemove actions to move only
                // on x-axis
                mousemove: {
                  actions: assignOnlyX,
                },
                "keyup.shift": {
                  target: "normal",
                },
              },
            },
          },
    • When entering the dragging, we want to use 'normal' as initial state.
    • Then we defined two nested state: 'normal' and 'locked'
    • When 'shift' key is down, we go from 'normal' to 'locked', when its up, we back from 'locked' to 'normal'.
    • We also need to overwirte mousemove state's action, to only move the box in x-axis.

    Full code:

    import { createMachine, assign, interpret } from "xstate";
    
    const elBox = document.querySelector("#box");
    const elBody = document.body;
    
    const assignPoint = assign({
      px: (context, event) => event.clientX,
      py: (context, event) => event.clientY,
    });
    
    const assignPosition = assign({
      x: (context, event) => {
        return context.x + context.dx;
      },
      y: (context, event) => {
        return context.y + context.dy;
      },
      dx: 0,
      dy: 0,
      px: 0,
      py: 0,
    });
    
    const assignDelta = assign({
      dx: (context, event) => {
        return event.clientX - context.px;
      },
      dy: (context, event) => {
        return event.clientY - context.py;
      },
    });
    
    const resetPosition = assign({
      dx: 0,
      dy: 0,
      px: 0,
      py: 0,
    });
    
    const assignOnlyX = assign({
      dx: (context, event) => {
        return event.clientX - context.px;
      },
    });
    
    const dragDropMachine = createMachine({
      initial: "idle",
      context: {
        x: 0,
        y: 0,
        dx: 0,
        dy: 0,
        px: 0,
        py: 0,
      },
      states: {
        idle: {
          on: {
            mousedown: {
              actions: assignPoint,
              target: "dragging", // dragging.locked
            },
          },
        },
        dragging: {
          initial: "normal",
          states: {
            normal: {
              on: {
                "keydown.shift": "locked",
              },
            },
            locked: { 
              on: {
                // overwrite mousemove actions to move only
                // on x-axis
                mousemove: {
                  actions: assignOnlyX,
                },
                "keyup.shift": {
                  target: "normal",
                },
              },
            },
          },
          on: {
            mousemove: {
              actions: assignDelta,
              internal: false,
            },
            mouseup: {
              actions: [assignPosition],
              target: "idle",
            },
            "keyup.escape": {
              target: "idle",
              actions: resetPosition,
            },
          },
        },
      },
    });
    
    const service = interpret(dragDropMachine);
    
    service.onTransition((state) => {
      elBox.dataset.state = state.toStrings().join(" ");
    
      if (state.changed) {
        elBox.style.setProperty("--dx", state.context.dx);
        elBox.style.setProperty("--dy", state.context.dy);
        elBox.style.setProperty("--x", state.context.x);
        elBox.style.setProperty("--y", state.context.y);
      }
    });
    
    service.start();
    
    elBox.addEventListener("mousedown", (event) => {
      service.send(event);
    });
    
    elBody.addEventListener("mousemove", (event) => {
      service.send(event);
    });
    
    elBody.addEventListener("mouseup", (event) => {
      service.send(event);
    });
    
    elBody.addEventListener("keyup", (e) => {
      if (e.key === "Escape") {
        service.send("keyup.escape");
      }
    
      if (e.key === "Shift") {
        service.send("keyup.shift");
      }
    });
    
    elBody.addEventListener("keydown", (e) => {
      if (e.key === "Shift") {
        console.log("shift is down");
        service.send("keydown.shift");
      }
    });
  • 相关阅读:
    超强、超详细Redis入门教程
    zsh: command not found: pip 解决方法
    Python 进阶必备函数
    【debian】解决debian中文安装后出现乱码的问题
    【随笔】关于服务器
    【随笔】Linux主机简单判断CC攻击的命令
    【Docker】通过cookie欺骗在ubuntu中使用wget下载jdk
    【linux】在ubuntu中使用apt-get安装oracle jdk6
    【Nginx】关于域名转发proxy_pass
    【Docker】制作一个支持SSH终端登录的镜像
  • 原文地址:https://www.cnblogs.com/Answer1215/p/13410344.html
Copyright © 2011-2022 走看看