Vue 3.0教程(for beginner):Vue Cli(下篇)

196 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第6天,点击查看活动详情

Props

在上一教程中,我们创建了一个Modal.vue组件,组件里面通过硬编码的方式写死了内容,那么我们如何在外部给组件传递参数呢?

<template>
  <div class="backdrop">
    <div class="modal">
      <h1>modal title</h1>
      <p>modal content</p>
    </div>
  </div>
</template>

<script>
export default {
  name: 'Modal',
}
</script>

props,定义从父组件到自组件的数据流。

<template>
  <div class="backdrop">
    <div class="modal">
      <h1>{{ modalTitle }}</h1>
      <p>{{ content }}</p>
    </div>
  </div>
</template>

<script>
export default {
  name: 'Modal',
  props: ['modalTitle', 'content'],
}
</script>

在Modal组件中我们定义了modalTitlecontent两个参数,父组件中引用该组件时,传递入参:

<template>
  <h1>{{ title }}</h1>
  <Modal :modal-title="modalTitle" :content="content" />
</template>

<script>
import Modal from './components/Modal.vue'
export default {
  name: 'App',
  components: { Modal },
  data() {
    return {
      title: 'Hello, Vue App :)',
      modalTitle: '模态弹窗标题',
      content: '模态弹窗内容,writed by lostvitta.',
    }
  },
}
</script>

image.png

我们注意到,Modal组件定义的modalTitle是驼峰的书写格式,而我们在传递参数时用的是kebab-case格式,如果我们想要继续使用驼峰格式,也是可以的。

自定义事件

前面章节我们实现了一个模态弹窗组件,本章节我们通过vue的自定义事件机制实现模态窗的打开与关闭功能。

<template>
  <div class="backdrop" @click="closeModal">
    <div class="modal">
      <h1>{{ modalTitle }}</h1>
      <p>{{ content }}</p>
    </div>
  </div>
</template>

<script>
export default {
  name: 'Modal',
  props: ['modalTitle', 'content'],
  emits: ['close'],
  methods: {
    closeModal() {
      this.$emit('close')
    },
  },
}
</script>

我们通过emits定义了组件支持的自定义事件,这里定义了一个close事件。

<template>
  <h1>{{ title }}</h1>
  <div>
    <button @click="toggleModal">打开</button>
  </div>
  <Modal
    v-if="showModal"
    :modalTitle="modalTitle"
    :content="content"
    @close="toggleModal"
  />
</template>

<script>
import Modal from './components/Modal.vue'
export default {
  name: 'App',
  components: { Modal },
  data() {
    return {
      title: 'Hello, Vue App :)',
      modalTitle: '模态弹窗标题',
      content: '模态弹窗内容,writed by lostvitta.',
      showModal: false,
    }
  },
  methods: {
    toggleModal() {
      this.showModal = !this.showModal
    },
  },
}
</script>

我们在父组件中实现了toggleModal方法用来打开会关闭模态窗,并作为@close事件的值传递给了子组件。如此我们可以看到,自定义事件的机制可以使子组件调用父组件中的方法,从而让子组件有了修改父组件数据的能力。

emits-01.gif

事件修饰符

在前文我们实现的关闭模态窗功能中,我们点击遮罩部分正常关闭了模态窗,但我们点击模态窗内容的时候也关闭了,这显然不是我们想要的功能。在我们实现的dom结构中,遮罩所在的div是作为根节点存在的,其子节点的点击事件都会冒泡在这个div节点上,我们要如何来阻止呢?

<template>
  <div class="backdrop" @click.self="closeModal">
    <div class="modal">
      <h1>{{ modalTitle }}</h1>
      <p>{{ content }}</p>
    </div>
  </div>
</template>

在组件的@click事件中使用self事件修饰符,表示仅党事件发生在当前节点时才触发绑定事件。

emits-02.gif

插槽Slots

我们实现的Modal组件,组件内容是通过传递字符串参数实现的自定义,如果我们想传递更复杂的内容如html,甚至是一个自定义的vue组件,是无法做到的。而这,Slots可以帮助我们:

<template>
  <div class="backdrop" @click.self="closeModal">
    <div class="modal">
      <slot>我是默认内容</slot>
      <div class="actions">
        <slot name="links"></slot>
      </div>
    </div>
  </div>
</template>

<script>
export default {
  name: 'Modal',
  emits: ['close'],
  methods: {
    closeModal() {
      this.$emit('close')
    },
  },
}
</script>

我们删除了Modal组件中的html内容,换为slot标签(slot是vue的自定义组件),其中一个不具名,另一个具名为links

<template>
  <h1>{{ title }}</h1>
  <div>
    <button @click="toggleModal">打开</button>
  </div>
  <Modal v-if="showModal" @close="toggleModal">
    <h1>模态弹窗标题</h1>
    <p>模态弹窗内容,writed by lostvitta.</p>
    <template v-slot:links>
      <a href="">登陆</a>
      <a href="">注册</a>
    </template>
  </Modal>
</template>

父组件中引用Modal组件时,采用了双标签闭合的方式,里面自定义一些内容。其中一部分没有用template标签包裹,会被填充到Modal组件的不具名slot内部,另一部分使用template包裹并定义了v-slot:links属性,这与组件内部的具名links对应。

image.png

而当我们什么都不传时,则会渲染默认内容:

<Modal v-if="showModal" @close="toggleModal"> </Modal>

image.png

传送门Teleport

我们的Modal是挂载在div#app上的,如果我们希望挂载在#app之外的div上呢?比如,在public/index.html文件中:

<div id="app"></div>
<div id="modal"></div>

在我们的App.vue组件中使用teleport,定义to属性关联div#modal

<template>
  <h1>{{ title }}</h1>
  <div>
    <button @click="toggleModal">打开</button>
  </div>
  <teleport to="#modal">
    <Modal v-if="showModal" @close="toggleModal">
      <h1>模态弹窗标题</h1>
      <p>模态弹窗内容,writed by lostvitta.</p>
      <template v-slot:links>
        <a href="">登陆</a>
        <a href="">注册</a>
      </template>
    </Modal>
  </teleport>
</template>

image.png 如此,我们便轻松地将组件挂载在任意我们想挂载的地方啦!

未完待续Vue 3.0教程(for beginner):反应计时器游戏