react-figma-clone项目2/4,算法有效的括号--羊的笔记(4.26)

220 阅读2分钟

4.26(figma-clone2/4)

好难!今天被困在canvas中了,简单的点击显示图形也没有实现,不知道是画布没选到还是初始化没有做到

1.实现flyReaction

鼠标实现,点击鼠标飞出图标,主要是从官网查文档,官方文档一直是最好的学习方式。

1.png

步骤:

1.复制按钮框代码,该文件主要用于选择表情,保存表情


import React from "react";
​
type Props = {
  setReaction: (reaction: string) => void;
};
​
export default function ReactionSelector({ setReaction }: Props) {
  return (
    // 将方框放在页面底部固定显示,并阻止默认事件捕获,防止在输入框输入e的时候触发显示表情框
    <div
      className='absolute bottom-20 left-0 right-0 mx-auto w-fit transform rounded-full bg-white px-2'
      onPointerMove={(e) => e.stopPropagation()}
    >
      {/* css:.w-fit {width: fit-content;}宽度自适应,根据内容宽度撑开  px就是在pading横向*/}
      {/* 新建表情按钮,使用封装子组件方式 */}
      <ReactionButton reaction="👍" onSelect={setReaction} />
      <ReactionButton reaction="🔥" onSelect={setReaction} />
      <ReactionButton reaction="😍" onSelect={setReaction} />
      <ReactionButton reaction="👀" onSelect={setReaction} />
      <ReactionButton reaction="😱" onSelect={setReaction} />
      <ReactionButton reaction="🙁" onSelect={setReaction} />
    </div>
  );
}
// 声明表情按钮组件,注册传入参数,参数类型
function ReactionButton(
  {
    reaction,
    onSelect,
  }: {
    reaction: string;
    onSelect: (reaction: string) => void;
  }
) {
  // 每个按钮的小方块
  return (
    <button
      className="transform select-none p-2 text-xl transition-transform hover:scale-150 focus:scale-150 focus:outline-none"
      onPointerDown={() => onSelect(reaction)}
    >
        {/* .select-none {user-select: none;} 禁用用户对元素内容的选择操作
      .text-xl {font-size: 1.25rem;line-height: 1.75rem;}font 20px line -28px
      */}
      {reaction}
    </button>
  );
}

2.新建flyReaction文件,该文件主要根据事件展示表情


export default function FlyingReaction({ x, y, timestamp, value }: Props) {
  return (
    <div
      className={`pointer-events-none absolute select-none ${
        styles.disappear
      } text-${(timestamp % 5) + 2}xl ${styles["goUp" + (timestamp % 3)]}`}
      style={{ left: x, top: y }}
    >
        //展示的图标,一左一右,展示
      <div className={styles["leftRight" + (timestamp % 3)]}>
        <div className="-translate-x-1/2 -translate-y-1/2 transform">
          {value}
        </div>
      </div>
    </div>
  );
}

好吧,我今晚没看懂这个代码,待我深入一下再总结

3.在liver主画布中将设置reaction的函数setReactions


// 设置当前反射状态,当前光标模式,
const setReactions = useCallback((reaction: string) => {
        setCursorState({ mode: CursorMode.Reaction, reaction,isPressed: false })
    }, [])
//这个干嘛的,还没懂
const borcast = useBroadcastEvent()
// 只显示4秒内的reaction
    useInterval(() => {
        setReaction((reactions) =>
          reactions.filter((reaction) => reaction.timestamp > Date.now() - 4000)
        );
      }, 1000);
    useInterval(() => {
        // 为什么在这里面可以有cursorState.reaction?
        if (cursorState.mode === CursorMode.Reaction &&
            cursorState.isPressed && cursor) {
            
            setReaction((reactions) => reactions.concat([
                {
                    point: { x: cursor.x, y: cursor.y },
                    value: cursorState.reaction,
                    timestamp: Date.now()
                }
            ]))
            borcast({
                x:cursor.x,
                y:cursor.y,
                value:cursorState.reaction,
            })
        }
           
    }, 500);

2.live Avatar Stack实时头像堆栈

效果展示

2.png

1.新建用户头像栈,用户头像容器


import { useOthers, useSelf } from "@/liveblocks.config";
import { Avatar } from "./Avatar";
import styles from "./index.module.css";
import { generateRandomName } from "@/lib/utils";
import { useMemo } from "react";
​
​
const ActiveUsers = () => {
    // 获取其他用户数据
    const users = useOthers();
    // 获取当前用户数据,自己的
    const currentUser = useSelf();
    // 使用useMemo缓存组件,防止移动鼠标后渲染
    const haresi = useMemo(() => {
        const hasMoreUsers = users.length > 3;
        return (
            // 展示两个用户图标
            <main className='flex items-center justify-center gap-1'>
                {/* .gap-1 {gap: 0.25rem} Css的栅栏布局,占1/4父元素 */}
                <div className="flex pl-3">
                    {currentUser && (
                        // 当前用户
                        <Avatar name="You" otherStyles="border-[3px] border-primary-green" />
                    )}
                    {users.slice(0, 3).map(({ connectionId, info }) => {
                        // 只展示前三个,遍历用户列表,展示用户id和图标
                        return (
                            <Avatar key={connectionId} name={generateRandomName()} otherStyles="" />
                        );
                    })}
                    {/* 当用户人数大于3时候展示其他效果 */}
                    {hasMoreUsers && <div className={styles.more}>+{users.length - 3}</div>}
                </div>
            </main>
        );
    }, [users.length])
    return haresi
}
export default ActiveUsers

用户头像


const IMAGE_SIZE = 48;
​
export function Avatar({ name, otherStyles }: { otherStyles: string; name: string }) {
  return (
      //// 用户头像容器样式,
    <div className={`${styles.avatar} ${otherStyles} h-9 w-9 `} data-tooltip={name}>
        {/* 图标src,样式,src用不了,官网数据没了,需要自己的图片,不用也行 */}
      <Image
        src={`https://liveblocks.io/avatars/avatar-${Math.floor(Math.random() * 30)}.png`}
        fill
        className={styles.avatar_picture}
        alt={name}
      />
    </div>
  );
}

3.canvas

画布,暂时没完成,

1.在live中新建canvas画布,


///live.tsx
<canvas ref={canvasRef} />
///page.tsx
 // 创建画布
  const canvasRef = useRef<HTMLCanvasElement>(null);
  // 创建fabric,可以对画布进行操作,在安装fabric记得安装@type/fabric类型声明
  const fabricRef = useRef<fabric.Canvas | null>(null);
  // 判断是否在方块中
  const isDrawing = useRef(false)
  // 获取图形元素
  const shapeRef = useRef<fabric.Object | null>(null)
  // 选择图形元素
  const selectedShapeRef = useRef<string | null>('rectangle')
//  实现异步操作,初始化画布,绑定事件
  useEffect(() => {
    console.log(fabricRef);
    // 初始化
    const canvas = initializeFabric({ canvasRef, fabricRef })
    // 画布绑定点击事件
    canvas.on("mouse:down", (options) => {
      handleCanvasMouseDown({
        options,
        canvas,
        isDrawing,
        shapeRef,
        selectedShapeRef,
      });
    });
    // 监听窗口是否改变大小
    window.addEventListener("resize", () => {
      handleResize({
        canvas: fabricRef.current,
      });
    })
  }, [])
​
​
......
<Live  canvasRef={canvasRef} />
.....

反正这个也不是什么技术拓展文章,能看到这句你牛。

4.算法有效的括号

先上代码,力扣的题,他的问题有问题,不要瞎想,必须是前后顺序闭合,不能够交叉闭合,[({})]这样就行了

var isValid = function(s) {
    // 还是老样子,结构数组变量
    const stack = [], 
        map = {
            "(":")",
            "{":"}",
            "[":"]"
        };
        // 遍历给定元素
    for(const x of s) {
        // 遍历键名,存在,则入栈,
        if(x in map) {
            stack.push(x);
            continue;
        };
        // 如果最后一个值与当前闭合则出栈
        if(map[stack.pop()] !== x) return false;
    }
    // 当栈为空则说明全部闭合
    return !stack.length;
};