Tìm kiếm trang web

solid js - Phát hiện nhấp chuột bên ngoài và thay đổi trạng thái của component trên Typescript (SolidJS)


Tôi học framework SolidJS và gặp vấn đề. Tôi muốn thay đổi trạng thái của phần tử bằng các chỉ thị, nhưng nó không hoạt động. Tôi làm sai chỗ nào? Toàn bộ dự án - https://github.com/XPahanX/editor (không phải phiên bản hiện tại)

Thành phần :

import { Component, createSignal, ParentComponent, Show } from 'solid-js';
import clickOutside from '../directives/click-outside';

clickOutside;

const EditorBlockMenu: Component<{fun: () => false}> = (prop) => {
    return (
        <div class='editor-block-menu' use:clickOutside={prop.fun}>
            <div><button>Delete</button></div>
            <div><button>Move Up</button></div>
            <div><button>Move Down</button></div>
        </div>
    )
}

const EditorBlockBtn: ParentComponent = () => {
    const [toggle, setToggle] = createSignal(false)
    const isToggle = () => setToggle(!toggle())

    return (
        <div classList={{'editor-block-btn': !toggle()}}>
            <button onClick={isToggle}>
                
            </button>
            <Show
                when={toggle()}
                fallback={<></>}
            >
                <EditorBlockMenu fun={() => setToggle(false)}/>
            </Show>
        </div>
    )
}

export default EditorBlockBtn;

Chỉ thị :

import { onCleanup } from "solid-js";

// https://www.solidjs.com/tutorial/bindings_directives?solved
// need fix
export default function clickOutside(el:Element, accessor: () => false) {
  const onClick = (e: Event) => 
    !el.contains(e.target as Node) && accessor();
  document.body.addEventListener("click", onClick);
  onCleanup(() => document.body.removeEventListener("click", onClick));
}

declare module "solid-js" {
  namespace JSX {
    interface Directives {
      clickOutside: () => false;
    }
  }
}

Theo như tôi hiểu, hàm setToggle() không hoạt động trong fun={}. Tôi không mạnh về Typescript, tôi hy vọng nhận được sự giúp đỡ của bạn.


Tôi sử dụng câu trả lời đầu tiên, nhưng nhận được một lỗi:

const EditorBlockMenu: Component = () => {
    return (
        <div class='editor-block-menu'>
            <div><button>Delete</button></div>
            <div><button>Move Up</button></div>
            <div><button>Move Down</button></div>
        </div>
    )
}

const EditorBlockBtn: ParentComponent = () => {
    const [toggle, setToggle] = createSignal(false)
    const isToggle = () => setToggle(!toggle())
    let ref: HTMLDivElement

    const handleClick = (event: MouseEvent) => {
        if(!ref.contains(event.target as Node)) { // withuot `as Node` highlights in red
          setToggle(false)
        }
      }
    
      onMount(() => {
        document.addEventListener('click', handleClick);
      })
      
      onCleanup(() => {
        document.removeEventListener('click', handleClick);
      })

    return (
        <div classList={{'editor-block-btn': !toggle()}}>
            <button onClick={isToggle}>
           
            </button>
            <Show
                when={toggle()}
                fallback={<></>}
            >
                <EditorBlockMenu ref={ref!}/>
            </Show>
        </div>
    )
}

export default EditorBlockBtn;

Hình ảnh

Câu trả lời #1

Có một hướng dẫn trên trang web của SolidJS minh họa chính xác cùng một trường hợp sử dụng:

https://www.solidjs.com/tutorial/bindings_directives

Các chỉ thị thì tốt khi bạn sao chép một chức năng cho nhiều phần tử, nếu không bạn có thể tự triển khai nó trực tiếp bên trong bất kỳ thành phần nào:

import { createSignal, onCleanup, onMount } from 'solid-js';

export const App = () => {
  let ref: HTMLDivElement;
  const [show, setShow] = createSignal(true);

  const handleClick = (event: MouseEvent) => {
    if(!ref.contains(event.target)) {
      setShow(false);
    };
  };

  onMount(() => {
    document.addEventListener('click', handleClick);
  });
  
  onCleanup(() => {
    document.removeEventListener('click', handleClick);
  });

  return (
  <div ref={ref!}>
    Visible: {show() ? 'true': 'false'}
  </div>
  );
};

https://playground.solidjs.com/anonymous/c933b32f-67cb-45e9-843c-6555144c33f5

Câu trả lời #2

Nói chung, sau vài lần thử và sai, tôi đã quyết định một phương pháp mới mà có hiệu quả. Tất nhiên, tôi đã đi lệch khỏi con đường đã định ban đầu, nhưng tôi nghĩ không có giải pháp nào tốt hơn cho nhiệm vụ này.

const EditorBlockBtn: ParentComponent = () => {
    const [toggle, setToggle] = createSignal(false)
    const isToggle = () => setToggle(!toggle())
    let divRef: HTMLDivElement
    let btnRef: HTMLButtonElement

    const handleClick = (event: MouseEvent) => {
        if(!divRef.contains(event.target as Node) && !btnRef.contains(event.target as Node)) {
            setToggle(false)
        }
    }
    
    onMount(() => {
        document.addEventListener('click', handleClick)
    })
    
    onCleanup(() => {
        document.removeEventListener('click', handleClick)
    })

    return (
        <div classList={{'editor-block-btn': !toggle()}}>
            <button onClick={isToggle} ref={btnRef!}>
           
            </button>
            <Show
                when={toggle()}
                fallback={<></>}
            >
                <div class='editor-block-menu' ref={divRef!}>
                    <div><button>Delete</button></div>
                    <div><button>Move Up</button></div>
                    <div><button>Move Down</button></div>
                </div>
            </Show>
        </div>
    )
}

export default EditorBlockBtn;

Bài viết liên quan