六、创建更好的用户界面

过渡和动画是在我们的应用中创建更好的用户体验的好方法。由于有这么多不同的选项和用例,如果使用不足或过度,它们可能会影响应用的效果。我们将在本章中进一步研究这个概念。

我们还将查看第三方【验证表】。这将允许我们创建与应用大小相适应的表单。我们还可以根据表单状态更改 UI,并显示有用的验证消息以帮助用户。

最后,我们将看看如何使用render函数和 JSX 来使用 Vue 构建用户界面。虽然这并非适用于所有场景,但有时您希望在模板中充分利用 JavaScript,并使用功能组件模型创建智能/表示组件。

在本章结束时,您将拥有:

  • 了解 CSS 动画
  • 创建自己的 CSS 动画
  • 用于Animate.css创建交互 UI,工作量小
  • 调查并创建了自己的 Vue 转换
  • 利用Vuelidate在 Vue 内验证表单
  • 使用render功能替代模板驱动的 UI
  • 使用 JSX 编写与 React 类似的 UI

让我们从理解为什么我们应该关心项目中的动画和过渡开始。

动画

动画可用于将焦点吸引到特定的 UI 元素,并通过将其带入生活来改善用户的整体体验。当没有清晰的开始状态和结束状态时,应使用动画。动画可以设置为自动播放,也可以由用户交互触发。

CSS 动画

CSS 动画不仅是一个强大的工具,而且它们也很容易维护,只需要很少的知识就可以在项目中使用它们。

将它们添加到界面可以是捕获用户注意力的直观方法,也可以轻松地将用户指向特定元素。动画可以定制,使其成为各种项目中大量用例的理想选择。

在深入研究 Vue 过渡和其他动画可能性之前,我们应该了解如何制作基本的 CSS3 动画。让我们创建一个简单的项目来更详细地了解这一点:

# Create a new Vue project
$ vue init webpack-simple vue-css-animations

# Navigate to directory
$ cd vue-css-animations

# Install dependencies
$ npm install

# Run application
$ npm run dev

App.vue内部,我们可以先创建以下样式:

<style>
button {
 background-color: transparent;
 padding: 5px;
 border: 1px solid black;
}

h1 {
 opacity: 0;
}

@keyframes fade {
 from { opacity: 0; }
 to { opacity: 1; }
}

.animated {
 animation: fade 1s;
 opacity: 1;
}
</style>

正如你所看到的,没有什么太不寻常的事情。我们用名为fade@keyframes声明 CSS 动画,本质上给 CSS 两种状态,我们希望元素处于-opacity: 1opacity: 0。它没有说明这些关键帧重复了多长时间或是否重复;这些都是在animated课上完成的。每当我们将类添加到元素时,我们都会为1s 应用fade关键帧;同时,我们正在添加opacity: 1以确保它不会在动画结束后消失。

我们可以利用v-bind:class根据toggle的值动态添加/删除该类,将其组合在一起:

<template>
 <div id="app">
  <h1 v-bind:class="{ animated: toggle }">I fade in!</h1>
  <button @click="toggle = !toggle">Toggle Heading</button>
 </div> 
</template>

<script>
export default {
 data () {
  return {
   toggle: false
  }
 }
}
</script>

凉的我们现在可以根据Boolean值淡入航向。但如果我们能做得更好呢?在这种特殊情况下,我们本可以通过过渡来实现类似的结果。在更详细地研究转换之前,让我们先看看在项目中使用 CSS 动画的其他方法。

动画

Animate.css是在项目中轻松实现不同类型动画的好方法。这是一个由 Daniel Eden(创建的开源 CSS 库 https://daneden.me/ ),它让我们可以访问“即插即用”CSS 动画。

在将其添加到任何项目之前,请前往https://daneden.github.io/animate.css/ 并预览不同的动画样式。有许多不同的动画可供选择,每种动画都提供不同的默认动画。这些可以进一步定制,我们将在本节稍后讨论更多。

通过在终端中运行以下命令,继续创建游乐场项目:

 Create a new Vue project
$ vue init webpack-simple vue-animate-css

# Navigate to directory
$ cd vue-animate-css

# Install dependencies
$ npm install

# Run application
$ npm run dev

项目设置完成后,继续在您选择的编辑器中打开它,然后转到index.html文件。在<head>标记内,添加以下样式表:

<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/animate.css/3.5.2/animate.min.css">

这是Animate.css处理项目所需的样式表参考。

使用 Animate.css

现在我们在项目中有了Animate.css,我们可以将App.vue改为template,如下所示:

<template>
 <h1 class="animated fadeIn">Hello Vue!</h1>
</template>

在添加任何动画之前,我们首先需要添加动画类。接下来,我们可以从Animate.css库中选择任何动画;我们选择fadeIn作为这个例子。然后可以将其切换到其他动画,如bounceInLeftshakerubberBand等等!

我们可以以前面的示例为例,将其转换为基于布尔值的绑定类值,但转换可能更令人兴奋。

过渡

转换是从一个特定状态开始,然后转换到另一个状态,并在其间插入值。过渡不能在动画中包含多个步骤。想象一对窗帘从打开到关闭:第一种状态是打开位置,而第二种状态是关闭位置。

Vue 有自己的处理转换的标签,称为<transition><transition-group>。这些标签是可定制的,可以轻松地与 JavaScript 和 CSS 一起使用。转换工作不一定需要transition标记,因为您只需将状态变量绑定到可见属性,但是标记通常提供更多的控制和可能更好的结果。

让我们以之前的toggle为例,创建一个使用transition的版本:

<template>
 <div id="app">
  <transition name="fadeIn"
  enter-active-class="animated fadeIn"
  leave-active-class="animated fadeOut">
   <h1 v-if="toggle">I fade in and out!</h1>
  </transition>
  <button @click="toggle = !toggle">Toggle Heading</button>
 </div> 
</template>

<script>
export default {
 data () {
  return {
   toggle: false
  }
 }
}
</script>

让我们更详细地看一下运动部件。

我们将元素包围在一个<transition>标记中,每当<h1>进入 DOM 时,该标记将应用于animated fadeInenter-active-class。这由v-if指令触发,因为toggle变量最初设置为false。单击按钮切换布尔值,触发转换并应用适当的 CSS 类。

过渡态

每个进入/离开变换最多应用六个类,这些类由进入场景、进入场景和离开场景时的变换组成。第一套(v-enter-*)为先入后出的过渡,第二套(v-leave-*)为先入后出的结束过渡:

| 名称 | 说明 | | v-enter | 这是 enter 的最开始状态。插入图元一帧后,将删除该图元。 | | v-enter-active | enter-activeenter的活动状态。它在整个活动阶段处于活动状态,并且仅在过渡或动画结束后才被删除。此状态还管理其他指令,如延迟、持续时间等。 | | v-enter-to | 这是 enter 的最后一个状态,在插入元素后添加了一帧,这与删除v-enter的时间相同。过渡/动画结束后,将删除Enter-to。 | | v-leave | 这是休假的开始状态。触发离开转换后,在一帧后移除。 | | v-leave-active | leave-activeleave的活动状态。它在离开阶段的整个过程中都处于活动状态,并且仅在过渡或动画结束后才被删除。 | | v-leave-to | 请假的最后一个状态,在触发请假后增加一帧,这与v-leave被删除的时间相同。当过渡/动画结束时,Leave-to被移除。 |

每个enterleave转换都有一个前缀,表中显示为v的默认值,因为转换本身没有名称。在将 enter 或 leave 转换添加到项目中时,理想情况下应该应用适当的命名约定作为唯一标识符。如果您计划在一个项目中使用多个转换,并且可以通过简单的分配操作来完成,则这会有所帮助:

<transition name="my-transition">

表单验证

在整本书中,我们研究了各种不同的方式,我们可以通过v-model之类的方式来捕获用户输入。我们将使用名为Vuelidate的第三方库根据特定规则集执行模型验证。让我们通过在终端中运行以下命令来创建游乐场项目:

# Create a new Vue project
$ vue init webpack-simple vue-validation

# Navigate to directory
$ cd vue-validation

# Install dependencies
$ npm install

# Install Vuelidate
$ npm install vuelidate

# Run application
$ npm run dev

什么是 Vuelidate?

Vuelidate是一个开源的轻量级库,帮助我们使用各种验证上下文执行模型验证。验证可以在功能上进行组合,它还可以与其他库(如MomentVuex等)很好地配合使用。由于我们已经在我们的项目中使用npm install vuelidate安装了它,我们现在需要将其注册为main.js中的插件:

import Vue from 'vue';
import Vuelidate from 'vuelidate';
import App from './App.vue';

Vue.use(Vuelidate);

new Vue({
  el: '#app',
  validations: {},
  render: h => h(App),
});

将空的 validations 对象添加到我们的主 Vue 实例会在整个项目中引导 Vuelidate 的$v。这样,我们就可以使用$v对象在 Vue 实例中跨所有组件获取表单当前状态的信息。

使用 Vuelidate

让我们创建一个基本表单,允许我们输入一个firstNamelastNameemailpassword。这将允许我们使用Vuelidate添加验证规则,并在屏幕上显示它们:

<template>
  <div>
    <form class="form" @submit.prevent="onSubmit">
      <div class="input">
        <label for="email">Email</label>
        <input 
        type="email" 
        id="email" 
        v-model.trim="email">
      </div>
      <div class="input"> 
        <label for="firstName">First Name</label>
        <input 
        type="text"
        id="firstName" 
        v-model.trim="firstName">
      </div>
      <div class="input">
        <label for="lastName">Last Name</label>
        <input 
        type="text" 
        id="lastName" 
        v-model.trim="lastName">
      </div>
      <div class="input">
        <label for="password">Password</label>
        <input 
        type="password" 
        id="password" 
        v-model.trim="password">
      </div>
      <button type="submit">Submit</button>
    </form>
  </div>
</template>
<script>
export default {
  data() {
    return {
      email: '',
      password: '',
      firstName: '',
      lastName: '',
    };
  },
  methods: {
    onSubmit(){
    }
  },
}
</script>

这里发生了很多事情,所以让我们一步一步地把它分解:

  1. 我们正在使用@submit.prevent指令创建一个新表单,以便在提交表单时页面不会重新加载,这与在此表单上调用 submit 并在事件上使用preventDefault相同
  2. 接下来,我们将v-model.trim添加到每个表单输入元素中,以便修剪任何空白并将输入捕获为变量

  3. 我们在数据函数中定义这些变量,以便它们是被动的

  4. submit按钮是用type="submit"定义的,因此当点击该按钮时,表单的submit功能将运行
  5. 我们正在剔除一个空白的onSubmit函数,我们很快就会创建它

现在我们需要添加@input事件,并在我们的input元素中的每一个上调用touch事件,绑定到数据属性v-model,并向字段提供验证,如下所示:

<div class="input">
  <label for="email">Email</label>
  <input 
  type="email" 
  id="email" 
  @input="$v.email.$touch()"
  v-model.trim="email">
</div>
<div class="input"> 
  <label for="firstName">First Name</label>
  <input 
  type="text"
  id="firstName" 
  v-model.trim="firstName"
  @input="$v.firstName.$touch()">
</div>
<div class="input">
  <label for="lastName">Last Name</label>
  <input 
  type="text" 
  id="lastName" 
  v-model.trim="lastName"
  @input="$v.lastName.$touch()">
</div>
<div class="input">
  <label for="password">Password</label>
  <input 
  type="password" 
  id="password" 
  v-model.trim="password"
  @input="$v.password.$touch()">
</div>

然后,我们可以通过从Vuelidate导入验证并添加与表单元素对应的validations对象,将验证添加到我们的 Vue 实例中。

Vuelidate将使用我们的data变量绑定此处设置的相同名称,如下所示:

import { required, email } from 'vuelidate/lib/validators';

export default {
 // Omitted
  validations: {
    email: {
      required,
      email,
    },
    firstName: {
      required,
    },
    lastName: {
      required,
    },
    password: {
      required,
    }
  },
}

我们只是导入所需的电子邮件验证器并将其应用于每个模型项。这从本质上确保我们的所有项目都是必需的,并且电子邮件输入与电子邮件正则表达式匹配。然后,我们可以通过添加以下内容来可视化表单和每个字段的当前状态:

 <div class="validators">
  <pre>{{$v}}</pre>
 </div>

然后,我们可以添加一些样式,在右侧显示验证,在左侧显示表单:

<style>
.form {
 display: inline-block;
 text-align: center;
 width: 49%;
}
.validators {
 display: inline-block;
 width: 49%;
 text-align: center;
 vertical-align: top;
}
.input {
 padding: 5px;
}
</style>

如果一切按计划进行,我们应该得到以下结果:

显示表单错误

我们可以使用$v.model_name对象内部的$invalid布尔值(其中model_name等于emailfirstNamelastNamepassword来显示消息或更改表单字段的外观。让我们首先添加一个名为error的新类,该类在输入字段周围添加一个red``border

<style>
input:focus {
  outline: none;
}
.error {
  border: 1px solid red;
}
</style>

然后,只要该字段无效并使用v-bind:class触碰,我们就可以有条件地应用该类:

<div class="input">
  <label for="email">Email</label>
  <input 
  :class="{ error: $v.email.$error }"
  type="email" 
  id="email" 
  @input="$v.email.$touch()"
  v-model.trim="email">
</div>
<div class="input"> 
  <label for="firstName">First Name</label>
  <input 
  :class="{ error: $v.firstName.$error }"
  type="text"
  id="firstName" 
  v-model.trim="firstName"
  @input="$v.firstName.$touch()">
</div>
<div class="input">
  <label for="lastName">Last Name</label>
  <input 
  :class="{ error: $v.lastName.$error}"
  type="text" 
  id="lastName" 
  v-model.trim="lastName"
  @input="$v.lastName.$touch()">
</div>
<div class="input">
  <label for="password">Password</label>
  <input 
  :class="{ error: $v.password.$error }"
  type="password" 
  id="password" 
  v-model.trim="password"
  @input="$v.password.$touch()">
</div>

然后,每当字段无效或有效时,这将为我们提供以下结果:

如果出现这种情况,则可以显示错误消息。这可以通过多种方式完成,具体取决于您想要显示的消息类型。以email输入为例,当email字段的电子邮件地址无效时,显示一条错误消息:

<div class="input">
  <label for="email">Email</label>
  <input 
  :class="{ error: $v.email.$error }"
  type="email" 
  id="email" 
  @input="$v.email.$touch()"
  v-model.trim="email">

  <p class="error-message" v-if="!$v.email.email">Please enter a valid email address</p>
</div>

// Omitted
<style>
.error-message {
 color: red;
}
</style>

正如我们从$v对象的表示中所看到的,当字段具有有效的电子邮件地址时,电子邮件布尔值为 true,如果没有,则为 false。虽然这会检查电子邮件是否正确,但不会检查字段是否为空。让我们添加另一条基于required验证器检查此情况的错误消息:

 <p class="error-message" v-if="!$v.email.email">Please enter a valid email address.</p>
 <p class="error-message" v-if="!$v.email.required">Email must not be empty.</p>

如果我们愿意,我们甚至可以更进一步,创建我们自己的包装器组件来呈现每个字段的各种错误消息。让我们填写其余的错误消息,同时检查表单元素是否已被触动(是$dirty

<div class="input">
  <label for="email">Email</label>
  <input 
  :class="{ error: $v.email.$error }"
  type="email" 
  id="email" 
  @input="$v.email.$touch()"
  v-model.trim="email">

  <div v-if="$v.email.$dirty">
    <p class="error-message" v-if="!$v.email.email">Please enter a 
    valid email address.</p>
    <p class="error-message" v-if="!$v.email.required">Email must not 
    be empty.</p>
  </div>

</div>
<div class="input"> 
  <label for="firstName">First Name</label>
  <input 
  :class="{ error: $v.firstName.$error }"
  type="text"
  id="firstName" 
  v-model.trim="firstName"
  @input="$v.firstName.$touch()">

  <div v-if="$v.firstName.$dirty">
    <p class="error-message" v-if="!$v.firstName.required">First Name 
  must not be empty.</p>
  </div>
</div>
<div class="input">
  <label for="lastName">Last Name</label>
  <input 
  :class="{ error: $v.lastName.$error}"
  type="text" 
  id="lastName" 
  v-model.trim="lastName"
  @input="$v.lastName.$touch()">

  <div v-if="$v.lastName.$dirty">
    <p class="error-message" v-if="!$v.lastName.required">Last Name 
   must not be empty.</p>
  </div>
</div>
<div class="input">
  <label for="password">Password</label>
  <input 
  :class="{ error: $v.password.$error }"
  type="password" 
  id="password" 
  v-model.trim="password"
  @input="$v.password.$touch()">

  <div v-if="$v.password.$dirty">
    <p class="error-message" v-if="!$v.password.required">Password must 
  not be empty.</p>
  </div>
</div>

密码验证

在创建用户帐户时,密码通常会输入两次,并符合最小长度。让我们添加另一个字段和更多验证规则来强制执行此操作:

import { required, email, minLength, sameAs } from 'vuelidate/lib/validators';

export default {
 // Omitted
  data() {
    return {
      email: '',
      password: '',
      repeatPassword: '',
      firstName: '',
      lastName: '',
    };
  },
  validations: {
    email: {
      required,
      email,
    },
    firstName: {
      required,
    },
    lastName: {
      required,
    },
    password: {
      required,
      minLength: minLength(6),
    },
    repeatPassword: {
      required,
      minLength: minLength(6),
      sameAsPassword: sameAs('password'),
    },
  },
}

我们已经做了以下工作:

  1. repeatPassword字段添加到我们的数据对象中,以便它可以保存重复的密码
  2. Vuelidate导入了minLengthsameAs验证器
  3. 6字符的minLength添加到password验证器
  4. 增加了sameAs验证器,强制repeatPassword遵循与password相同的验证规则

由于我们现在有了适当的密码验证,我们可以添加新字段并显示任何错误消息:

<div class="input">
 <label for="email">Email</label>
 <input 
 :class="{ error: $v.email.$error }"
 type="email" 
 id="email" 
 @input="$v.email.$touch()"
 v-model.trim="email">

 <div v-if="$v.email.$dirty">
 <p class="error-message" v-if="!$v.email.email">Please enter a valid email address.</p>
 <p class="error-message" v-if="!$v.email.required">Email must not be empty.</p>
 </div>

</div>
<div class="input"> 
 <label for="firstName">First Name</label>
 <input 
 :class="{ error: $v.firstName.$error }"
 type="text"
 id="firstName" 
 v-model.trim="firstName"
 @input="$v.firstName.$touch()">

 <div v-if="$v.firstName.$dirty">
 <p class="error-message" v-if="!$v.firstName.required">First Name must not be empty.</p>
 </div>
</div>
<div class="input">
 <label for="lastName">Last Name</label>
 <input 
 :class="{ error: $v.lastName.$error}"
 type="text" 
 id="lastName" 
 v-model.trim="lastName"
 @input="$v.lastName.$touch()">

 <div v-if="$v.lastName.$dirty">
 <p class="error-message" v-if="!$v.lastName.required">Last Name must not be empty.</p>
 </div>
</div>
<div class="input">
 <label for="password">Password</label>
 <input 
 :class="{ error: $v.password.$error }"
 type="password" 
 id="password" 
 v-model.trim="password"
 @input="$v.password.$touch()">

 <div v-if="$v.password.$dirty">
 <p class="error-message" v-if="!$v.password.required">Password must not be empty.</p>
 </div>
</div>
<div class="input">
 <label for="repeatPassword">Repeat Password</label>
 <input 
 :class="{ error: $v.repeatPassword.$error }"
 type="password" 
 id="repeatPassword" 
 v-model.trim="repeatPassword"
 @input="$v.repeatPassword.$touch()">

 <div v-if="$v.repeatPassword.$dirty">
 <p class="error-message" v-if="!$v.repeatPassword.sameAsPassword">Passwords must be identical.</p>

 <p class="error-message" v-if="!$v.repeatPassword.required">Password must not be empty.</p>
 </div>
</div>

提交表格

接下来,如果表单无效,我们可以禁用Submit按钮:

<button :disabled="$v.$invalid" type="submit">Submit</button>

我们还可以通过this.$v.$invalid在 JavaScript 中获取该值。下面是一个示例,说明如何检查表单是否无效,然后基于表单元素创建用户对象:

methods: {
  onSubmit() {
    if(!this.$v.$invalid) {
      const user = { 
        email: this.email,
        firstName: this.firstName,
        lastName: this.lastName,
        password: this.password,
        repeatPassword: this.repeatPassword
      }

      // Submit the object to an API of sorts
    }
  },
},

如果您希望以这种方式使用数据,您可能更愿意这样设置数据对象:

data() {
  return {
    user: {
      email: '',
      password: '',
      repeatPassword: '',
      firstName: '',
      lastName: '',
    }
  };
},

我们现在已经创建了一个具有适当验证的表单!

渲染/功能组件

我们将绕过和绕开验证和动画,考虑使用功能组件和渲染功能来提高应用性能。您还可能听说这些组件被称为“表示组件”,因为它们是无状态的,只作为输入属性接收数据。

到目前为止,我们只为组件声明了带有template标记的标记,但也可以使用render函数(如src/main.js所示):

import Vue from 'vue'
import App from './App.vue'

new Vue({
  el: '#app',
  render: h => h(App)
})

h来自 hyperscript,它允许我们使用 JavaScript 创建/描述 DOM 节点。在render函数中,我们只是简单地呈现App组件,将来,我们将更详细地研究它。Vue 创建一个虚拟 DOM,以使使用实际 DOM 变得更简单(以及在处理大量元素时提高性能)。

渲染元素

我们可以用以下对象替换我们的App.vue组件,该对象接受render对象和hyperscript而不是使用template

<script>
export default {
 render(h) {
  return h('h1', 'Hello render!')
 }
}
</script>

然后呈现一个新的带有文本节点'Hello render!'h1标记,该标记被称为VNode虚拟节点)和复数VNode虚拟 DOM 节点),用于描述整个树。现在让我们看看如何在ul中显示项目列表:

  render(h){
    h('ul', [
      h('li', 'Evan You'),
      h('li', 'Edd Yerburgh'),
      h('li', 'Paul Halliday')
    ])
 }

必须认识到,我们只能使用 hyperscript 渲染一个根节点。此限制与我们的模板相同,因此我们希望将项目包装在一个div中,如下所示:

render(h) {
 return h('div', [
  h('ul', [
   h('li', 'Evan You'),
   h('li', 'Edd Yerburgh'),
   h('li', 'Paul Halliday')
  ])
 ])
}

属性

我们还可以将样式元素和各种其他属性传递给渲染项。下面是一个使用style对象更改每个项目red颜色的示例:

 h('div', [
  h('ul', { style: { color: 'red' } }, [
   h('li', 'Evan You'),
   h('li', 'Edd Yerburgh'),
   h('li', 'Paul Halliday')
  ])
 ])

您可以想象,我们可以添加任意数量的style属性,以及我们期望的额外选项,例如propsdirectiveson(单击处理程序)等等。让我们看看如何映射元素以使用props渲染组件。

组件和道具

让我们用一个道具namecomponents/ListItem.vue下创建一个ListItem组件。我们将渲染此组件来代替我们的li,并映射到包含各种names的数组上。注意我们如何将functional: true选项添加到我们的 Vue 实例中;这告诉 Vue,这纯粹是一个表示组件,它不会有任何自己的状态:

<script>
export default {
 props: ['name'],
 functional: true
}
</script>

通过我们的render函数,h通常也被称为createElement,因为我们处于 JavaScript 上下文中,所以我们能够利用数组操作符,例如mapfilterreduce等等。让我们用map替换动态生成组件的静态名称:

import ListItem from './components/ListItem.vue';

export default {
 data() {
  return {
   names: ['Evan You', 'Edd Yerburgh', 'Paul Halliday']
  }
 },
 render(createElement) {
  return createElement('div', [
   createElement('ul',
    this.names.map(name => 
     createElement(ListItem, 
      {props: { name: name } })
     ))
   ])
 }
}

我们需要做的最后一件事是在组件中添加一个render函数。作为第二个参数,我们能够访问上下文对象,这允许我们访问options比如props。在本例中,我们假设name道具始终存在,而不是nullundefined

export default {
 props: ['name'],
 functional: true,
 render(createElement, context) {
  return createElement('li', context.props.name)
 }
}

同样,我们现在有一个元素列表,其中包括作为prop传递的项目:

JSX

虽然这是一个很好的思考练习,但在大多数情况下模板都是优越的。有时您可能希望在组件内部使用 render 函数,在这些情况下,使用 JSX 可能更简单。

让我们通过在终端中运行以下命令,将用于 JSX 的 babel 插件添加到我们的项目中:

$ npm i -D babel-helper-vue-jsx-merge-props babel-plugin-syntax-jsx babel-plugin-transform-vue-jsx

然后我们可以更新我们的.babelrc以使用新插件:

{
 "presets": [
 ["env", { "modules": false }],
 "stage-3"
 ],
 "plugins": ["transform-vue-jsx"]
}

这允许我们重写render函数,以利用更简单的语法:

render(h) {
 return (
  <div>
   <ul>
    { this.names.map(name => <ListItem name={name} />) }
   </ul>
  </div>
 )
}

这更具声明性,也更易于维护。在引擎盖下,它正在被传输到以前的hyperscript格式与巴贝尔。

总结

在本章中,我们学习了如何在 Vue 项目中利用 CSS 动画和转换。这允许我们让用户体验更流畅,并改善应用的外观和感觉。

我们还学习了如何使用render方法构建 UI;这涉及到使用 HyperScript 创建 VNode,然后使用 JSX 进行更清晰的抽象。虽然您可能不想在项目中使用 JSX,但如果您来自 React 背景,您可能会发现它更适合您。