use*_*028 5 typescript vue.js vuetify.js
我正在尝试扩展 vuetifyVTextField组件来创建可重用的password-field. 有许多道具可以控制我们需要改变的组件。Vuejs 认为 prop 突变是一种“反模式”,并对其发出警告。
我尝试过声明一个计算属性来覆盖有效的 prop,但它会在 Web 控制台中抛出有关冲突的警告。
这是一个简单的例子:
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'
}
}
})
Run Code Online (Sandbox Code Playgroud)
感觉应该可以使用 mixins 来扩展 VTextField 并有选择地删除我们想要用计算属性替换的 props。最后,我们需要该值是反应性的并且受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>
Run Code Online (Sandbox Code Playgroud)
这是一个如何使用该组件的简单示例
<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>
Run Code Online (Sandbox Code Playgroud)
type如果这个特殊的道具能够实现的话,那将会很有帮助sync;但既然不是,您可以通过重新渲染 来解决这个问题VTextField,同时也可以从它扩展。
现在,我不能说这是最好的解决方案,因为它有一些缺点,使其成为一个有缺陷的包装器。但它确实可以根据您的相关要求满足您的需求。
常见缺点:
append、append-outer)不会输出预期的元素。因此,为了这个目的,我们将该组件称为“PasswordField”,我们将这样使用它:
<PasswordField
label="Enter your password"
:revealed="revealed"
append-outer-icon="mdi-eye"
@click:append-outer="togglePassword" />
Run Code Online (Sandbox Code Playgroud)
图标append-outer-icon切换机制可能应该封装在组件本身内。
实现如下:
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'
}
})
}
}
Run Code Online (Sandbox Code Playgroud)
extends从基本组件 ( ) 中注意到这一点VTextField,并且有点“覆盖”原始render函数,返回自定义的虚拟节点(又称为 )VNode。
然而,如前所述,这有一些缺点,即它无法侦听发出的事件。(我很想知道是否有人有解决方案)。
因此,作为最后的手段,我们实际上使用模板和计算属性(我们希望该props部分是唯一要绑定的属性,减去data)。
<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>
Run Code Online (Sandbox Code Playgroud)
希望能以某种方式有所帮助!
| 归档时间: |
|
| 查看次数: |
6865 次 |
| 最近记录: |