我正在尝试扩展vuetify VTextField组件以创建可重用的password-field。有许多道具可以控制我们需要变异的组件。Vuejs认为道具突变是一种“反模式”,并对此发出警告。
我已经尝试过声明一个覆盖可工作的支柱的计算属性,但是它会在网络控制台中抛出关于冲突的警告。
下面是一个简单的例子:
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'
}
}
})感觉应该使用mixins来扩展VTextField,并有选择地删除我们想用计算属性替换的道具。最后,我们需要该值是反应性的,并在password-field组件的控制下--而不是由父组件控制。
我走错方向了吗?
更新
借助Yom S ()提供的专家建议,我能够创建VTextField的自定义扩展。我们同意他的建议#2,证监会的模板组件。
对于任何偶然发现这个主题的人,下面是与类型记录兼容的实现:
<!-- 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>发布于 2020-04-28 17:19:13
如果这个特定的type道具是sync-able,那会很有帮助;但是由于它不是,所以您可以通过重新呈现VTextField来解决这个问题,同时也可以从它扩展。
现在,我不能说这是最好的解决方案,因为它有一些缺点,使它成为一个有缺陷的包装。但它确实让你得到了你所需要的,根据你的要求。
共同缺点:
append、append-outer)不会输出预期的元素。因此,为此,让我们将这个组件称为"PasswordField",我们将使用它如下:
<PasswordField
label="Enter your password"
:revealed="revealed"
append-outer-icon="mdi-eye"
@click:append-outer="togglePassword" />append-outer-icon和图标切换机制可能应该封装在组件本身中。
下面是实现方案:
PasswordField.js
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'
}
})
}
}请注意这个来自基本组件(VTextField)的VTextField,它“重写”了原始的render函数,返回自定义的虚拟节点a.k.a。VNode。
但是,正如前面提到的,这有一些缺点,因为它无法侦听发出的事件。(我很想知道是否有人有办法解决这个问题)。
因此,作为最后的手段,让我们实际使用模板和计算道具,字面意思是(我们希望props部件是唯一绑定到的属性,减去data)。
PasswordField.vue
<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>希望这在某种程度上有帮助!
发布于 2022-02-22 10:54:22
全码
<template>
<v-text-field v-bind="$props" v-on="$listeners" class="custom-class">
<template
v-for="slot in Object.keys($scopedSlots)"
:slot="slot"
slot-scope="scope"
>
<slot :name="slot" v-bind="scope" />
</template>
</v-text-field>
</template>
<script>
import { VTextField } from 'vuetify/lib'
export default {
extends: VTextField,
props: {
filled: { default: true },
},
}
</script>解释
如何扩展一个虚拟组合
让我们以v-text-field为例
VTextField组件:import { VBtn } from 'vuetify/lib'VTextField扩展组件export default {
extends: VBtn,
}如何扩展模板?
v-bind="$props"将绑定所有的道具v-on="$listeners"将绑定所有事件$scopedSlots上循环并重新定义所有作用域槽示例:
<template>
<v-text-field v-bind="$props" v-on="$listeners">
<template
v-for="slot in Object.keys($scopedSlots)"
:slot="slot"
slot-scope="scope"
>
<slot :name="slot" v-bind="scope" />
</template>
</v-text-field>
</template>现在您可以添加自定义类、重写模板或其他任何东西。
如何覆盖默认道具:
props对象中重新定义道具,并为它们添加一个默认值示例在默认情况下使文本字段填充:
props: {
filled: { default: true },
}https://stackoverflow.com/questions/61479853
复制相似问题