Skip to content

组件复用

介绍Vue3.0中组件复用技术,所有样例可在GitHub仓库中找到

渲染控制

条件渲染v-if实例

v-if

  • v-if指令根据表达式的真假值来有条件地渲染元素
    <div v-if="type === 'A'">
        A
    </div>
    <div v-else-if="type === 'B'">
        B
    </div>
    <div v-else-if="type === 'C'">
        C
    </div>
    <div v-else>
        Not A/B/C
    </div>
    

循环渲染v-for实例

v-for

  • v-for基于源数据多次渲染元素或模板块,必须使用特定语法alias in expression
    <li v-for="todo in todos">
        {{ todo.text }}
    </li>
    

数据传递

v-bind实例

v-bind

  • v-bind可以地绑定一个或多个attribute,或绑定一个组件prop到表达式,可以通过:进行缩写,详情参考文档
  • 以下是常见的v-bind例子:
    <!-- 绑定 attribute -->
    <img v-bind:src="imageSrc" />
    
    <!-- 动态 attribute 名 -->
    <button v-bind:[key]="value"></button>
    
    <!-- 缩写 -->
    <img :src="imageSrc" />
    
    <!-- 动态 attribute 名缩写 -->
    <button :[key]="value"></button>
    
    <!-- 内联字符串拼接 -->
    <img :src="'/path/to/images/' + fileName" />
    
    <!-- class 绑定 -->
    <div :class="{ red: isRed }"></div>
    <div :class="[classA, classB]"></div>
    <div :class="[classA, { classB: isB, classC: isC }]"></div>
    
    <!-- style 绑定 -->
    <div :style="{ fontSize: size + 'px' }"></div>
    <div :style="[styleObjectA, styleObjectB]"></div>
    
    <!-- 绑定一个全是 attribute 的对象 -->
    <div v-bind="{ id: someProp, 'other-attr': otherProp }"></div>
    
    <!-- prop 绑定。"prop" 必须在 my-component 声明 -->
    <my-component :prop="someThing"></my-component>
    
    <!-- 将父组件的 props 一起传给子组件 -->
    <child-component v-bind="$props"></child-component>
    

props实例

  • 我们可以在组件内定义props,用以接受父组件通过v-bind传入的数据,从而更好地实现组件的复用,所有的prop都使得其父子 prop 之间形成了一个单向下行绑定,详细例子可以参考官方文档

v-model实例

  • 在Vue3中,自定义组件上的v-model相当于传递了modelValueprop并接收抛出的update:modelValue事件
    • 下面的例子中,CustomInput会接受input事件,向父组件抛出update:modelValue事件,并附加input内容$event.target.value,其中$event是原始的DOM事件。这样HTML代码就可以通过<custom-input v-model="searchText"></custom-input>searchTextinput的内容及事件进行绑定。
      const CustomInput = {
          props: ['modelValue'],
          emits: ['update:modelValue'],
          template:`
              <input
                  :value="modelValue"
                  @input="$emit('update:modelValue', $event.target.value)"
              />
          `
      }
      
  • v-model实例展示了v-model绑定不同input组件的方式

事件传送

v-on实例

  • v-on指令用于绑定事件监听器,绑定的监听器可以接受原生的DOM事件$event作为参数,并通过事件修饰符控制触发事件行为
    <!-- 阻止单击事件继续冒泡 -->
    <button @click.stop="say($event, 'button_clicked')">Click_With_Stop</button>
    

$emit实例

通过v-bind和props,父组件可以将数据传递到子组件;同样,通过v-on和emits,子组件可以抛出事件到父组件

  • JS代码
    • this.$emit("increment-count")抛出了increment-count事件,可以通过v-on:increment-count绑定事件监听器
      const ChildComponent = {
      emits: ['increment-count'],
      template: `
          <div>
              <button @click='this.$emit("increment-count")'>click me</button>
          </div>
      `
      }
      

数据监控

computed实例

我们可以用computed创建一个跟随响应性数据变化的对象。Vue可以通过两种方式配置computed对象,computed接受一个getter函数,并根据getter的返回值返回一个不可变的响应式ref对象:

watch实例

我们可以用watch侦听包含了datacomputedproperty的变化,并调用相应的回调函数。Vue提供了多种方法创建watch对象:

内容分发

Vue通过插槽分发内容。

插槽内容实例

通过<todo-button>{{ text }}</todo-button>可以向TodoButton分发父组件的text内容,以替换子组件默认slot的内容。插槽可以访问与模板其余部分相同的实例property(即相同的“作用域”),但不能访问<todo-button>组件的作用域。例如,例子中尝试访问action将不起作用:

  • HTML代码

    <div id="app">
       <!-- item is defined in root component, show: Delete First Item -->
       <todo-button>Delete {{ item }}</todo-button>
       <!-- use default slot, show: Add an item  -->
       <todo-button></todo-button>
       <!-- action will be undefined here, show: an item -->
       <todo-button action="Delete">{{ action }} an item</todo-button>
    </div>
    

  • JS代码

    const TodoButton = {
       props: {
          action: {
             type: String,
             default: 'Add'
          }
       },
       template: `
          <button><slot>{{ action }} an item</slot></button>
       `
    }
    

具名插槽实例

  • 在向具名插槽提供内容的时候,我们可以在一个<template>元素上使用v-slot指令,并以v-slot的参数的形式提供其名称
    <base-layout>
      <template v-slot:header>
        <h1>Here might be a page title</h1>
      </template>
    
      <template v-slot:default>
        <p>A paragraph for the main content.</p>
        <p>And another one.</p>
      </template>
    
      <template v-slot:footer>
        <p>Here's some contact info</p>
      </template>
    </base-layout>
    

作用域插槽实例

要使slot的属性在父级提供的插槽内容上可用,我们可以添加一个<slot>元素并将其作为一个attribute绑定。

  • JS代码

    • TodoList组件通过slot属性暴露给父级组件
      const TodoList = {
          data() {
              return {
                  items: ['Feed a cat', 'Buy milk']
              }
          },
          template: `
              <ul>
                  <li v-for="(item, index) in items">
                      <slot :item="item" :index="index">{{item}}</slot>
                  </li>
              </ul>
          `
      }
      
  • HTML代码

    • TodoList的父级组件通过v-slot:default="slotProps"可以拿到slot所有暴露的属性
      <todo-list>
          <template v-slot:default="slotProps">
              <span style="color:blue;">Change in parent component: {{ slotProps.item }}</span>
          </template>
      </todo-list>