vue3学习笔记之Fragment和Emits

5,388 阅读2分钟

Fragment和Emits

本文主要包含两部分内容:

  1. Fragments-碎片
  2. emits 自定义事件

(一)Fragments

Fragments 作为vue3 的新特性之一,允许一个vue组件可以有多个根节点。创建一个如下的组件,vue3中开箱即用

<template>
	<header>...</header>
	<main v-bind="$attrs">...</main>
	<footer>...</footer>
</template>

相比于vue3,vue2规定创建一个vue组件,只能有一个根节点,在vue2中创建如上的一个vue组件,会报如下错:

Errors compiling template:
Component template should contain exactly one root element.

原因是代表任何组件的vue实例需要绑定到一个单一的DOM元素中。唯一可以创建一个具有多个DOM节点的组件的方法就是创建一个没有底层Vue实例的功能组件。

目前可以在vue2中使用vue-fragments库来使用Fragments

Fragments 用起来像一个普通的DOM元素,但它是虚拟的,根本不会在DOM树种呈现。这样我们就可以将组件功能绑定到一个单一的元素中,而不需要创建一个多余的DOM节点。

(二) Emits Component Option

Vue3 中组件发送的自定义事件需要定义在emits 选项中:

  • 若自定义事件名与原生事件冲突,比如'click',倘若没有在emits选项中设置,则会有触发两次事件的坑
  • 更好的指示组件工作方式
<template>
  <button @click="$emit('click')">
    自定义事件
  </button>
</template>
<script>
  import { defineComponent } from "vue";

  export default defineComponent({
    emits: ['click'] // 此处与原生事件名冲突,若没有设置,则点击会触发两次,一次为自定义事件,一次为原生事件
  })
</script>

注意:尽量避免自定义事件名与原生事件名冲突

  • 参数有两种形式对象和数组,对象里面可以配置带校验函数的事件,为null表示不校验,校验函数将接收传递给$emit 调用的其他参数,如`$emit('event', 1)被调用,event事件对应的校验函数接收参数1,返回布尔值,表示事件参数是否有效
// search-btn组件
<template>
	<a-button @click="onReset">
      重置
    </a-button>
    <a-button
      type="primary"
      @click="onSearch"
    >
      搜索
    </a-button>
</template>

<script lang="ts">
import { defineComponent } from 'vue';

export default defineComponent({
  name: 'search-btn',
  emits: {
    // 没有校验函数
    reset: null,
     // 带校验函数
    search: playload 为子组件向父组件传的值 => {
      // playload 为子组件向父组件传的值
      if (playload) {
    	// 校验通过
        return true;
      } else {
         // 校验不通过                      
        return false;
      }
    }
  },
  setup(props, { emit }) {
	const onReset = () => {
      emit('reset');
    };
    const onSearch = () => {
      emit('search');
    };

    return {
      onSearch
    };
  }
});
</script>
// 父组件 index.vue
 <search-btn @reset="onReset" @search="onSearch" />

// js核心代码
const onSearch = () => {
   console.log('执行外部的事件')
}

注意:校验不通过的时候,控制台会输出一个警告,但是emits事件会继续执行。

image-20210412204625592.png

这里有个坑,一开始理解以为是校验不通过就拦截,不执行外部组件的方法,但经过测试,发现还是会继续执行,只是输出一个警告,所以个人认为这个校验函数还是比较鸡肋

思考

问题一:vue2为什么不引入Fragments?

根据Vue贡献者的说法,vue2限制组件只能有一个根节点, 主要原因是虚拟DOM diff算法依赖于具有单个根的组件,如果允许Fragments需要对该算法进行重大更改,不仅要使其正常工作,而且必须使其具有高性能,这是一项非常艰巨的任务。

image-20210413173722242.png

github.com/vuejs/vue/i…

划重点,vue2不引入主要是diff算法的缘故,

问题二:vue3引入Fragments,diff算法是否变化?渲染机制是否改变?

TODO: diff算法理解