前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Vue Class Component文档翻译

Vue Class Component文档翻译

作者头像
治电小白菜
发布2020-08-25 15:54:29
3.2K0
发布2020-08-25 15:54:29
举报
文章被收录于专栏:技术综合

英文文档地址: https://class-component.vuejs.org/

本文包括了文档中的 总览, 安装, 指南, TypeScript指南

总览

Vue Class Component 是一个可以让你使用Class风格语法编写Vue组件的库. 例如, 下面是一个通过Vue Class Component编写的简单的计数器组件的例子:

代码语言:javascript
复制
<template>
  <div>
    <button v-on:click="decrement">-</button>
    {{ count }}
    <button v-on:click="increment">+</button>
  </div>
</template>

<script>
import Vue from 'vue'
import Component from 'vue-class-component'

// 使用Class风格定义组件
@Component
export default class Counter extends Vue {
  // Class的属性将是组件的data
  count = 0

  // Methods will be component methods
  increment() {
    this.count++
  }

  decrement() {
    this.count--
  }
}
</script>

正如例子展现的, 你可以使用通过@Component装饰器标注Class, 来用直观和标准的Class语法定义组件的data和方法. 你可以简单地使用Class风格的组件代替组件定义, 因为它等价于普通的使用对象定义的组件.

通过使用Class风格定义的组件, 你不但要改变语法, 还要利用一些ECMAScript语法特性, 比如Class继承和装饰器. Vue Class Component 也提供了一个mixins 帮助 来继承mixin, 以及一个 createDecorator 方法来简单地创建你自己的修饰器.

你或许也需要使用 Vue Property Decorator 提供的 @Prop@Watch 装饰器.

安装

Vue CLI 安装

你可以通过使用 Vue CLI 简单的安装 Vue Class Component. 运行下面命令来创建一个新项目:

代码语言:javascript
复制
$ vue create hello-world

你将被告知是否使用预设配置. 请选择 "Manually select features":

image.png

选中 TypeScript 功能来使用 Vue Class Component. 你可以添加其他你需要的功能:

image.png

输入 y 来回答 Use class-style component syntax?:

image.png

你可以按照自己的偏爱回答剩下的问题. 在结束安装进程后, Vue CLI 会创建一个新的安装了Vue Class Component 的项目目录.

手动安装

如果你要手动安装, 娜美你需要使用npm以及配置你自己的打包工具.

npm

使用 npm 安装 Vue Class Component. 请确定你以及安装了Vue核心库, Vue Class Component依赖于它:

代码语言:javascript
复制
$ npm install --save vue vue-class-component

使用 yarn 安装:

代码语言:javascript
复制
$ yarn add --save vue vue-class-component

Build Setup

使用Vue Class Component 你需要在你的项目中配置 TypeScript 或者 Babel, 因为它依赖于 ECMAScript stage 1 decorators 编译, 从而能在浏览器中运行.

::: 注意 它不支持 stage 2 decorators, 由于 TypeScript 编译器只支持旧版本装饰器. :::

TypeScript

在项目根目录创建 tsconfig.json, 然后配置 experimentalDecorators 选项, 它可以编译装饰器语法:

代码语言:javascript
复制
{
  "compilerOptions": {
    "target": "es5",
    "module": "es2015",
    "moduleResolution": "node",
    "strict": true,
    "experimentalDecorators": true
  }
}
Babel

安装 @babel/plugin-proposal-decorators@babel/plugin-proposal-class-properties:

代码语言:javascript
复制
$ npm install --save-dev @babel/plugin-proposal-decorators @babel/plugin-proposal-class-properties

在文件根目录下配置 .babelrc 文件:

代码语言:javascript
复制
{
  "plugins": [
    ["@babel/proposal-decorators", { "legacy": true }],
    ["@babel/proposal-class-properties", { "loose": true }]
  ]
}

注意 legacyloose 选项需要 Vue Class Component 只支持 stage 1 (legacy) decorator spec.

CDN

unpkg.com 提供基于npm的 CDN 链接. 你可以选择对应版本的 Vue Class Component 来代替 @latest 版本 (例如 https://unpkg.com/vue-class-component@7.2.2/dist/vue-class-component.js 就是使用版本为 7.2.2的Vue Class Component).

代码语言:javascript
复制
<!-- UMD build -->
<script src="https://unpkg.com/vue-class-component@latest/dist/vue-class-component.js"></script>

<!-- UMD minified build -->
<script src="https://unpkg.com/vue-class-component@latest/dist/vue-class-component.min.js"></script>

<!-- ES Module build -->
<script src="https://unpkg.com/vue-class-component@latest/dist/vue-class-component.esm.browser.js"></script>

<!-- ES Module minified build -->
<script src="https://unpkg.com/vue-class-component@latest/dist/vue-class-component.esm.browser.min.js"></script>

不同的打包方式

Vue Class Component 提供不同的打包方式, 用来在不同的环境下使用

  • For development
    • vue-class-component.js (UMD)
    • vue-class-component.common.js (CommonJS)
    • vue-class-component.esm.js (ES Module for bundlers)
    • vue-class-component.esm.browser.js (ES Module for browsers)
  • For production (minified)
    • vue-class-component.min.js (UMD)
    • vue-class-component.esm.browser.min.js (ES Module for browsers)

Class 组件

@Component 装饰器可以让你能创建一个基于Class的Vue组件:

代码语言:javascript
复制
import Vue from 'vue'
import Component from 'vue-class-component'

// HelloWorld class will be a Vue component
@Component
export default class HelloWorld extends Vue {}

Data

使用Class属性来初始化 data:

代码语言:javascript
复制
<template>
  <div>{{ message }}</div>
</template>

<script>
import Vue from 'vue'
import Component from 'vue-class-component'

@Component
export default class HelloWorld extends Vue {
  // 定义 component 的 data
  message = 'Hello World!'
}
</script>

The above component renders 上面的组件会在<div>中的组件data message中渲染Hello World!

注意如果初始化的值是 undefined, Class属性将不是响应式的, 意思就是当其发生修改后, 将不会被侦测到:

代码语言:javascript
复制
import Vue from 'vue'
import Component from 'vue-class-component'

@Component
export default class HelloWorld extends Vue {
  // `message` 将不是响应式数据
  message = undefined
}

为了防止这种情况, 你需要使用 null 来赋值, 或者使用 data 钩子来代替:

代码语言:javascript
复制
import Vue from 'vue'
import Component from 'vue-class-component'

@Component
export default class HelloWorld extends Vue {
  // `message` 将是响应式
  message = null

  data() {
    return {
      // `hello` 将是响应式的, 因为在data钩子里
      hello: undefined
    }
  }
}

Methods

组件 methods 将直接定义在Class方法属性中:

代码语言:javascript
复制
<template>
  <button v-on:click="hello">Click</button>
</template>

<script>
import Vue from 'vue'
import Component from 'vue-class-component'

@Component
export default class HelloWorld extends Vue {
  // 定义一个组件方法
  hello() {
    console.log('Hello World!')
  }
}
</script>

Computed Properties

计算属性可以通过Class属性的 getter / setter 定义:

代码语言:javascript
复制
<template>
  <input v-model="name">
</template>

<script>
import Vue from 'vue'
import Component from 'vue-class-component'

@Component
export default class HelloWorld extends Vue {
  firstName = 'John'
  lastName = 'Doe'

  // 定义计算属性的 getter
  get name() {
    return this.firstName + ' ' + this.lastName
  }

  // 定义计算属性的 setter
  set name(value) {
    const splitted = value.split(' ')
    this.firstName = splitted[0]
    this.lastName = splitted[1] || ''
  }
}
</script>

Hooks

data, render 以及所有Vue生命周期钩子可以直接在Class属性方法中直接定义, 但是你不能在实例本身上调用他们. 当定义自定义方法时, 你应该回避这些保留名

代码语言:javascript
复制
import Vue from 'vue'
import Component from 'vue-class-component'

@Component
export default class HelloWorld extends Vue {
  // 定义生命周七钩子函数
  mounted() {
    console.log('mounted')
  }

  // 定义渲染函数
  render() {
    return <div>Hello World!</div>
  }
}

其他选项

对于其他的选项, 使用修饰器来配置它们:

代码语言:javascript
复制
<template>
  <OtherComponent />
</template>

<script>
import Vue from 'vue'
import Component from 'vue-class-component'
import OtherComponent from './OtherComponent.vue'

@Component({
  // 查看 Vue.js 文档, 来了解所有的选项:
  // https://vuejs.org/v2/api/#Options-Data
  components: {
    OtherComponent
  }
})
export default class HelloWorld extends Vue {}
</script>

额外的钩子

如果你使用Vue的插件, 比如Vue Router, 你或许需要Class组件来解决它们提供的钩子. 在这个例子中, Component.registerHooks允许你注册这些钩子:

代码语言:javascript
复制
// class-component-hooks.js
import Component from 'vue-class-component'

// 使用路由钩子函数的名字注册
Component.registerHooks([
  'beforeRouteEnter',
  'beforeRouteLeave',
  'beforeRouteUpdate'
])

在注册完这些钩子后, 就可以在Class组件中把它们当作Class属性方法来使用:

代码语言:javascript
复制
import Vue from 'vue'
import Component from 'vue-class-component'

@Component
export default class HelloWorld extends Vue {
  beforeRouteEnter(to, from, next) {
    console.log('beforeRouteEnter')
    next()
  }

  beforeRouteUpdate(to, from, next) {
    console.log('beforeRouteUpdate')
    next()
  }

  beforeRouteLeave(to, from, next) {
    console.log('beforeRouteLeave')
    next()
  }
}

推荐在单独的文件中写注册钩子的代码, 因为你需要在其他组件定义前注册它们. 你可以在文件顶部使用 import 引入:

代码语言:javascript
复制
// main.js

// 确定在引入其他组件前注册
import './class-component-hooks'

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

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

自定义装饰器

你可以通过创建你自己的装饰器来扩展功能性的库. Vue Class Component 提供 createDecorator 帮助创建自定义装饰器. createDecorator 接受一个回调函数作为第一个参数, 回调将接受下面的参数:

  • options: Vue 组件选项. 改变这个对象将影响所提供的组件.
  • key: 装饰器所需要的属性或方法的键.
  • parameterIndex: 如果自定义装饰器用于参数,则装饰参数的索引.

下面例子是创建一个 Log 装饰器, 当修饰器方法被调用时, 打印log信息, 包括方法名和参数:

代码语言:javascript
复制
// decorators.js
import { createDecorator } from 'vue-class-component'

// 定义 Log 装饰器.
export const Log = createDecorator((options, key) => {
  // 保存原始方法.
  const originalMethod = options.methods[key]

  // 覆盖方法.
  options.methods[key] = function wrapperMethod(...args) {
    // 打印一个 log.
    console.log(`Invoked: ${key}(`, ...args, ')')

    // 调用原始方法
    originalMethod.apply(this, args)
  }
})

作为方法修饰器使用它:

代码语言:javascript
复制
import Vue from 'vue'
import Component from 'vue-class-component'
import { Log } from './decorators'

@Component
class MyComp extends Vue {
  // 当`hello`方法被调用, 打印一个log
  @Log
  hello(value) {
    // ...
  }
}

在上面代码中, 当 hello 被调用, 并传入 42, 将会打印处下面的log:

代码语言:javascript
复制
Invoked: hello( 42 )

扩展 和 Mixins

扩展

你可以扩展一个存在的Class组件, 类似于原生的Class继承. 想象你有下面的名为Super的Class组件:

代码语言:javascript
复制
// super.js
import Vue from 'vue'
import Component from 'vue-class-component'

// 定义一个叫super的Class组件
@Component
export default class Super extends Vue {
  superValue = 'Hello'
}

你可以扩展他, 通过使用原生的Class继承语法:

代码语言:javascript
复制
import Super from './super'
import Component from 'vue-class-component'

// 扩展  名为Super的Class组件
@Component
export default class HelloWorld extends Super {
  created() {
    console.log(this.superValue) // -> Hello
  }
}

注意 名为Super的Class组件必须是一个Class组件. 换句话说, 它需要继承作为原本的Vue构造器以及被 @Component 装饰器装饰.

Mixins

Vue Class Component 提供 mixins 助手函数来在Class风格中使用 mixins. 通过使用mixins助手, TypeScript 可以推断mixin类型以及在组件类型中继承它们.

例子中定义了名为HelloWorld 的 mixins :

代码语言:javascript
复制
// mixins.js
import Vue from 'vue'
import Component from 'vue-class-component'

// 你可以定义和组件风格一样的 mixins .
@Component
export class Hello extends Vue {
  hello = 'Hello'
}

@Component
export class World extends Vue {
  world = 'World'
}

在Class组件中使用它们:

代码语言:javascript
复制
import Component, { mixins } from 'vue-class-component'
import { Hello, World } from './mixins'

// 使用 `mixins` 助手函数代替 `Vue`.
// `mixins` 可以接收任何数量的参数.
@Component
export class HelloWorld extends mixins(Hello, World) {
  created () {
    console.log(this.hello + ' ' + this.world + '!') // -> Hello World!
  }
}

和名为Super的Class组件一样, 所有的mixins 必须被定义为一个 Class 组件.

Class 组件的注意事项

Vue Class Component 收集Class属性作为Vue实例的data, 通过在引擎下实例化原始的构造器. 当我们能像原生Class方法一样定义实例data时, 我们需要了解它时如何工作的.

在属性中初始化this的值

如果你在类的属性中定义一个箭头函数, 箭头函数中访问 this 时, 将无法获取实例. 这是因为当初始化Class属性时, this仅仅时Vue实例的代理:

代码语言:javascript
复制
import Vue from 'vue'
import Component from 'vue-class-component'

@Component
export default class MyComp extends Vue {
  foo = 123

  // 不要这么做
  bar = () => {
    // 不能这样更新属性
    // 事实上`this` 不是Vue实例.
    this.foo = 456
  }
}

在下面的例子中, 你可以简单的定义一个方法代替一个Class属性, 因为Vue将自动绑定实例:

代码语言:javascript
复制
import Vue from 'vue'
import Component from 'vue-class-component'

@Component
export default class MyComp extends Vue {
  foo = 123

  bar() {
    // 正确的更新属性
    this.foo = 456
  }
}

通常使用生命周期函数代替 constructor

由于原始构造函数被调用来收集初始组件数据, 建议不要自己声明 constructor:

代码语言:javascript
复制
import Vue from 'vue'
import Component from 'vue-class-component'

@Component
export default class Posts extends Vue {
  posts = []

  // 不要这么做
  constructor() {
    fetch('/posts.json')
      .then(res => res.json())
      .then(posts => {
        this.posts = posts
      })
  }
}

上面的代码打算在组件初始化的时候用fetch来获取post列表, 但是fetch将会被调用两次, 因为Vue Class Component的运作

所以推荐写在生命周期函数里, 比如用created 代替 constructor:

代码语言:javascript
复制
import Vue from 'vue'
import Component from 'vue-class-component'

@Component
export default class Posts extends Vue {
  posts = []

  // 这样做才对哦
  created() {
    fetch('/posts.json')
      .then(res => res.json())
      .then(posts => {
        this.posts = posts
      })
  }
}

Props 定义

Vue Class Component没有提供用于 props 定义的专用API, 当然, 你可以使用Vue.extend API来做到这个:

代码语言:javascript
复制
<template>
  <div>{{ message }}</div>
</template>

<script lang="ts">
import Vue from 'vue'
import Component from 'vue-class-component'

// 使用Vue的经典方法定义props
const GreetingProps = Vue.extend({
  props: {
    name: String
  }
})

// 通过扩展GreetingProps来定义 props
@Component
export default class Greeting extends GreetingProps {
  get message(): string {
    // this.name will be typed
    return 'Hello, ' + this.name
  }
}
</script>

Vue.extend 推算定义的 prop 的类型, 可以通过扩展它来在你的Class组件中使用.

如果你有一个名为super的Class组件或者mixins来扩展, 使用 mixins 助手来关联定义的props:

代码语言:javascript
复制
<template>
  <div>{{ message }}</div>
</template>

<script lang="ts">
import Vue from 'vue'
import Component, { mixins } from 'vue-class-component'
import Super from './super'

// 使用Vue的经典方法定义props
const GreetingProps = Vue.extend({
  props: {
    name: String
  }
})

// 使用 `mixins` 助手来关联定义props 和一个 mixin.
@Component
export default class Greeting extends mixins(GreetingProps, Super) {
  get message(): string {
    // this.name will be typed
    return 'Hello, ' + this.name
  }
}
</script>

Property Type Declaration

有时候, 你需要在Class组件外定义组件属性和方法. 例如, Vuex, Vue的状态管理库,提供 mapGettersmapActions 助手来映射一个存储到组件属性和方法. 这些助手函数需要在组件对象的选项中使用.

甚至在这个例子中, 你可以将组件选项作为@Component 装饰器的参数. 然而, 在运行时方式工作时,它不能自动的在类型级别上定义属性和方法

你需要在Class组件里手动的定义它们的类型:

代码语言:javascript
复制
import Vue from 'vue'
import Component from 'vue-class-component'
import { mapGetters, mapActions } from 'vuex'

// post 接口
import { Post } from './post'

@Component({
  computed: mapGetters([
    'posts'
  ]),

  methods: mapActions([
    'fetchPosts'
  ])
})
export default class Posts extends Vue {
  // 在类型级别上定义 getters 和 actions的映射.
  // 你或许需要添加 `!` 在属性的名字后
  // 来避免编译错误 (definite assignment assertion).

  // 给映射的posts getter 赋予类型
  posts!: Post[]

  // 给映射的 fetchPosts action 赋予类型
  fetchPosts!: () => Promise<void>

  mounted() {
    // 使用映射的getter 和 action.
    this.fetchPosts().then(() => {
      console.log(this.posts)
    })
  }
}

$refs 类型扩展

$refs组件的类型声明为处理所有可能的ref类型的最广泛的类型. 虽然从理论上来它是收集的,但在大多数情况下,每个ref在实践中仅具有特定的元素或组件.

通过在Class组件里重写$refs类型, 你可以指定一个特定的 ref 类型:

代码语言:javascript
复制
<template>
  <input ref="input">
</template>

<script lang="ts">
import Vue from 'vue'
import Component from 'vue-class-component'

@Component
export default class InputFocus extends Vue {
  // 解释 refs 的类型.
  // 符号 `!` (definite assignment assertion)
  // 用来摆脱编译错误.
  $refs!: {
    input: HTMLInputElement
  }

  mounted() {
    // 使用 `input` ref 不用抛出类型
    this.$refs.input.focus()
  }
}
</script>

你可以访问 input 类型而不用抛出类型, 因为在上面示例中, 在Class组件上指定了$refs.input 的类型.

注意, 需要一个类型注解(使用符号 :) 而不是赋值(=).

Hooks Auto-complete

Vue Class Component 提供内建的钩子类型, 这将自动应用在Class组件中定义的 data, render 和 其他生命周期钩子上, 对于 TypeScript. 使用它, 你需要引入位于vue-class-component/hooks的钩子类型.

代码语言:javascript
复制
// main.ts
import 'vue-class-component/hooks'
import Vue from 'vue'
import App from './App.vue'

new Vue({
  render: h => h(App)
}).$mount('#app')

如果你想让它可以应用在自定义钩子上, 你可以自己手动添加:

代码语言:javascript
复制
import Vue from 'vue'
import { Route, RawLocation } from 'vue-router'

declare module 'vue/types/vue' {
  // 增强组件实例的类型
  interface Vue {
    beforeRouteEnter?(
      to: Route,
      from: Route,
      next: (to?: RawLocation | false | ((vm: Vue) => void)) => void
    ): void

    beforeRouteLeave?(
      to: Route,
      from: Route,
      next: (to?: RawLocation | false | ((vm: Vue) => void)) => void
    ): void

    beforeRouteUpdate?(
      to: Route,
      from: Route,
      next: (to?: RawLocation | false | ((vm: Vue) => void)) => void
    ): void
  }
}
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 总览
  • 安装
    • Vue CLI 安装
      • 手动安装
        • npm
        • Build Setup
      • CDN
        • 不同的打包方式
        • Class 组件
          • Data
            • Methods
              • Computed Properties
                • Hooks
                  • 其他选项
                  • 额外的钩子
                  • 自定义装饰器
                  • 扩展 和 Mixins
                    • 扩展
                      • Mixins
                      • Class 组件的注意事项
                        • 在属性中初始化this的值
                          • 通常使用生命周期函数代替 constructor
                          • Props 定义
                          • Property Type Declaration
                          • $refs 类型扩展
                          • Hooks Auto-complete
                          相关产品与服务
                          内容分发网络 CDN
                          内容分发网络(Content Delivery Network,CDN)通过将站点内容发布至遍布全球的海量加速节点,使其用户可就近获取所需内容,避免因网络拥堵、跨运营商、跨地域、跨境等因素带来的网络不稳定、访问延迟高等问题,有效提升下载速度、降低响应时间,提供流畅的用户体验。
                          领券
                          问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档