首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >扩展vuetify

扩展vuetify
EN

Stack Overflow用户
提问于 2020-04-28 12:09:36
回答 2查看 4.4K关注 0票数 3

我正在尝试扩展vuetify VTextField组件以创建可重用的password-field。有许多道具可以控制我们需要变异的组件。Vuejs认为道具突变是一种“反模式”,并对此发出警告。

我已经尝试过声明一个覆盖可工作的支柱的计算属性,但是它会在网络控制台中抛出关于冲突的警告。

下面是一个简单的例子:

代码语言:javascript
复制
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,证监会的模板组件。

对于任何偶然发现这个主题的人,下面是与类型记录兼容的实现:

代码语言:javascript
复制
<!-- 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>

下面是如何使用此组件的一个简单示例

代码语言:javascript
复制
<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>
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2020-04-28 17:19:13

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

现在,我不能说这是最好的解决方案,因为它有一些缺点,使它成为一个有缺陷的包装。但它确实让你得到了你所需要的,根据你的要求。

共同缺点:

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

因此,为此,让我们将这个组件称为"PasswordField",我们将使用它如下:

代码语言:javascript
复制
<PasswordField 
  label="Enter your password"
  :revealed="revealed" 
  append-outer-icon="mdi-eye" 
  @click:append-outer="togglePassword" />

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

下面是实现方案:

PasswordField.js

  • 优点:
    • 稍微简单一些(不需要模板)。
    • 编译时间更快,因为它只是一个JS文件,不需要经过Vue模板编译器和Vue Loader。(你可以更进一步,把它变成功能部件)。

  • 缺点:
    • 事件侦听器似乎不起作用。

代码语言:javascript
复制
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

  • 优点:
    • 更可靠,功能更好。
    • 事件侦听器将按其应有的方式工作。
    • 当然,证监会以这种方式运作得最好。

  • 缺点:
    • 有些重复,因为您必须手动(重新)绑定道具和注册事件。
    • 较慢的编译时间(无论如何很难被注意到)。

代码语言:javascript
复制
<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>

希望这在某种程度上有帮助!

票数 4
EN

Stack Overflow用户

发布于 2022-02-22 10:54:22

全码

代码语言:javascript
复制
<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组件:
代码语言:javascript
复制
import { VBtn } from 'vuetify/lib'
  • VTextField扩展组件
代码语言:javascript
复制
export default {
  extends: VBtn,
}

如何扩展模板?

  • v-bind="$props"将绑定所有的道具
  • v-on="$listeners"将绑定所有事件
  • $scopedSlots上循环并重新定义所有作用域槽

示例:

代码语言:javascript
复制
<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对象中重新定义道具,并为它们添加一个默认值

示例在默认情况下使文本字段填充:

代码语言:javascript
复制
props: {
    filled: { default: true },
  }
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/61479853

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档