gpt4 book ai didi

typescript - 扩展 vuetify VTextField

转载 作者:行者123 更新时间:2023-12-05 02:55:06 26 4
gpt4 key购买 nike

我正在尝试扩展 vuetify VTextField 组件以创建可重用的 password-field。有许多 Prop 可以控制我们需要改变的组件。 Vuejs 将 prop mutation 视为“反模式”并发出警告。

我已经尝试过声明一个计算属性来覆盖有效的 prop,但它会在网络控制台中抛出有关冲突的警告。

这是一个简单的例子:

import Vue from 'vue'
import { VTextField } from 'vuetify/lib'

export default Vue.extend({
name: 'password-field',
mixins: [VTextField],
data: () => ({
reveal: false
}),
computed: {
function type () {
return this.reveal ? 'text' : 'password'
}
}
})

感觉应该不再使用混合来扩展 VTextField 并有选择地删除我们想要用计算属性替换的 Prop 。最后,我们需要该值是 react 性的,并在 password-field 组件的控制下 -- 由父级控制。

我是不是走错方向了?

已更新

根据 Yom S 提供的专家建议(),我能够创建 VTextField 的自定义扩展。我们采纳了他的建议 #2,一个 SFC 模板化组件。

对于偶然发现该主题的任何其他人,这里是 Typescript 兼容的实现:

<!-- put this in components/password-field.vue -->
<template>
<v-text-field
v-bind="computedProps"
v-on:click:append="reveal = !reveal"
v-on="listeners$"
></v-text-field>
</template>

<script lang="ts">
import Vue from 'vue'
import { VTextField } from 'vuetify/lib'

export default {
name: 'PasswordField',
extends: VTextField,

props: {
label: {
type: String,
default: 'Password'
},
rules: {
type: Array,
default: () => [(v: string) => {
return /((?=.*\d)(?=.*[a-z])(?=.*[!@#$%^&*()?.]).{8,})/i.test(v) ||
'At least 8 char; upper and lowercase, a number and a special char'
}]
}
},

data: () => ({
reveal: false
}),

computed: {
computedProps: function () {
return {
...this.$props,
type: this.reveal ? 'text' : 'password',
appendIcon: this.reveal ? 'mdi-eye' : 'mdi-eye-off'
}
}
}

} as Vue.ComponentOptions<Vue>
</script>

这是一个如何使用这个组件的简单例子

<template>
<v-form v-model="formValid">
<password-field v-model="newPassword/>
<v-btn :disabled="!formValid">Change</v-btn>
</v-form>
</template>

<script lang="ts">
import Vue from 'vue'
import PasswordField from '@/components/password-field.vue'

export default Vue.extend({
name: 'ChangePasswordForm',
data: () => ({
formValid: false,
newPassword: ''
})
})
</script>

最佳答案

如果这个特定的 type 属性是 sync 会很有帮助-有能力的;但由于它不是,您可以通过重新呈现 VTextField 来解决这个问题,同时也从它扩展。

现在,我不能说这是最好的解决方案,因为它有一些缺点,使它成为一个有缺陷的包装器。但它确实根据您的相关要求为您提供所需的东西。

常见缺点:

  • 作用域插槽(例如 appendappend-outer)不会输出预期的元素。

为此,我们将此组件称为“PasswordField”,我们会像这样使用它:

<PasswordField 
label="Enter your password"
:revealed="revealed"
append-outer-icon="mdi-eye"
@click:append-outer="togglePassword" />

append-outer-icon 和图标切换机制应该封装在组件本身中。

下面是实现:

密码字段.js

  • 优点:
    • 稍微简单一些(因为不需要模板)。
    • 编译时间更快,因为它只是一个 JS 文件,无需通过 Vue 模板编译器和 Vue Loader。 (您可以更进一步,将其设为 functional component )。
  • 缺点:
    • 事件监听器似乎不起作用。
import { VTextField } from 'vuetify/lib';

export default {
name: 'PasswordField',
extends: VTextField,

props: {
revealed: {
type: Boolean,
default: false
}
},

render(h) {
const { revealed, ...innerProps } = this.$options.propsData;

return h(VTextField, {
// For some reason this isn't effective
listeners: this.$listeners,

props: {
...innerProps,
type: revealed ? 'text' : 'password'
}
})
}
}

注意这个extends来自基本组件 (VTextField) 并“覆盖”原始的 render 函数,返回自定义虚拟节点 a.k.a. VNode

但是,如前所述,这有一些缺点,无法监听发出的事件。 (我很想知道是否有人对此有解决方案)。

所以,作为最后的手段,让我们实际使用模板和计算 Prop ,字面意思(我们希望 props 部分是唯一要绑定(bind)的属性,减去数据)。

密码字段.vue

  • 优点:
    • 在功能方面更可靠。
    • 事件监听器将正常工作。
    • 当然,SFC 这种方式效果最好。
  • 缺点:
    • 有些重复,因为您必须手动(重新)绑定(bind) Prop 和注册事件。
    • 较慢的编译时间(无论如何应该很难注意到)。
<template>
<v-text-field
v-bind="computedProps"
v-on="$listeners">
</v-text-field>
</template>

<script>
import { VTextField } from 'vuetify/lib';

export default {
name: 'PasswordField',
extends: VTextField,

props: {
revealed: {
type: Boolean,
default: false
}
},

computed: {
computedProps() {
return {
...this.$props,
type: this.revealed ? 'text' : 'password'
}
}
}
}
</script>

希望对您有所帮助!

关于typescript - 扩展 vuetify VTextField,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61479853/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com