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");
      }
    });
  • 相关阅读:
    SQL
    HTTP协议
    工具命令
    安全策略
    日志与审核
    python视频教程免费下载,百度云网盘资源,全套!
    《Python基础教程(第3版)》PDF电子版百度云网盘免费下载
    老男孩Python全栈开发视频教程全套完整版!免费分享!
    Pycharm激活码分享,2020最新Pycharm永久激活码~
    老男孩Python视频教程全套完整版!无偿分享~
  • 原文地址:https://www.cnblogs.com/Answer1215/p/13410344.html
Copyright © 2011-2022 走看看