如何使用 Vue.js 构建模态组件

介绍

模块是一种用户体验的惯例,旨在将用户的注意力集中在他们需要阅读或互动的内容上,这些内容往往以直接进入用户视野的内容的小块的形式,某种背景或掩盖或隐藏页面上的其他内容。

在本文中,您将学习如何使用 Vue.js 中的过渡和插槽创建可重复使用的模式组件。

前提条件

要完成本教程,您将需要:

步骤1 - 设置项目

您可以使用 @vue/cli创建新的 Vue.js 项目。

在您的终端窗口中,使用以下命令:

1npx @vue/cli create --default vue-modal-component-example

这将使用默认配置来创建 Vue.js 项目。

导航到新创建的项目目录:

1cd vue-modal-component-example

启动项目以确保没有错误。

1npm run serve

如果您访问本地应用程序(通常在localhost:8080)在您的 Web 浏览器中,您将看到一个欢迎来到您的 Vue.js 应用程序的消息。

有了这个支架设置,您可以开始在模特组件上工作。

步骤 2 – 创建模块组件

首先,在项目目录中,在src/components下创建一个新的Modal.vue文件。

您将需要一个div为背景阴影,一个div作为模式框,以及一些元素来定义其结构:

 1[label src/components/Modal.vue]
 2<template>
 3  <div class="modal-backdrop">
 4    <div class="modal">
 5      <slot name="header">
 6      </slot>
 7
 8      <slot name="body">
 9      </slot>
10
11      <slot name="footer">
12      </slot>
13    </div>
14  </div>
15</template>

您可以使用代理来提供头部,身体和脚部,但使用插槽将允许更多的灵活性。

使用 插槽允许您重复使用相同的模式与不同类型的身体内容。

您可以使用模式来显示消息,但您可能希望与表单重复使用相同模式来提交请求。

虽然支持程序通常足以构建一个组件,但通过支持程序提供HTML将要求我们使用v-html来渲染它 - 这可能会导致XSS攻击(https://vuejs.org/v2/api/#v-html)。

在这里,您正在使用命名的插槽,允许在同一组件中使用多个插槽。

当您定义一个命名的插槽时,您用该名称识别的任何东西都将被渲染,而不是原始插槽。 想象它作为一个位置持有者。

由于提供的内容取代了<slot>标签,为了保证部分具有您想要的类,您需要包装每个插槽。

让我们为插槽,包装元素和初始CSS设置一些默认设置,使其看起来像一个基本的模式。

在模板上方,添加组件名称和关闭模式的方法:

 1[label src/components/Modal.vue]
 2<script>
 3  export default {
 4    name: 'Modal',
 5    methods: {
 6      close() {
 7        this.$emit('close');
 8      },
 9    },
10  };
11</script>

然后,修改模板以包装插槽,提供默认值,并显示关闭模式的按钮:

 1[label src/components/Modal.vue]
 2<template>
 3  <div class="modal-backdrop">
 4    <div class="modal">
 5      <header class="modal-header">
 6        <slot name="header">
 7          This is the default title!
 8        </slot>
 9        <button
10          type="button"
11          class="btn-close"
12          @click="close"
13        >
14          x
15        </button>
16      </header>
17
18      <section class="modal-body">
19        <slot name="body">
20          This is the default body!
21        </slot>
22       </section>
23
24      <footer class="modal-footer">
25        <slot name="footer">
26          This is the default footer!
27        </slot>
28        <button
29          type="button"
30          class="btn-green"
31          @click="close"
32        >
33          Close Modal
34        </button>
35      </footer>
36    </div>
37  </div>
38</template>

接下来,在模板下方,为组件添加样式:

 1[label src/components/Modal.vue]
 2<style>
 3  .modal-backdrop {
 4    position: fixed;
 5    top: 0;
 6    bottom: 0;
 7    left: 0;
 8    right: 0;
 9    background-color: rgba(0, 0, 0, 0.3);
10    display: flex;
11    justify-content: center;
12    align-items: center;
13  }
14
15  .modal {
16    background: #FFFFFF;
17    box-shadow: 2px 2px 20px 1px;
18    overflow-x: auto;
19    display: flex;
20    flex-direction: column;
21  }
22
23  .modal-header,
24  .modal-footer {
25    padding: 15px;
26    display: flex;
27  }
28
29  .modal-header {
30    position: relative;
31    border-bottom: 1px solid #eeeeee;
32    color: #4AAE9B;
33    justify-content: space-between;
34  }
35
36  .modal-footer {
37    border-top: 1px solid #eeeeee;
38    flex-direction: column;
39    justify-content: flex-end;
40  }
41
42  .modal-body {
43    position: relative;
44    padding: 20px 10px;
45  }
46
47  .btn-close {
48    position: absolute;
49    top: 0;
50    right: 0;
51    border: none;
52    font-size: 20px;
53    padding: 10px;
54    cursor: pointer;
55    font-weight: bold;
56    color: #4AAE9B;
57    background: transparent;
58  }
59
60  .btn-green {
61    color: white;
62    background: #4AAE9B;
63    border: 1px solid #4AAE9B;
64    border-radius: 2px;
65  }
66</style>

所有这些组件都组合在一起,完成你的模特组件,你可以在App.vue中导入这个新组件,并在行动中观察它。

更改App.vue以更改模板并添加showModal,closeModalisModalVisible:

 1[label src/App.vue]
 2<template>
 3  <div id="app">
 4    <button
 5      type="button"
 6      class="btn"
 7      @click="showModal"
 8    >
 9      Open Modal!
10    </button>
11
12    <Modal
13      v-show="isModalVisible"
14      @close="closeModal"
15    />
16  </div>
17</template>
18
19<script>
20  import modal from './components/Modal.vue';
21
22  export default {
23    name: 'App',
24    components: {
25      Modal,
26    },
27    data() {
28      return {
29        isModalVisible: false,
30      };
31    },
32    methods: {
33      showModal() {
34        this.isModalVisible = true;
35      },
36      closeModal() {
37        this.isModalVisible = false;
38      }
39    }
40  };
41</script>

此代码将导入Modal组件,并显示一个 Open Modal按钮以与之交互。

<$>[注] 注: 在您的App.js文件中,您可以选择引用插槽并取代默认内容:

 1[label src/App.js]
 2<Modal
 3  v-show="isModalVisible"
 4  @close="closeModal"
 5>
 6  <template v-slot:header>
 7    This is a new modal header.
 8  </template>
 9
10  <template v-slot:body>
11    This is a new modal body.
12  </template>
13
14  <template v-slot:footer>
15    This is a new modal footer.
16  </template>
17</Modal>

美元

查看您的Web浏览器中的应用程序,并通过打开和关闭它来验证modal的行为如预期。

步骤 3 – 添加过渡

您可以通过使用过渡来使它看起来更顺利地打开和关闭。

Vue 提供一个名为过渡的包装组件,允许您添加输入和离开的过渡组件. 这个包装组件可以用于任何元素或组件,它们允许 CSS 和 JavaScript 锁定。

每次插入或删除一个过渡的组件或元素,Vue 都会检查该元素是否有 CSS 过渡,并会在适当的时间添加或删除它们。

当一个元素被添加或删除时, 六类应用于输入和输出过渡,每个过渡将以过渡名称为前缀。

首先,让我们先将过渡包装组件添加到模式中:

 1[label src/components/Modal.vue]
 2<template>
 3  <transition name="modal-fade">
 4    <div class="modal-backdrop">
 5      <div class="modal">
 6        ...
 7      </div>
 8    </div>
 9  </transition>
10</template>

现在,让我们通过使用应用的类来添加一个过渡,以便透明度缓慢消失:

 1[label src/components/Modal.vue]
 2<style>
 3  ...
 4
 5  .modal-fade-enter,
 6  .modal-fade-leave-to {
 7    opacity: 0;
 8  }
 9
10  .modal-fade-enter-active,
11  .modal-fade-leave-active {
12    transition: opacity .5s ease;
13  }
14</style>

最初,模式将显示隐藏的不透明度属性值为0

当模式打开时,它将应用.modal-fade-enter-active类,并在ease动画时刻函数中应用opacity属性的CSS过渡在.5秒内。

当离开模特时,它会反过来。将应用`模特模特模特模特模特模特模特模特模特模特模特模特模特模特模特模特模特模特模特模特模特模特模特模特模特模特模特模特模特模特模特模特模特模特模特模特模特模特模特模特模特模特模特模特模特模特模特模特模特模特模特模特模特模特模特模特模特模特模特模特模特模特模特模特模特模特模特模特模特

查看您的Web浏览器中的应用程序,并验证模式在进出。

步骤 4 – 增加可用性

你將要用 ARIA 屬性來使你的模式部件可用。

添加`role="dialog``将有助于辅助软件将组件识别为与其他用户界面分离的应用程序对话。

您还需要用aria-labelledbyaria-describedby属性正确标记它。

并将aria-label属性添加到关闭按钮中。

 1[label src/components/Modal.vue]
 2<template>
 3  <transition name="modal-fade">
 4    <div class="modal-backdrop">
 5      <div class="modal"
 6        role="dialog"
 7        aria-labelledby="modalTitle"
 8        aria-describedby="modalDescription"
 9      >
10        <header
11          class="modal-header"
12          id="modalTitle"
13        >
14          <slot name="header">
15            This is the default title!
16          </slot>
17          <button
18            type="button"
19            class="btn-close"
20            @click="close"
21            aria-label="Close modal"
22          >
23            x
24          </button>
25        </header>
26
27        <section
28          class="modal-body"
29          id="modalDescription"
30        >
31          <slot name="body">
32            This is the default body!
33          </slot>
34        </section>
35
36        <footer class="modal-footer">
37          <slot name="footer">
38            This is the default footer!
39          </slot>
40          <button
41            type="button"
42            class="btn-green"
43            @click="close"
44            aria-label="Close modal"
45          >
46            Close Modal
47          </button>
48        </footer>
49      </div>
50    </div>
51  </transition>
52</template>

模式组件的最终版本现在应该看起来像:

  1[label src/components/Modal.vue]
  2<script>
  3  export default {
  4    name: 'Modal',
  5    methods: {
  6      close() {
  7        this.$emit('close');
  8      },
  9    },
 10  };
 11</script>
 12
 13<template>
 14  <transition name="modal-fade">
 15    <div class="modal-backdrop">
 16      <div class="modal"
 17        role="dialog"
 18        aria-labelledby="modalTitle"
 19        aria-describedby="modalDescription"
 20      >
 21        <header
 22          class="modal-header"
 23          id="modalTitle"
 24        >
 25          <slot name="header">
 26            This is the default tile!
 27          </slot>
 28          <button
 29            type="button"
 30            class="btn-close"
 31            @click="close"
 32            aria-label="Close modal"
 33          >
 34            x
 35          </button>
 36        </header>
 37
 38        <section
 39          class="modal-body"
 40          id="modalDescription"
 41        >
 42          <slot name="body">
 43            This is the default body!
 44          </slot>
 45        </section>
 46
 47        <footer class="modal-footer">
 48          <slot name="footer">
 49            This is the default footer!
 50          </slot>
 51          <button
 52            type="button"
 53            class="btn-green"
 54            @click="close"
 55            aria-label="Close modal"
 56          >
 57            Close me!
 58          </button>
 59        </footer>
 60      </div>
 61    </div>
 62  </transition>
 63</template>
 64
 65<style>
 66  .modal-backdrop {
 67    position: fixed;
 68    top: 0;
 69    bottom: 0;
 70    left: 0;
 71    right: 0;
 72    background-color: rgba(0, 0, 0, 0.3);
 73    display: flex;
 74    justify-content: center;
 75    align-items: center;
 76  }
 77
 78  .modal {
 79    background: #FFFFFF;
 80    box-shadow: 2px 2px 20px 1px;
 81    overflow-x: auto;
 82    display: flex;
 83    flex-direction: column;
 84  }
 85
 86  .modal-header,
 87  .modal-footer {
 88    padding: 15px;
 89    display: flex;
 90  }
 91
 92  .modal-header {
 93    position: relative;
 94    border-bottom: 1px solid #eeeeee;
 95    color: #4AAE9B;
 96    justify-content: space-between;
 97  }
 98
 99  .modal-footer {
100    border-top: 1px solid #eeeeee;
101    flex-direction: column;
102  }
103
104  .modal-body {
105    position: relative;
106    padding: 20px 10px;
107  }
108
109  .btn-close {
110    position: absolute;
111    top: 0;
112    right: 0;
113    border: none;
114    font-size: 20px;
115    padding: 10px;
116    cursor: pointer;
117    font-weight: bold;
118    color: #4AAE9B;
119    background: transparent;
120  }
121
122  .btn-green {
123    color: white;
124    background: #4AAE9B;
125    border: 1px solid #4AAE9B;
126    border-radius: 2px;
127  }
128
129  .modal-fade-enter,
130  .modal-fade-leave-to {
131    opacity: 0;
132  }
133
134  .modal-fade-enter-active,
135  .modal-fade-leave-active {
136    transition: opacity .5s ease;
137  }
138</style>

这是具有可访问性和过渡性的模式组成部分的基础。

结论

在本文中,您使用 Vue.js 构建了一个模式组件。

您试验了插槽,以便您的组件可重复使用,过渡,以创建更好的用户体验,以及ARIA属性,以使您的组件更易于访问。

如果您想了解有关 Vue.js 的更多信息,请参阅 我们的 Vue.js 主题页面以获取练习和编程项目。

Published At
Categories with 技术
comments powered by Disqus