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

本文探讨了Vue与TypeScript的深度整合,包括组件、Vuex、API调用及Vue路由器的类型安全实践,提出了使用Vetur、jest、vuex-simple、io-ts等工具和方法提升开发体验。

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 people try to bundle them together. But, due to different reasons, it is hard to really type your Vue 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 have this wonderful template with Nuxt, Vue, Vuex, and jest fully typed. Just install it and everything will be covered for you. Go to 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 like Nuxt and vue-cli with typescript plugin

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

  3. We already have wemake-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 with Vue and typescript 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. Will typescript 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 use Vetur with vetur.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. Track the original issue in case you are interested.

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

vetur

The second option is two write snapshot tests with jest. 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)

Typing css-modules is also covered by several external tools:

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

The main idea of these tools is to fetch css-modules and then create .d.ts declaration files out of them. Then your styles will be fully typed. It is still not implemented for Nuxt or Vue, but you can tract this 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 is Vuex. 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 the Vuex internals.

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

But, it is 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 where vuex-simple helps us. It actually offers a completely different way to write your Vuex 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 your Vuex 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% native Vuex.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 typed Vuex 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 have Vuex 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 of CommentType and not a single number or a bunch of AuthorType instances?

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

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

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

How can we be safe? We can use runtime typing! Let me introduce io-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 of ts.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 our api 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 of io-ts-promise, we can return a Promise in a failed state if the response from server does not match a ts.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 at pact as an example. And monitor your app with Sentry.

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

Vue路由器 (Vue Router)

The next problem is that this.$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 each this.$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 with typedStore property, we will find out that we actually cannot do that according to the typescript:

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

vue-test-utils

Why does this happen? It happens because mount() call does not know anything about your component's type, because all components have a VueConstructor<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 use vuetype to produce YouComponent.vue.d.ts typings that will tell your tests the exact type of the mounted component.

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

You can also track this 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:

在这里做出自己的决定:

  • Use vuetype all the way

    一直使用vuetype

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

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

    使用any作为后备

结论 (Conclusion)

The average level of typescript support in Vue ecosystem increased over the last couple of years:

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

  • Nuxt firstly introduced nuxt-ts and now ships ts builds by default

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

  • Vue@3 will have improved typescript 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-safe Vue 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 type Vue apps? Let's discuss it in the comment section.

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

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

vue输入框限制输入

<think>好的,我现在需要帮用户解决Vue输入框无法输入或延迟输入的问题。首先,我得回忆一下常见的可能原因。用户可能用的是v-model绑定数据,所以第一个想到的是v-model的使用是否正确。比如,是否在data中正确定义了对应的变量,或者是否在自定义组件中使用时需要处理modelValue和update事件。 接下来,如果用户的数据绑定正确,那可能问题出在输入事件的处理上。比如,是否用了@input或者@change,而事件处理函数中有比较耗时的操作,导致输入延迟。这时候需要检查是否有不必要的计算或者网络请求在输入时触发,可能需要用防抖或节流来优化。 另外,如果用户自己封装了输入框组件,有没有正确触发input事件?有时候自定义组件可能需要显式地emit事件,否则v-model无法正确更新数据。比如在子组件里,输入的时候需要$emit('input', event.target.value),否则父组件的数据不会更新,导致看起来无法输入。 还有可能是表单验证库的影响,比如Vuelidate或VeeValidate,这些库可能在输入时进行实时验证,如果验证逻辑复杂,可能会导致延迟。需要检查验证规则是否有性能问题,或者是否在输入时频繁触发验证。 另外,如果使用了第三方UI库,比如Element UI或Vant,这些库的输入框组件可能有自己的处理逻辑,或者需要特定的prop和event。比如,是否漏掉了某些必要的prop,或者事件没有正确绑定。这时候需要查阅对应UI库的文档,确认使用方式是否正确。 还有一个可能性是Vue的响应式系统问题。比如,数据可能没有被正确声明为响应式,或者在更新数组或对象时没有使用Vue.set方法,导致视图不更新。这种情况下,输入框的值变化了,但视图没有同步,看起来像是无法输入。 另外,浏览器或设备的兼容性问题也可能导致输入延迟,比如在移动端某些情况下输入法处理慢。这时候需要测试不同的环境和设备,确认问题是否普遍存在。 最后,如果以上都排除了,可能需要检查是否有其他代码干扰,比如全局的事件监听器、自定义指令,或者CSS样式导致输入框被遮挡或禁用。比如,z-index问题让输入框无法获取焦点,或者pointer-events被设置为none。 总结下来,解决步骤大致是:检查v-model绑定是否正确,确认事件处理是否高效,查看自定义组件的事件触发,排除第三方库的影响,验证响应式数据是否正确处理,检查兼容性和样式问题。可能需要用户提供更多代码细节,或者逐步排查这些可能性。</think>关于Vue输入框无法输入或延迟输入的问题,以下是分步骤排查和解决方案: --- ### 一、基础检查:v-model绑定 1. **变量未声明响应式** ```javascript // ❌ 错误:未在data中声明会导致绑定失效 export default { methods: { init() { this.inputValue = "" // 非响应式 } } } // ✅ 正确:在data中声明 export default { data() { return { inputValue: "" // 响应式变量 } } } ``` 2. **自定义组件未正确处理model** 封装输入框组件时需显式传递值和事件: ```javascript // 子组件 <input :value="modelValue" @input="$emit('update:modelValue', $event.target.value)" > export default { props: ['modelValue'] } ``` --- ### 二、输入事件优化 1. **避免在@input中执行高耗时操作** ```javascript // ❌ 错误:频繁触发复杂计算 <input @input="handleHeavyCalculation"> // ✅ 正确:使用防抖(lodash.debounce) methods: { handleInput: debounce(function(e) { // 逻辑代码 }, 300) } ``` 2. **检查第三方表单验证库** 如使用Vuelidate/VeeValidate时: ```javascript // 验证规则可能导致延迟 validations: { inputValue: { required, complexRule: (value) => /* 耗时校验逻辑 */ } } ``` **优化方案**:将实时验证改为失焦验证(@blur) --- ### 三、第三方UI库问题 常见于Element UI、Vant等组件: ```html <!-- Element UI需确认是否缺少native修饰符 --> <el-input @input.native="handleInput"></el-input> <!-- Vant需检查v-model是否绑定到正确prop --> <van-field v-model="value" :value="value" /> <!-- 重复绑定可能导致冲突 --> ``` --- ### 四、响应式数据更新问题 1. **对象/数组未正确更新** ```javascript // ❌ 错误:直接修改数组元素 this.list[0] = newValue // ✅ 正确:使用Vue.set或展开运算符 Vue.set(this.list, 0, newValue) // 或 this.list = [...this.list] ``` 2. **异步更新导致延迟** 使用`this.$nextTick`确保DOM更新后操作: ```javascript this.inputValue = "new value" this.$nextTick(() => { // 操作更新后的DOM }) ``` --- ### 五、其他潜在问题 1. **CSS干扰** 检查是否隐藏或禁用输入框: ```css /* 错误样式示例 */ .my-input { pointer-events: none; /* 阻止交互 */ z-index: -1; /* 被其他元素遮挡 */ } ``` 2. **浏览器兼容性** 测试不同浏览器,尤其是旧版本IE或移动端WebView。 --- ### 六、调试工具 1. 使用Vue Devtools检查数据流 2. 通过Chrome Performance面板分析输入事件耗时 --- 通过以上步骤逐步排查,90%的输入问题可定位解决。如果仍存在问题,建议提供具体代码片段进一步分析。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值