根据文档横向对比vue2.0与vue3.0(二)

993 阅读5分钟

前言

在上篇文章里,根据vue2.0与vue3.0的文档,针对基础部分进行了横向对比。基础部分的对比主要是比较琐碎的内容,比如一些很细节的写法,又或是几个名称的变化。(不过在我看来,正是因为这各种琐碎,才让人习惯性的敲出来后,又得一个个删掉,这不就暴躁起来了吗)。

现在对比进入到了第二阶段,本篇内容主要为vue2.0与vue3.0的组件部分横向对比。

组件部分,在我看来其实是vue很核心的内容,所以其实vue3.0对比vue2.0在组件部分上没有很大的改动(当然也有一点啦🤏)。因此,本篇文章主要内容,除了进行vue2.0与vue3.0语法上的横向对比外,主要还进行了内容的重点概括。

(对比差异部分,使用2️⃣3️⃣分别表示vue2.0与vue3.0)

组件部分对比思维导图.png

(对比差异部分,使用2️⃣3️⃣分别表示vue2.0与vue3.0)

组件相关介绍

  • 组件:可复用的vue实例。个人认为所谓的“组件”主要为页面组件,将界面中重复的部分连同功能一起提取成可重用的代码段。

  • 组件特点:

    1、多次使用均相互独立,每次都是新实例。

    2、组件的根元素:

    2️⃣组件只能有单个根元素,需要将模板的内容包裹在一个父元素内。
    3️⃣组件允许多个根元素。
    

组件的基础使用

  • 定义组件名:

    1、kebab-case法。定义和引用都需要使用这个短横线写法。

    2、PascalCase法。定义这样写,引用时可以用短横线写法或同定义写法。

  • 使用组件:

    1、注册组件

      1)全局注册:
      可全局使用,但就算不使用,打包的时候还是会打包进去,造成多余部分下载。
      组件间不具备层次关系,均可互相调用。
    
      2)局部注册:
      需在用组件的位置注册。
      组件间具备层次关系,需要引用才可使用。
    

    2、创建组件实例

    3、使用组件

  • vue2.0与vue3.0 对比:

1、组件注册方式变化:
 2️⃣Vue.component('component-name',{})
 3️⃣const app = Vue.createApp({});app.component('component-name',{})

2、挂载方式变化:
 2️⃣new Vue()
 3️⃣app.mount()

关于props

通过prop父组件向子组件传递数据

  • 用法:父传数据给子,子用props选项承接数据。

  • 命名相关:attribute是大小写不敏感的,所以父需要用 kebab-case法,子用PascalCase法承接。

  • 数据类型相关:

    1、props可为数组或对象。

    2、父组件可以传任何类型的值。(除了静态字符串,其他借助v-bind传)

  • 特性:props是单向数据流,单向下行。

    1)防止从子组件意外变更父级组件的状态,从而导致数据流向难以理解。
    2)对象和数组是引用传入同根数据的,子组件改变则会影响父组件的状态。
      (应避免使用,因为无视了单向数据流原则)
    
  • 如需在子组件改变接收到的props:

    方法一:复制一份data为本地prop数据来使用。

    props: ['initialCounter'],
    data: function () {
      return {
        counter: this.initialCounter
      }
    }
    

    方法二:定义一份计算属性,适合于需要数据改造的情况。

    props: ['size'],
    computed: {
      normalizedSize: function () {
        return this.size.trim().toLowerCase()
      }
    }
    
  • 关于prop验证

    注意:会在一个组件实例创建之前进行验证,所以不要在验证中使用data等。

    用法:validator选项用来自定义验证函数。

    validator:(value)=>{
    return ['success', 'warning', 'danger'].indexOf(value) !== -1
    }
    

非 Prop 的 Attribute

  • 介绍:一个非 prop 的 attribute 是指传向一个组件,但是该组件并没有相应 props 或 emits 定义的 attribute。(常见的示例包括 class、style 和 id attribute。可以通过 $attrs property 访问那些 attribute )

  • 使用:

    1、一般情况下继承:父组件使用子组件时,添加的属性事件等,会自动添加到子组件的根节点。

    2、如果需要禁用继承:在子组件中设置 inheritAttrs: false ,通过 v-bind="$attrs" 来决定父组件给的property传到那个位置。

    3、3️⃣如果子组件有多个根节点,需要 v-bind="$attrs" 来显示的绑定父组件传值位置。

自定义事件 emits

自定义事件的用法

  • 子组件上:

    1、3️⃣vue3.0 新增emits选项:

       1、emits选项,和现有的 props 选项类似,可通过emits选项定义组件可触发的事件。
       2、emits选项可为 数组或对象,在emits选项内对自定义事件进行定义。
       3、备注:
         关于原生事件:
           在 emits 选项中定义了原生事件 (如 click) 时,将使用组件中的事件替代原生事件侦听器。
           
         关于验证函数:
           子组件使用 $emit 调用父组件对应函数,如果需要验证该方法,可以为这个事件分配一个函数,该函数接收传递给 emit 调用的参数,并返回一个布尔值以指示事件是否有效。
    

    2、通过$emit('event-name',传参) 触发事件。

  • 父组件上:父用 @event-name="自定义函数"承接,并在自定义函数的第一个参数处获得传参。

监听原生事件

  • native修饰符

    2️⃣父级调用组件时,使用.native修饰符,一般可监听到原生事件。

    <base-input v-on:focus.native="onFocus"></base-input>
    

    3️⃣vue3.0 已移除该修饰符。

  • $listeners 实例方法

    1、如果组件内是一些特定元素,可能监听不到,所以组件内可通过$listeners,将所有监听器指向特定的子元素。

    2、当组件内部的根元素不一定是对应的元素时,如想监听base-input内部的input,但没想到组件最外层是label。

插槽 slot

插槽的一般使用

主要用于父组件给子组件传内容。

使用时,父在调用子组件位置中传内容;子在对应显示位置用插槽slot标签,slot标签作为想要插入内容的占位符。

关于插槽

1、槽内可以包含任何模板代码,包括 HTML、组件。

2、插槽传值作用域,父用父子用子。(父级模板里的所有内容都是在父级作用域中编译的;子模板里的所有内容都是在子作用域中编译的。)所以不能从父级传子级作用域的东西。

3、插槽默认值(后备),写在slot标签内,父不提供插槽内容时展示默认值。

其他插槽类型

默认插槽的缩写语法不能和具名插槽混用,因为它会导致作用域不明确。混合使用必须要用完整的语法。

具名插槽

  • 适用场景:一个组件内多个插槽,想对应位置对应展示。

  • 用法:

    1、子组件上:通过name给插槽分配id,不写则默认name:default

    <slot name="header"></slot>
    

    2、父组件上:<template>元素上使用 v-slot 指令,v-slot:可简写为 #。

    <template v-slot:header>
        <h1>Here might be a page title</h1>
    </template>
    

作用域插槽

  • 适用场景:父想访问子的数据并展示。

  • 用法

    1、子组件上:在<slot>通过v-bind 绑定prop让父的对应位置能够拿到。

    <span>
      <slot v-bind:user="user">
        {{ user.lastName }}
      </slot>
    </span>
    

    2、父组件上:<template> 元素上使用 v-slot 指令定义插槽prop并使用,可简写,将插槽prop重命名进行使用。

    <current-user>
      <template v-slot:default="slotProps">
        {{ slotProps.user.firstName }}
      </template>
    </current-user>
    
    //可对插槽prop进行重命名为person:
    <current-user v-slot="{ user: person }">
      {{ person.firstName }}
    </current-user>
    

依赖注入 provide/inject

  • 作用:长距离的 prop 效果。

    组件深层嵌套时,深层子组件需要最外层父组件,需要将prop沿着组件链级传递,会很麻烦,这时候就可以用 provide inject,无论组件层次结构有多深,父组件都可以作为其所有子组件的依赖提供者。

  • 使用方式

    1、父组件提供数据。provide:{}/(){return{}}

    2、在深层子组件内可使用数据。inject:[]

    3、备注:除了基本操作外,如果需要provide一些组件的实例,需要转为返回对象的函数,而不能直接使用对象。

    // 错误
    provide: {
     todoLength: this.todos.length 
    },
    
    // 正确
    provide() {
      return {
       todoLength: this.todos.length
      }
    },
    
    
  • 特点:

    provide和inject的绑定不是响应式的,改变子中的对应值,父不会改变。

    如果需要改变,祖先传带有计算属性的值。

    provide() {
        return {
          todoLength: Vue.computed(() => this.todos.length)
        }
      }
    
  • 备注

    2️⃣在vue2.0中,依赖注入的内容属于“边界情况”,建议少用。

    3️⃣在vue3.0中,将依赖注入内容移出了“边界情况”,证明使用率的提高。

动态组件

  • :is 可切换不同组件

    <component v-bind:is="currentTabComponent"></component>
    
    //其中的currentTabComponent,可以为已注册组件的名字/组件的选项对象
    
  • keep-alive 保持组件状态,即缓存

    因为每次切换,vue都会创建一个新的currentTabComponent 实例,所以会出现希望缓存的场景。

模板引用 ref

  • 作用:访问子组件实例/子元素。

  • 使用:ref在子组件赋予一个id引用,父组件通过this.$refs.xxx访问。

  • 备注:$refs只会在组件渲染完成之后生效。

  • 区别:

    2️⃣在vue2.0中,模板引用的内容属于“边界情况”,建议少用。

    3️⃣在vue3.0中,将模板引用内容移出了“边界情况”,证明使用率的提高。

元素位置受限情况

  • 问题:有些元素需要限制内部元素。如tabel里应该放tr,若组件内写其他的内容,则会被视为无效。

  • 解决:

    1、可以用is来确定组件,给一定的标签赋予组件名称。

    2、当组件用于原生元素,需要vue:开头。

边界情况(建议少用的情况)

1、访问根实例:$root

2、访问父组件实例:$parent

3、访问子组件实例:$children(3️⃣在vue3.0中已废除该实例方法)

4、程序化事件侦听:$on/$once/$off(3️⃣vue3.0已移除这三个实例方法)

5、强制更新:$forceUpdate

6、仅渲染一次就缓存:v-once(适用于一个组件包含了大量静态内容,内容只计算一次然后缓存起来)

父子组件相互关系汇总

数据相关

  • 父传给子:

    1、prop

    2、插槽 slot

    3、依赖注入 provide/inject(长距离传输)

  • 子传给父:

    1、自定义事件 emits

实例相关

  • 访问子组件实例:

    1、模板引用 $refs

    2、$children(3️⃣在vue3.0中已废除该实例方法)

  • 访问夫组件实例:

    1、$root 访问根实例

    2、$parent

结尾

本篇文章主要为根据文档,针对vue2.0与vue3.0的组件部分进行横向对比。

总体而言,组件部分最大的改变,就是在vue3.0中增加了emits选项内容,这让自定义事件更加的具体即更有针对性。其他细节方面,也有很多是因为emits的存在,所以废除了一些实例方法。

其实,本篇文章也是个人针对vue组件部分内容的概括(不代表所有人哈),vue组件常用的部分主要就是上述陈列的内容。那为啥还列出来呢?

其实主要是因为,在我个人的想象里,vue内容居多巨多巨复杂(前端小菜鸡的自述🙃),vue就像一片汪洋大海,感觉自己纯粹是海里的鱼,虽然在其中游来游去,但总觉得远方还有一大片未曾到达过的的未知领域。这会让我惧怕未知。但花了时间和精力列出来后,就仿佛看到了海洋的边缘,虽然肯定还会有很多未知,但自己心里会清楚,这些未知就在这片海里。

接下来计划,以相同的vue2.0与3.0文档横向对比方式,对比可复用部分等内容,个人认为这是vue3.0最大的变化部分。

传送门

vue2.0与vue3.0 基础部分 对比:根据文档横向对比vue2.0与vue3.0(一)

vue2.0与vue3.0 组件部分 对比:根据文档横向对比vue2.0与vue3.0(二)

vue2.0与vue3.0 可复用&组合 对比:根据文档横向对比vue2.0与vue3.0(三)

vue2.0与vue3.0 零碎部分 对比:根据文档横向对比vue2.0与vue3.0(四)