Как нажать кнопку в одном компоненте и вызвать событие в другом компоненте в Svelte?

Я новичок в Svelte и все еще учусь, но я застрял в чем-то, что кажется довольно простым. Я использую Svelte и Svelte Material UI, чтобы создать приложение в стиле материального дизайна.

Я начал с простой панели приложений и выдвижное меню. Проблема, с которой я столкнулся, заключается в том, что в документах пользовательского интерфейса Svelte Material кнопка, которая заставляет меню выдвигаться и выдвигаться, является частью того же компонента меню: https://github.com/hperrin/svelte-material-ui/blob/master/site/src/routes/demo/menu.svelte

В моем случае я хотел бы, чтобы кнопка была частью моего компонента панели приложений, и когда я нажимаю на нее, компонент меню должен выдвигаться (или вставляться).

Я видел примеры того, как передавать свойства (данные) от одного компонента к другому, но не как запускать событие от одного компонента к другому.

Что я пробовал:

  • экспорт функции (кажется, скрипт должен быть модулем, как описано здесь)
  • экспорт логического значения и изменение его извне (выдает ошибку, я точно не помню, что это было)

Мой код выглядит следующим образом (с использованием метода экспорта функции):

App.svelte

<script>
  import TopAppBar, {Row, Section, Title} from '@smui/top-app-bar';
  import IconButton from '@smui/icon-button';
  import AppMenu, {Toggle} from "./AppMenu.svelte";

  let prominent = false;
  let dense = true;
  let secondaryColor = false;
</script>


<TopAppBar variant="static" {prominent} {dense} color={secondaryColor ? 'secondary' : 'primary'}>
  <Row>
    <Section>
      <IconButton class="material-icons" on:click={Toggle}>menu</IconButton>
      <Title>Test app</Title>
    </Section>
    <Section align="end" toolbar>
      <IconButton class="material-icons" aria-label="Print this page">account_circle</IconButton>
      <IconButton class="material-icons" aria-label="Bookmark this page">home</IconButton>
    </Section>
  </Row>
</TopAppBar>
<AppMenu></AppMenu>
<div>
    Lorem ipsum dolor sit amet, consectetur adipiscing elit. Quisque tellus libero, semper at lobortis at, congue sit amet lorem. Aliquam porttitor varius sagittis. In non lorem lorem. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Pellentesque fringilla et nulla et tempus. Vestibulum pharetra tristique neque, non sodales massa dignissim vulputate. Sed eget leo tellus. Phasellus egestas gravida ante. 
</div>

Appmenu.svelte

<script>
  import Menu from '@smui/menu';
  import List, {Item, Separator, Text} from '@smui/list';
  import Button from '@smui/button';
  let menu;
  let clicked = 'nothing yet';
  let menustate = false;
</script>

<script context="module">
  export function Toggle(){
    menu.setOpen(open = !open)
  }
</script>

    <div style="min-width: 100px;">
      <Button on:click={() => menu.setOpen(true)}>Open Menu</Button>
      <Menu bind:this={menu}>
        <List>
          <Item on:SMUI:action={() => clicked = 'Cut'}><Text>Cut</Text></Item>
          <Item on:SMUI:action={() => clicked = 'Copy'}><Text>Copy</Text></Item>
          <Item on:SMUI:action={() => clicked = 'Paste'}><Text>Paste</Text></Item>
          <Separator />
          <Item on:SMUI:action={() => clicked = 'Delete'}><Text>Delete</Text></Item>
        </List>
      </Menu>
    </div>

Любая помощь приветствуется


person Erik Oosterwaal    schedule 05.09.2020    source источник


Ответы (2)


Ваш пример должен работать. Вот очень простой пример экспорта функции:

//C.svelte
<script context="module">
export function myFunc() {
  console.log("myFunc")
}
</script>

// App.svelte
<script>
  import {myFunc} from "./C.svelte"
</script>
<h1 on:click={myFunc}>click me</h1>

Я думаю, вам следует изучить такие вещи на очень простых примерах, а затем объединить их в более сложные программы. Я также рекомендую оставить внешние библиотеки подальше и сначала изучить вещи с помощью собственных элементов, потому что эти библиотеки скрывают вещи, изменяют поведение и даже содержат ошибки.

person grohjy    schedule 05.09.2020
comment
Что ж, тогда мой подход кажется правильным, но мой скрипт (context = module) не может взаимодействовать с объектами в другом блоке скрипта. Поэтому я не могу обратиться к menu. Я что-то создаю и учусь по ходу дела, поэтому я не боюсь отказываться от инфраструктуры пользовательского интерфейса. - person Erik Oosterwaal; 05.09.2020
comment
Переменные в context=”module” не являются реактивными, возможно, вам стоит использовать store в вашем случае. Дополнительная информация: svelte.dev/docs#script_context_module - person grohjy; 05.09.2020
comment
Вот рабочий пример, но он кажется немного взломанным: svelte.dev/repl/ efd9db7b3c9c41c4a60de48b58b8214a? version = 3.24.1 - person grohjy; 05.09.2020
comment
Я согласен, это выглядит взломанным, я думаю, вы правы в своем замечании о магазинах. Я читал об этом, и, похоже, это мой вариант использования. - person Erik Oosterwaal; 05.09.2020

Хотя использование подхода context="module" будет работать, в вашем случае вы можете просто распространить функцию переключения дальше.

Позвольте MenuApp экспортировать функцию переключения
В App используйте синтаксис bind для привязки вашего AppMenu к чему-либо (appMenu < / em>?)
Вызов toggle объекта с помощью кнопки

<IconButton class="material-icons" on:click={appMenu.toggle}>menu</IconButton>
person Stephane Vanraes    schedule 05.09.2020
comment
Вы имеете в виду этот пример? svelte.dev/repl/fbf5b6994e9c41a9bfa2a0ae52e - person grohjy; 06.09.2020
comment
да, но это работает, только если компоненты находятся относительно близко, конечно - person Stephane Vanraes; 06.09.2020