vue输入框限制输入_真正输入Vue

2022-10-21 13:25:59

vue输入框限制输入

Logo

inb4: This is not another "setting up" a new project with Vue and TypeScript tutorial. Let's do some deep dive into more complex topics!

inb4:这不是另一个使用Vue和TypeScript教程“设置”新项目的方法。 让我们深入研究更复杂的主题!

typescript is awesome.Vue is awesome. No doubt, that a lot of peopletry to bundle them together. But, due to different reasons, it is hard toreally type yourVue app. Let's find out what are the problems and what can be done to solve them (or at least minimize the impact).

typescript很棒。Vue很棒。 毫无疑问,很多人试图将它们捆绑在一起 。 但是,由于不同的原因,很难真正键入您的Vue应用。 让我们找出问题所在以及可以解决的方法(或至少将影响最小化)。

TLDR(TLDR)

We havethis wonderful template withNuxt,Vue,Vuex, andjest fully typed. Just install it and everything will be covered for you. Goto the docs to learn more.

我们有一个非常漂亮的模板Nuxt完整键入了NuxtVueVuexjest 。 只需安装它,一切将为您覆盖。 转到文档以了解更多信息。

And as I said I am not going to guide you through the basic setup for three reasons:

正如我所说,由于以下三个原因,我不会指导您完成基本设置:

  1. There are a lot of existing tutorials about it

    有很多关于它的现有教程
  2. There are a lot of tools to get started with a single click likeNuxt andvue-cli withtypescript plugin

    有很多的工具,开始使用一个单一的点击喜欢Nuxtvue-clitypescript插件

  3. We already havewemake-vue-template where every bit of setup that I going to talk about is already covered

    我们已经有了wemake-vue-template ,其中我要谈论的所有设置都已涵盖

组件类型(Component typings)

The first broken expectation when you start to work withVue andtypescript and after you have already typed your class components is that<template> and<style> tags are still not typed. Let me show you an example:

当您开始使用Vuetypescript并在键入类组件之后,第一个破破的期望是<template><style>标记仍未键入。 让我给你看一个例子:

<template>
  <h1 :class="$style.headr">
    Hello, {{ usr }}!
  </h1>
</template>

<script lang="ts">
import Vue from 'vue'
import Component from 'vue-class-component'
import { Prop } from 'vue-property-decorator'

@Component({})
export default class HelloComponent extends Vue {
  @Prop()
  user!: string
}
</script>

<style module>
.header { /* ... */ }
</style>

I have made two typos here:{{ usr }} instead of{{ user }} and$style.headr instead of$style.header. Willtypescript save me from these errors? Nope, it won't.

我在这里做了两个错别字:{{ usr }}而不是{{ user }}$style.headr而不是$style.headertypescript会帮助我避免这些错误吗? 不,不会。

What can be done to fix it? Well, there are several hacks.

该如何解决? 好吧,这里有几个技巧。

键入模板(Typing the template)

One can useVetur withvetur.experimental.templateInterpolationService option to type-check your templates. Yes, this is only an editor-based check and it cannot be used inside the CI yet. But,Vetur team is working hard to provide a CLI to allow this. Trackthe original issue in case you are interested.

可以将Veturvetur.experimental.templateInterpolationService选项一起使用,以对模板进行类型检查。 是的,这只是基于编辑器的检查,尚不能在CI中使用。 但是,Vetur团队正在努力提供CLI以允许这样做。 如果您有兴趣,请跟踪原始问题

vetur

The second option is two write snapshot tests withjest. It will catch a lot of template-based errors. And it is quite cheap in the maintenance.

第二种选择是使用jest两次写快照测试。 它将捕获很多基于模板的错误。 而且它在维护上非常便宜。

So, the combination of these two tools provides you a nice Developer Experience with fast feedback and a reliable way to catch errors inside the CI.

因此,这两种工具的结合为您提供了良好的开发人员体验,并提供了快速的反馈和可靠的方式来捕获CI中的错误。

打字风格(Typing styles)

Typingcss-modules is also covered by several external tools:

键入css-module s也可以通过几种外部工具来完成:

The main idea of these tools is to fetchcss-modules and then create.d.ts declaration files out of them. Then your styles will be fully typed. It is still not implemented forNuxt orVue, but you can tractthis issue for progress.

这些工具的主要思想是获取css-module s,然后.d.ts创建.d.ts声明文件。 然后,您的样式将被完全键入。NuxtVue仍未实现该Nuxt ,但是您可以继续解决这个问题

However, I don't personally use any of these tools in my projects. They might be useful for projects with large code bases and a lot of styles, but I am fine with just snapshots.

但是,我并没有在项目中亲自使用任何这些工具。 对于具有大型代码库和许多样式的项目,它们可能很有用,但仅快照就可以了。

Styleguides with visual regression tests also help a lot.@storybook/addon-storyshots is a nice example of this technique.

带有视觉回归测试的样式指南也有很大帮助。@storybook/addon-storyshots是此技术的一个很好的例子。

威克斯(Vuex)

The next big thing isVuex. It has some built-in by-design complexity for typing:

下一件大事是Vuex 。 它具有一些内置的设计复杂性来进行键入:

const result: Promise<number> = this.$store.dispatch('action_name', { payload: 1 })

The problem is that'action_name' might no exist, take other arguments, or return a different type. That's not something you expect for a fully-typed app.

问题在于'action_name'可能不存在,采用其他参数或返回其他类型。 对于全类型应用程序,这不是您期望的。

What are the existing solutions?

现有的解决方案是什么?

Vuex级(vuex-class)

vuex-class is a set of decorators to allow easy access from your class-based components to theVuex internals.

vuex-class是一组装饰器,可让您轻松地从基于类的组件访问Vuex内部。

But, itis not typed safe since it cannot interfere with the types of state, getters, mutations, and actions.

但是,它的类型不安全,因为它不会干扰状态,吸气剂,突变和动作的类型。

vuex-class

Of course, you can manually annotate types of properties.

当然,您可以手动注释属性类型。

vuex-class annotated

But what are you going to do when the real type of your state, getters, mutations, or actions will change? You will have a hidden type mismatch.

但是,当状态,吸气剂,突变或动作的真实类型发生变化时,您将怎么办? 您将遇到隐藏的类型不匹配。

简单的vuex(vuex-simple)

That's wherevuex-simple helps us. It actually offers a completely different way to write yourVuex code and that's what makes it type safe. Let's have a look:

这就是vuex-simple帮助我们的地方。 实际上,它提供了一种完全不同的方式来编写Vuex代码,这就是使其安全的原因。 我们来看一下:

import { Action, Mutation, State, Getter } from 'vuex-simple'

class MyStore {

  // State

  @State()
  public comments: CommentType[] = []

  // Getters

  @Getter()
  public get hasComments (): boolean {
    return Boolean(this.comments && this.comments.length > 0)
  }

  // Mutations

  @Mutation()
  public setComments (payload: CommentType[]): void {
    this.comments = updatedComments
  }

  // Actions

  @Action()
  public async fetchComments (): Promise<CommentType[]> {
    // Calling some API:
    const commentsList = await api.fetchComments()
    this.setComments(commentsList) // typed mutation
    return commentsList
  }
}

Later this typed module can be registered inside yourVuex like so:

以后,可以像下面这样在您的Vuex内部注册该类型的模块:

import Vue from 'vue'
import Vuex from 'vuex'
import { createVuexStore } from 'vuex-simple'

import { MyStore } from './store'

Vue.use(Vuex)

// Creates our typed module instance:
const instance = new MyStore()

// Returns valid Vuex.Store instance:
export default createVuexStore(instance)

Now we have a 100% nativeVuex.Store instance and all the type information bundled with it. To use this typed store in the component we can write just one line of code:

现在,我们有了一个100%本机Vuex.Store实例,并捆绑了所有类型信息。 要在组件中使用这种类型的存储,我们可以只编写一行代码:

import Vue from 'vue'
import Component from 'nuxt-class-component'
import { useStore } from 'vuex-simple'

import MyStore from './store'

@Component({})
export default class MyComponent extends Vue {
  // That's all we need!
  typedStore: MyStore = useStore(this.$store)

  // Demo: will be typed as `Comment[]`:
  comments = typedStore.comments
}

Now we have typedVuex that can be safely used inside our project. When we change something inside our store definition it is automatically reflected to the components that use this store. If something fails — we know it as soon as possible.

现在,我们输入了可以在项目中安全使用的Vuex 。 当我们在商店定义中更改某些内容时,它会自动反映到使用该商店的组件中。 如果出现故障-我们会尽快知道。

There are also different libraries that do the same but have different API. Choose what suits you best.

也有不同的库执行相同的操作,但具有不同的API。 选择最适合您的东西。

API调用(API calls)

When we haveVuex correctly setup, we need to fill it with data. Let's have a look at our action definition again:

正确设置Vuex ,需要用数据填充它。 让我们再次看一下我们的动作定义:

@Action()
public async fetchComments (): Promise<CommentType[]> {
  // Calling some API:
  const commentsList = await api.fetchComments()
  // ...
  return commentsList
}

How can we know that it will really return a list ofCommentType and not a singlenumber or a bunch ofAuthorType instances?

我们怎样才能知道它真的会返回一个列表CommentType而不是一个单一number或一串AuthorType实例?

We cannot control the server. And the server might actually break the contract. Or we can simply pass the wrongapi instance, make a typo in the URL, or whatever.

我们无法控制服务器。 服务器实际上可能违反合同。 或者,我们可以简单地传递错误的api实例,在URL中输入错误或其他。

How can we be safe? We can use runtime typing! Let me introduceio-ts to you:

我们如何安全? 我们可以使用运行时输入! 让我向您介绍io-ts

import * as ts from 'io-ts'

export const Comment = ts.type({
  'id': ts.number,
  'body': ts.string,
  'email': ts.string,
})

// Static TypeScript type, that can be used as a regular `type`:
export type CommentType = ts.TypeOf<typeof Comment>

What do we do here?

我们在这里做什么?

  1. We define an instance ofts.type with fields that we need to be checked in runtime when we receive a response from server

    我们定义了ts.type的实例,ts.type包含当我们从服务器收到响应时需要在运行时检查的字段

  2. We define a static type to be used in annotation without any extra boilerplate

    我们定义了一个用于注释的静态类型,而无需任何额外的模板

And later we can use it ourapi calls:

然后我们可以使用它通过我们的api调用:

import * as ts from 'io-ts'
import * as tPromise from 'io-ts-promise'

public async fetchComments (): Promise<CommentType[]> {
  const response = await axios.get('comments')
  return tPromise.decode(ts.array(Comment), response.data)
}

With the help ofio-ts-promise, we can return aPromise in a failed state if the response from server does not match ats.array(Comment) type. It really works like a validation.

借助io-ts-promise ,如果服务器的响应与ts.array(Comment)类型不匹配,我们可以以失败状态返回Promise 。 它真的像验证一样工作。

fetchComments()
   .then((data) => /* ... */
   .catch(/* Happens with both request failure and incorrect response type */)

Moreover, return type annotation is in sync with the.decode method. And you cannot put random nonsense there:

此外,返回类型注释与.decode方法同步。 而且您不能在这里随意胡扯:

io-ts

With the combination of runtime and static checks, we can be sure that our requests won't fail because of the type mismatch. But, to be 100% sure that everything works, I would recommend using contract-based testing: have a look atpact as an example. And monitor your app withSentry.

结合运行时检查和静态检查,我们可以确保我们的请求不会因为类型不匹配而失败。 但是,为100%确保一切正常,我建议使用基于合同的测试:以pact为例。 并使用Sentry监视您的应用程序。

Vue路由器(Vue Router)

The next problem is thatthis.$router.push({ name: 'wrong!' }) does not work the way we want to.

下一个问题是this.$router.push({ name: 'wrong!' })无法按照我们想要的方式工作。

I would say that it would be ideal to be warned by the compiler that we are routing to the wrong direction and this route does not exist. But, it is not possible. And not much can be done: there are a lot of dynamic routes, regex, fallbacks, permissions, etc that can eventually break. The only option is to test eachthis.$router call in your app.

我要说的是,最好由编译器警告我们正在朝错误的方向布线,并且该路由不存在。 但是,这是不可能的。 不能做的事情很多:最终可能会破坏很多动态路由,正则表达式,后备,权限等。 唯一的选择是测试应用程序中的每个this.$router调用。

vue-test-utils(vue-test-utils)

Speaking about tests I do not have any excuses not to mention@vue/test-utils that also has some problems with typing.

说到测试,我没有任何借口,更不用说@vue/test-utils ,它在输入方面也存在一些问题。

When we will try to test our new shiny component withtypedStore property, we will find out that we actually cannot do that according to thetypescript:

当我们尝试使用typedStore属性测试新的闪亮组件时,我们会发现实际上无法根据typescript

vue-test-utils

Why does this happen? It happens becausemount() call does not know anything about your component's type, because all components have aVueConstructor<Vue> type by default:

为什么会这样? 发生这种情况是因为mount()调用对您的组件类型VueConstructor<Vue> ,因为默认情况下所有组件都具有VueConstructor<Vue>类型:

vue-constructor

That's where all the problems come from. What can be done? You can usevuetype to produceYouComponent.vue.d.ts typings that will tell your tests the exact type of the mounted component.

那就是所有问题的根源。 该怎么办? 您可以使用vuetype生成YouComponent.vue.d.ts类型,这些类型将告诉您的测试所安装组件的确切类型。

You can also trackthis issue for the progress.

您也可以跟踪此问题以获取进度。

But, I don't like this idea. These are tests, they can fail. No big deal. That's why I stick to(wrapper.vm as any).whatever approach. This saves me quite a lot of time to write tests. But spoils Developer Experience a little bit.

但是,我不喜欢这个主意。 这些是测试,它们可能会失败。 没什么大不了的。 这就是为什么我坚持使用(wrapper.vm as any).whatever方式的原因。 这为我节省了大量时间来编写测试。 但是会破坏开发人员的经验。

Make your own decision here:

在这里做出自己的决定:

  • Usevuetype all the way

    一直使用vuetype

  • Partially apply it to the most important components with the biggest amount of tests and update it regularly

    将其部分应用到具有最多测试量的最重要组件,并定期进行更新
  • Useany as a fallback

    使用any作为后备

结论(Conclusion)

The average level oftypescript support inVue ecosystem increased over the last couple of years:

在过去几年中,Vue生态系统中的typescript支持平均水平有所提高:

  • Nuxt firstly introducednuxt-ts and now shipsts builds by default

    Nuxt首先引入了nuxt-ts ,现在默认情况下提供了ts构建

  • Vue@3 will have improvedtypescript support

    Vue@3将改进typescript支持

  • More 3rd-party apps and plugins will provide type definitions

    更多的第三方应用程序和插件将提供类型定义

But, it is production ready at the moment. These are just things to improve! Writing type-safeVue code really improves your Developer Experience and allows you to focus on the important stuff while leaving the heavy-lifting to the compiler.

但是,目前已经可以生产了。 这些只是需要改进的地方! 编写类型安全的Vue代码确实可以改善您的开发人员体验,并让您可以专注于重要的内容,而无需费力地进行编译。

What are your favourite hacks and tools to typeVue apps? Let's discuss it in the comment section.

您最喜欢键入Vue应用程序的黑客和工具是什么? 让我们在评论部分中讨论它。

翻译自:https://habr.com/en/post/458632/

vue输入框限制输入

  • 作者:cullen2012
  • 原文链接:https://blog.csdn.net/cullen2012/article/details/108485535
    更新时间:2022-10-21 13:25:59