Vue2.x组件使用

311 阅读6分钟

组件是可复用的 Vue 实例,且带有一个名字

因为组件是可复用的 Vue 实例,所以它们与 new Vue 接收相同的选项,例如 datacomputedwatchmethods 以及生命周期钩子等。

Vue 组件的示例:

// 定义一个名为 button-counter 的新组件
Vue.component('button-counter', {
  data: function () {
    return {
      count: 0
    }
  },
  template: '<button v-on:click="count++">You clicked me {{ count }} times.</button>'
})

你可以将组件进行任意次数的复用:

<div id="components-demo">
  <button-counter></button-counter>
  <button-counter></button-counter>
  <button-counter></button-counter>
</div>

data必须是一个函数

由于组件是复用的,所有一个组件的 data 选项必须是一个函数,这样确保每次的复用的data都是一个新的实例对象。

data: () => {
  return {
    count: 0
  }
}

如果Vue的data不是一个函数的话,所有的组件共用一个data,只要一处发生了改变,该组件所有的复用都会发生改变。

prop传递数据

new Vue({
  el: '#blog-post-demo',
  data: {
    posts: [
      { id: 1, title: 'My journey with Vue' },
      { id: 2, title: 'Blogging with Vue' },
      { id: 3, title: 'Why Vue is so fun' }
    ]
  }
})

给博文组件传递一个标题,我们可以用一个 props 选项将其包含在该组件可接受的 prop 列表中:

Vue.component('blog-post', {
  props: ['title'], ['id'],
  template: `
    <h3>{{id}} - {{ title }}</h3>
    <button>
        Enlarge text
     </button>
    `
})

一个组件默认可以拥有任意数量的 prop,任何值都可以传递给任何 prop。在上述模板中,你会发现我们能够在组件实例中访问这个值,就像访问 data 中的值一样。

可以像这样把数据作为一个自定义 attribute 传递进来, 我们可以使用 v-bind 来动态传递 prop。

<blog-post
  v-for="(post, index) in posts"
  :key="index"
  :id="post.id"
  :title="post.title"
></blog-post>

监听子组件事件

点击Enlarge text按钮时,我们需要告诉父级组件放大所有博文的文本。幸好 Vue 实例提供了一个自定义事件的系统来解决这个问题。父级组件可以像处理 native DOM 事件一样通过 v-on 监听子组件实例的任意事件:

<blog-post
  ...
  v-on:enlarge-text="postFontSize += 0.1"
></blog-post>

子组件可以通过调用内建的方法$emit并传入事件名称来触发一个事件:

<button v-on:click="$emit('enlarge-text')">
  Enlarge text
</button>

有了这个 v-on:enlarge-text="postFontSize += 0.1" 监听器,父级组件就会接收该事件并更新 postFontSize 的值。

事件传参

有的时候用一个事件来抛出一个特定的值是非常有用的。例如我们可能想让 <blog-post> 组件决定它的文本要放大多少。这时可以使用 $emit 的第二个参数来提供这个值:

<button v-on:click="$emit('enlarge-text', 0.1)">
  Enlarge text
</button>

当在父级组件监听这个事件的时候,我们可以通过 $event 访问到被抛出的这个值:

<blog-post
  ...
  v-on:enlarge-text="postFontSize += $event"
></blog-post>

如果这个事件处理函数是一个方法:

<blog-post
  ...
  v-on:enlarge-text="onEnlargeText"
></blog-post>

那么这个值将会作为第一个参数传入这个方法:

methods: {
  onEnlargeText: function (enlargeAmount) {
    this.postFontSize += enlargeAmount
  }
}

订阅-发布者

自定义事件只能父子组件通讯,当组件存在其他关系时,这种方式将不便获取数据。这是就需要另外一种方式

配置:

import Vue from "vue"
export const EventBus = new Vue()

发布事件组件

// 引入配置
import { EventBus } from ".../EvenBus"
// 发布函数,携带参数   $emit
let num = parseInt(Math.random() * 10)
EventBus.$emit("newRandom", num)

订阅者

// 引入配置
import { EventBus } from ".../EvenBus"

订阅者通过 $on 订阅函数, 在回调函数中获取数据

EventBus.$on("newRandom", (random) => {
        this.randomNUm = random
      })

slot插槽

组件中的diy,能够使用组件并且能够自己修改组件中某部分的内容

设置组件中的slot

<template>
  <div>
    <div class="header">
      <h1>头部</h1>
      <slot name="header">header</slot>
    </div>
    <div class="main">
      <h1>内容</h1>
      <slot :article="article"></slot>
​
    </div>
    <div class="footer">
      <h1>底部</h1>
      <slot name="footer">footer</slot>
​
    </div>
  </div>
</template>
​
<script>
export default {
  data() {
    return {
      article: {
        title: "标题",
        content:  "内容"
      }
    }
  },
};
</script>

展示了不同的slot插槽方式

  • 默认插槽
  • 具名插槽

使用组件

    <Article>
        <!-- header的位置 -->
        <template #default="{ article }">
          <div>
            <h2>{{ article.title }}</h2>
            <h2>{{ article.content }}</h2>
          </div>
        </template>
        <template #footer>
          <div>2021年12月2日20:42:09</div>
        </template>
    </Article>

image-20211207233335934.png

通过代码及截图能够看到slot插槽的用法

  1. 当没有写替换插槽内容时,会默认显示原本slot标签的内容name="header"的slot
  2. 给template模板标签指定 name="footer" 缩写成 #footer,指定替换name是footer的slot标签的内容
  3. 因为插槽是有作用域的,当使用作为组件时,作用域是在父级中无法获取到自身的data中的数据,可以通过绑定自定义属性进行传输,传输过来是一个对象,对象的属性才是传输的值,因此可以通过解构赋值的形式获取到数据。

动态组件

在一个多标签的界面中使用 is attribute 来切换不同的组件:

<button @click="show = !show; com = show ? 'va' : 'vb'">hello</button>
<!-- 动态组件 -->
<component :is="com"></component>
<script>
export default {
  components: {
    'va' : Article,
    'vb': imageVue
  },
  data() {
    return {
      show: true,
      com: 'va'
    };
  },
};
</script>

当在这些组件之间切换的时候,你有时会想保持这些组件的状态,以避免反复重渲染导致的性能问题。

为了解决这个问题,我们可以用一个 <keep-alive> 元素将其动态组件包裹起来。

<!-- 失活的组件将会被缓存!-->
<keep-alive>
  <component v-bind:is="currentTabComponent"></component>
</keep-alive>

异步组件:传送门

过渡动画

Vue 提供了 transition 的封装组件,在下列情形中,可以给任何元素和组件添加进入/离开过渡

  • 条件渲染 (使用 v-if)
  • 条件展示 (使用 v-show)
  • 动态组件
  • 组件根节点

Vue 在插入、更新或者移除 DOM 时,提供多种不同方式的应用过渡效果。包括以下工具:

  • 在 CSS 过渡和动画中自动应用 class
  • 可以配合使用第三方 CSS 动画库,如 Animate.css
  • 在过渡钩子函数中使用 JavaScript 直接操作 DOM
  • 可以配合使用第三方 JavaScript 动画库,如 Velocity.js

示例:动态组件切换

<template>
  <div id="app">
    <button @click="show = !show; com = show ? 'va' : 'vb'">hello</button>
    <transition name="fade" mode="out-in">
      <!-- 动态组件 -->
      <component :is="com"></component>
    </transition>
  </div>
</template>
<style>
 // 组件进入时
.fade-enter-active
{
  animation: identifier ease-in forwards 1s;
}
 // 组件离开时
.fade-leave-active  {
  animation: identifier ease-in forwards 1s reverse;
}
​
​
@keyframes identifier {
  from {
    transform: translateX(100%);
  }
  to {
    transform: translateX(0);
  }
}
</style>

当切换组件时,能够看到组件先移出,后面另一个紧接着移入

讲解

过渡的类名

如果你使用一个没有名字的 <transition>,则 v- 是这些类名的默认前缀。如果你使用了 <transition name="my-transition">,那么 v-enter 会替换为 my-transition-enter

在进入/离开的过渡中,会有 6 个 class 切换。

  1. v-enter:定义进入过渡的开始状态。在元素被插入之前生效,在元素被插入之后的下一帧移除。
  2. v-enter-active:定义进入过渡生效时的状态。在整个进入过渡的阶段中应用,在元素被插入之前生效,在过渡/动画完成之后移除。这个类可以被用来定义进入过渡的过程时间,延迟和曲线函数。
  3. v-enter-to2.1.8 版及以上定义进入过渡的结束状态。在元素被插入之后下一帧生效 (与此同时 v-enter 被移除),在过渡/动画完成之后移除。
  4. v-leave:定义离开过渡的开始状态。在离开过渡被触发时立刻生效,下一帧被移除。
  5. v-leave-active:定义离开过渡生效时的状态。在整个离开过渡的阶段中应用,在离开过渡被触发时立刻生效,在过渡/动画完成之后移除。这个类可以被用来定义离开过渡的过程时间,延迟和曲线函数。
  6. v-leave-to2.1.8 版及以上定义离开过渡的结束状态。在离开过渡被触发之后下一帧生效 (与此同时 v-leave 被删除),在过渡/动画完成之后移除。

多元素过渡

当有相同标签名的元素切换时,需要通过 key attribute 设置唯一的值来标记以让 Vue 区分它们,否则 Vue 为了效率只会替换相同标签内部的内容。

<transition>
  <button v-if="isEditing" key="save">
    Save
  </button>
  <button v-else key="edit">
    Edit
  </button>
</transition>

过渡模式

生效的进入和离开的过渡不能满足所有要求,所以 Vue 提供了过渡模式

  • in-out:新元素先进行过渡,完成之后当前元素过渡离开。
  • out-in:当前元素先进行过渡,完成之后新元素过渡进入。