返回博客首页
← 所有文章

使用类组件的 NativeScript-Vue

2019 年 3 月 21 日 — 作者:Alexander Ziskind

你可能已经听说过,从 5.2 版本开始,NativeScript CLI 可以构建基于 Vue 的原生移动应用。对于一个小版本的发布来说,这是一个很棒的额外功能,我认为这是朝着正确方向迈出的一步。

我一直是 TypeScript 的粉丝,它在企业中被广泛使用,并且在 2019 年也得到了 VueJS 社区的认可。因此,听到 NativeScript-Vue 最近也获得了 TypeScript 支持,我感到非常高兴。

虽然我们正在等待 NativeScript CLI 为其 Vue 项目提供 TypeScript 选项,但仍然有一种替代方法可以创建 NativeScript-Vue 项目,从而获得 TypeScript 支持,并允许你使用类组件。

让我们看看如何在 NativeScript-Vue 中利用类组件。

创建使用 TypeScript 的 NativeScript-Vue 项目

我们需要创建一个 NativeScript 项目,同时支持 Vue 和 TypeScript。我在 YouTube 上发布的最近的视频中展示了如何做到这一点。以下是步骤。

我假设你已经在你的机器上安装了最新的NativeScript 必备组件

首先,通过 npm 全局安装 Vue CLI 和 cli-init 工具

npm install -g @vue/cli @vue/cli-init

使用 Vue CLI 和 cli-init 工具以及 nativescript-vue vue-cli-template 生成一个新的 NativeScript 项目。

vue init nativescript-vue/vue-cli-template <project-name>

运行此 Vue CLI 命令时,你会得到一个交互式向导,它会询问你一些问题。

- Project name
- Project description
- Application...

等等...

你需要选择的语言选项是

- Select the programming language
  - javascript
  - typescript <- this one

按照向导的其余步骤设置项目,在此之后,你选择的任何选项都可以。

这将创建一个新的 NativeScript 项目,并在 package.json 文件中包含正确的包,一个正确配置的 tsconfig.json,以及最重要的:一个正确配置的 webpack.config.js 文件。还有一个 types 文件夹,其中包含环境的额外 TypeScript 声明、Vue shims 和 nativescript 平台引用。

app 文件夹中有一个 main.ts 文件。是的,你看到的是 .ts 扩展名。

并且你的单文件 Vue 组件有一个代码块,指定 TypeScript 作为语言。请注意 script 标签上 lang 属性的 ts 值。

<script lang="ts">
  export default {
    data() {
      return {
        msg: 'Hello World!'
      }
    }
  }
</script>

顺便说一句,如果你愿意,可以省略此 lang 属性并在此处只编写纯 JavaScript。例如,这对于从 JavaScript 过渡到 TypeScript 的项目很有用。

运行项目时,不要忘记你需要使用 --bundle 标志。否则,你将百思不得其解,抓耳挠腮,想知道发生了什么。

tns run ios --bundle

或者

tns run android --bundle

添加类组件支持

如果你来自 Angular 背景,那么你将对带有装饰器的基于类的组件感到宾至如归。这是切换到使用 TypeScript 后的下一步,也是 Angular 开发人员的自然选择。

为什么要使用类组件?很简单 - 语法更简洁。类属性自动成为数据属性。无需使用由数据属性返回的奇怪函数语法,**并且**你也不必担心 this

安装包

开箱即用,新的 nativescript-vue cli 模板创建对象表示法 TypeScript 组件。如果你想获得类组件**和**TypeScript,则需要执行一些手动步骤。希望这些步骤将来也会被集成到模板中。

在项目的 package.json 文件中,添加以下依赖项以支持 Vue 类组件和装饰器

"dependencies": {
    ...
    "vue-class-component": "^6.3.2",
    "vue-property-decorator": "^7.3.0",
    ...
},

运行 npm install

创建基于类的单文件组件

你可以立即开始使用类组件。让我们尝试创建一个简单的临时组件,以便我们可以了解它们的工作原理。创建一个单文件组件文件,我们将其命名为 MyComp.vue 并添加以下代码

<template>
  <Label class="message" :text="msg" col="0" row="0"/>
</template>

<script lang="ts">
import { Component, Prop, Vue } from "vue-property-decorator";
@Component
export default class MyComp extends Vue {
  @Prop() private msg: string;
}
</script>

请注意,默认导出不是 JavaScript 对象,而是导出一个类。并且我们不是从 vue 中导入 Vue,而是从 vue-property-decorator 中导入它。

不要忘记类上的 @Component 装饰器。

类组件脚手架

在这里,我们将稍微改变一下方向,创建一个新的示例,以便我们可以检查在 NativeScript-Vue 中使用类组件的所有方面。

类组件 .vue 文件与它们的 object notation .vue 文件并没有太大区别。

以下是我们将要使用的示例。

<template>
  <StackLayout class="form">
    <StackLayout class="input-field">
      <Label text="First Name" class="label font-weight-bold m-b-5"/>
      <TextField v-model="firstName" hint="First Name" class="input input-border"/>
    </StackLayout>
  </StackLayout>
</template>

<script lang="ts">
import { Vue, Component } from "vue-property-decorator";

@Component
export default class PersonClassComponent extends Vue {

}
</script>

这里需要注意的两件事是,我们导出一个继承自 Vue 的类,并且我们使用 @Component 装饰器修饰了该类,这与我们在 Angular 中的操作类似。

检查 NativeScript-Vue 中的类组件

如果你认真考虑在你的 NativeScript VueJS 应用中使用 TypeScript 的类组件,你需要了解以下五件事。我创建了一个YouTube 视频,详细展示了每一件事。

  1. Props - 作为输入传递到 Vue 组件的数据
  2. Data - 这是 Vue 组件的本地属性(或状态)
  3. Watch - 使用它来监视其他属性并对它们的变化做出反应
  4. Computed - 不要创建和维护另一个属性!使用计算属性来创建一个计算属性。
  5. Methods - 它们执行操作!这些是你的事件处理程序和其他类函数

第一件事:Props

通过使用 vue-property-decorator 中的 @Prop 装饰器,我们只需修饰类属性即可声明输入属性。

<template>
  <StackLayout class="form">
    <StackLayout class="input-field">
      <Label text="First Name" class="label font-weight-bold m-b-5"/>
      <TextField v-model="firstName" hint="First Name" class="input input-border"/>
    </StackLayout>
  </StackLayout>
</template>

<script lang="ts">
import { Vue, Component, Prop } from "vue-property-decorator";

@Component
export default class PersonClassComponent extends Vue {
  @Prop() whatToSay: string;
}
</script>

如果你来自 object notation Vue,那么你习惯了这样的代码

export default {
  props: {
    whatToSay: {
      type: String
    }
  }
};

第二件事:Data

使用类组件时,data 非常简单。它只是类上的属性

<template>
  <StackLayout class="form">
    <StackLayout class="input-field">
      <Label text="First Name" class="label font-weight-bold m-b-5"/>
      <TextField v-model="firstName" hint="First Name" class="input input-border"/>
    </StackLayout>
  </StackLayout>
</template>

<script lang="ts">
import { Vue, Component, Prop } from "vue-property-decorator";

@Component
export default class PersonClassComponent extends Vue {
  @Prop() whatToSay: string;

  //Data
  counter = 1;
  firstName = "Donna";
  initialLastName = "Summer";
  lastName = this.initialLastName;
}
</script>

以下是 object notation 中 data 的样子 - 我认为它没有那么容易理解

data() {
    return {
      counter: 1,
      firstName: "Donna",
      initialLastName: "Summer",
      lastName: "Summer"
    };
  },

第三件事:Watch

Watcher 可能最复杂的部分,因为它们被定义为带有 @Watch 装饰器的类方法。@Watch 装饰器必须指定我们正在监视哪个属性。

<template>
  <StackLayout class="form">
    <StackLayout class="input-field">
      <Label text="First Name" class="label font-weight-bold m-b-5"/>
      <TextField v-model="firstName" hint="First Name" class="input input-border"/>
    </StackLayout>
  </StackLayout>
</template>

<script lang="ts">
import { Vue, Component, Prop, Watch } from "vue-property-decorator";

@Component
export default class PersonClassComponent extends Vue {
  @Prop() whatToSay: string;
  counter = 1;
  firstName = "Donna";
  initialLastName = "Summer";
  lastName = this.initialLastName;

  //Here we define a Watch
  @Watch("firstName")
  onFirstNameChanged() {
    this.lastName = this.initialLastName + this.counter++;
  }
}
</script>

但是,它仍然比 object notation 更简洁,object notation 看起来像这样

watch: {
    firstName: {
      handler() {
        this.lastName = this.initialLastName + this.counter++;
        console.log("first name changed");
      }
    }
  }

三重嵌套对象绝对不容易查看或理解。再说一遍,这是我的观点。

第四件事:Computed

Computed 是我最喜欢的,因为它们在类中以 getter(和 setter)属性的方式执行。

<template>
  <StackLayout class="form">
    <StackLayout class="input-field">
      <Label text="First Name" class="label font-weight-bold m-b-5"/>
      <TextField v-model="firstName" hint="First Name" class="input input-border"/>
    </StackLayout>

    <StackLayout class="input-field">
      <Label text="Full Name" class="label font-weight-bold m-b-5"/>
      <Label :text="fullName"/>
    </StackLayout>
  </StackLayout>
</template>

<script lang="ts">
import { Vue, Component, Prop, Watch } from "vue-property-decorator";

@Component
export default class PersonClassComponent extends Vue {
  @Prop() whatToSay: string;
  counter = 1;
  firstName = "Donna";
  initialLastName = "Summer";
  lastName = this.initialLastName;

  //Computed
  get fullName() {
    return `${this.firstName} ${this.lastName}`;
  }

  @Watch("firstName")
  onFirstNameChanged() {
    this.lastName = this.initialLastName + this.counter++;
  }
}
</script>

第五件事:Methods

由于我们使用的是类,所以猜猜看!方法只是类方法!在模板中声明一个事件处理程序,然后在你的类中编写一个方法即可。

<template>
  <StackLayout class="form">
    <StackLayout class="input-field">
      <Label text="First Name" class="label font-weight-bold m-b-5"/>
      <TextField v-model="firstName" hint="First Name" class="input input-border"/>
    </StackLayout>

    <StackLayout class="input-field">
      <Label text="Full Name" class="label font-weight-bold m-b-5"/>
      <Label :text="fullName"/>
    </StackLayout>

    <Button text="SPEAK" @tap="speak"/>
  </StackLayout>
</template>

<script lang="ts">
import { Vue, Component, Prop, Watch } from "vue-property-decorator";

@Component
export default class PersonClassComponent extends Vue {
  @Prop() whatToSay: string;

  counter = 1;
  firstName = "Donna";
  initialLastName = "Summer";
  lastName = this.initialLastName;

  get fullName() {
    return `${this.firstName} ${this.lastName}`;
  }

  @Watch("firstName")
  onFirstNameChanged() {
    this.lastName = this.initialLastName + this.counter++;
  }

  //And here is the method
  speak() {
    alert("This is " + this.fullName + " speaking. " + this.whatToSay);
  }
}
</script>

结论

我知道类组件并不适合所有人,有些人真的喜欢使用纯 JavaScript,这完全没问题。这只是另一种方法,如果你确实要在 NativeScript-vue 应用中使用 TypeScript,那么 Vue 中的类组件是自然之选。尤其是在那些来自面向对象编程背景的人 - .NET 和 Angular 开发人员,包括你。

你想要更多 NativeScript-Vue 视频吗?我有一个NativeScript-Vue 入门课程,另一位 NativeScript 开发专家 Paul Halliday 也提供了一个全新的课程,专门讲解使用 NativeScript-Vue 和 Vuex 进行状态管理