Svelte系列 --- 事件

1,454 阅读4分钟

事件绑定

基本使用

<script>
    function handleClick() {
	console.log('event handler is working');
    }
</script>

<!-- 
    这是svelte中最为简单的事件绑定方式
    on:click="{handleClick}" <=> on:click={handleClick}
    唯一的区别是: on:click="{handleClick}"可能会存在语法高亮,而另一种可能没有
-->
<button on:click="{handleClick}">点我触发事件</button>

内联事件

<!--
    在某些框架中,不推荐使用内联事件,尤其是在循环中,因为这往往意味着可能创造多个相同的函数,会造成性能的损失
    但是这个规则不适用 Svelte,无论你选择哪种形式,编译器都将始终会做正确的事情
-->
<button on:click="{() => console.log('event handler is working')}">点我触发事件</button>

事件修饰符

svelte允许我们使用事件修饰符来对我们的事件处理函数的执行和触发加以限制

修饰符作用
preventDefault在运行事件处理程序之前先调用 event.preventDefault(),来阻止默认事件
stopPropagation调用 event.stopPropagation() 停止事件冒泡,防止事件传播到下一个元素
passive改进触摸/滚轮事件的滚动性能(Svelte 默认会自动在安全的地方添加它),
也就是直接执行事件的默认行为,而不需要检测有没有阻止默认行为
passive和preventDefault同时使用的时候,preventDefault会失效
nonpassive显式设置 passive: false
Svelte会在合适的地方自动添加passive修饰符,此时preventDefault修饰符就会失效
如果我们明确在触摸/滚动事件中需要添加preventDefault,
我们可以显示添加nonpassive,以阻止浏览器自动添加passive修饰符
capture捕获 阶段就触发处理程序,而非 冒泡 阶段
once在运行一次事件处理后,立即将其移除
self仅当 event.target 是元素本身时(也就是是自身元素触发该事件时)才触发事件处理程序
trusted事件是用户主动触发的,而不是通过JavaScript进行触发的(例如: element.dispatchEvent(...))
当事件是用户主动触发的时候,event.isTrusted的值将会是true
<!-- 事件修饰符的基本使用 -->
<button on:click|once={handleClick}>
    Click me
</button>

<!----------------------------------->

<!-- 多个事件修饰符 连用 -->
<button on:click|once|preventDefault|self={handleClick}>
    Click me
</button>

组件事件

子组件有些使用需要向父组件发送(dispath)事件(可以是原生dom事件,也可以是用户自定义事件),

例如子组件向父组件通信(数据传递)的时候。为此,需要创建一个事件分发器(dispatcher)

<!-- 子组件 -->
<script>
    // 引入事件分发器创建方法 	
    import { createEventDispatcher } from 'svelte'
	
    // 必须在组件初始化的时候就创建事件分发器 --- 也就是在顶层script作用域中
    // 以便于svelte可以将事件分发器绑定到组件实例对象上
    // 这也就意味着在定时器中或函数方法(如这里的sayHello)中生成事件分发器是没有意义的
    const dispatch = createEventDispatcher();
	
    function sayHello() {
       // dispath(事件名, 需要传递的数据)
       // 需要传递的数据可以是任意数据类型,这里使用的是对象
       dispatch('message', {
	 msg: 'Hello Svelte'
       })
    }
</script>

<button on:click={sayHello}>
    Click to say hello
</button>
<!-- 父组件 -->
<script>
  import Inner from './Inner.svelte';

  function handleMessage(event) {
    // 子组件传入的数据,会存在于event.detail中
    // 因为这里传入的是一个对象,所以可以通过点语法来进行值的获取
    alert(event.detail.msg);
  }
</script>

<!-- 当子组件触发自定义的message方法的时候,handleMessage方法会被触发 -->
<Inner on:message={handleMessage}/>

<!---------------------------------------------->

<!-- 这是另一个父组件 -->
<script>
  import Inner from './Inner.svelte';
</script>

<!-- 
    父组件并没有message事件响应代码,此时当子组件触发message事件的时候
    父组件知道子组件触犯了message事件,但是因为没有任何对应的事件响应函数
    所以此时并不会报错, 但是同样的也不会有任何的响应行为发生
-->
<Inner />

事件转发

与DOM事件不同,组件事件不会 冒泡

如果要在某个深层嵌套的组件上监听事件,则中间组件必须 转发 该事件。

中间组件

<script>
  import Inner from './Inner.svelte';
  import { createEventDispatcher } from 'svelte';

  const dispatch = createEventDispatcher();

  function forward(event) {
    dispatch('message', event.detail);
  }
</script>

<Inner on:message={forward}/>

此时中间组件中会存在大量的转发子组件事件给父组件的相关代码

这些代码明显是冗余的,所以svelte给我们提供了一种语法糖

<script>
  import Inner from './Inner.svelte';
</script>

<!-- 如果我们只写了事件名,而没有写值的时候,就代表“转发所有同类型事件”, Svelte 自动生响应的事件转发代码 -->
<Inner on:message/>

我们不仅仅可以转发自定义事件,同样的,在svelte中我们还可以转发原生DOM事件

<!-- 子组件 -->

<!--
  假设这是一个组件,我们对于组件的事件处理不应有组件来进行实现
  而是应该由组件的使用者,也就是父组件,根据具体的需求来进行实现
  所以我们此时就只需要监听到对应的事件然后转发给父组件即可
-->
<button on:click>
	Click me
</button>

<!-------------------------------------------------->

<!-- 父组件 -->
<script>
    import CustomButton from './CustomButton.svelte';

    function handleClick() {
       // 子组件触发点击事件后,会转发给父组件
       // 随后父组件会触发点击事件,并触发该函数中的逻辑代码
            alert('Button Clicked');
       }
</script>

<CustomButton on:click={handleClick}/>