深入了解vue自定义组件之Prop

Prop就是在组件上自定义的特性
官方文档

基本使用方式

子组件:PropDemo.vue

<template>
    <div>
        <p>{{myMsg}}</p>
    </div>
</template>

<script>
    export default {
        name: "PropDemo",
        props: {
            myMsg: {
                type: String,
                // 默认值,没有传入msg时使用
                default: 'hi prop'
            }
        }
    }
</script>

父组件

<template>
    <div>
        <prop-demo :my-msg="message" />
    </div>
</template>

<script>
    import PropDemo from '@/components/PropDemo'

    export default {
        name: "home",
        components: {
            PropDemo
        },
        data: () => ({
            message: 'hi vue.js'
        })
    }
</script>

标题Prop类型

props: {
    myMsg: {
        type: String,//字符串
        // 默认值,没有传入msg时使用
        default: 'hi prop'
    },
    count: Number,//数字
    isVueAwesome: Boolean,//布尔
    ids: Array,//数组
    author: Object,//对象
    callback: Function//函数
}

除了上述的类型外,还可以通过构造函数自定义一个类型

function Person (firstName, lastName) {
  this.firstName = firstName
  this.lastName = lastName
}
props: {
    author: Person
}

单向数据流

所有的prop都是由父组件绑定到子组件,父组件更新prop,子组件会马上刷新数据;
子组件不应该修改prop,否则会改变父组件中的数据,导致数据流变得混乱,难以理解。
如果子组件中需要修改prop,vue推荐了两种方式

  1. 在子组件的data中定义一个属性,将需要修改的prop用作其初始值

    props: ['initialCounter'],
    data: function () {
      return {
        counter: this.initialCounter
      }
    }
    
  2. 使用prop作为初始值定义一个计算属性

    props: ['size'],
    computed: {
      normalizedSize: function () {
        return this.size.trim().toLowerCase()
      }
    }
    

单向数据流反面例子下面的代码是不推荐的

子组件

<template>
    <div>
        <p>{{author.name}} is {{author.feature}}</p>
    </div>
</template>

<script>
    export default {
        name: "PropDemo",
        props: {
            author: {
                type: Object,//对象
                default: function () {
                    return {
                        name: 'vue',
                        feature: 'awesome'
                    }
                }
            }
        },
        mounted() {
       		 //子组件中更新prop数据,会导致父组件中的数据发生无法预料的结果
            this.author.name = 'vuejs'
        }
    }
</script>

父组件

<template>
    <div>
        //由于子组件修改的prop,这里并不会按照预期出现vue
        <p>{{author.name}}</p>
        <prop-demo  :author="author" />
    </div>
</template>

<script>
    import PropDemo from '@/components/PropDemo'

    export default {
        name: "home",
        components: {
            PropDemo
        },
        data: () => ({
            author: {
                name: 'vue',
                feature: 'Powerful'
            }
        })
    }
</script>

标题Prop 验证

建议每一个prop都添加预期的条件
比如已经知道一个prop是一个布尔类型的属性,就应该通过下面方式添加类型

props: {
	isVueAwesome: Boolean
}

或者

props: {
	isVueAwesome: {
		type: Boolean	
	}
}

更多的需求验证方式

props: {
    // 基础的类型检查 (`null` 和 `undefined` 会通过任何类型验证)
    propA: Number,
    // 多个可能的类型
    propB: [String, Number],
    // 必填的字符串
    propC: {
      type: String,
      required: true
    },
    // 带有默认值的数字
    propD: {
      type: Number,
      default: 100
    },
    // 带有默认值的对象
    propE: {
      type: Object,
      // 对象或数组默认值必须从一个工厂函数获取
      default: function () {
        return { message: 'hello' }
      }
    },
    // 自定义验证函数
    propF: {
      validator: function (value) {
        // 这个值必须匹配下列字符串中的一个
        return ['success', 'warning', 'danger'].indexOf(value) !== -1
      }
    }
  }

当 prop 验证失败的时候,(开发环境构建版本的) Vue 将会产生一个控制台的警告。

非prop的特性

非prop特性指的就是使用子组件的时候传入一个属性,但是子组件内部并没有定义这个属性

替换和合并

下面这段代码中prop-demo标签中的class和style是最常见的属性,但是prop-demo组件中并没有定义这两个prop,所以他们就属于非prop的特性

<template>
    <div>
        <prop-demo class="color-red" style="font-size: 20px"  />
    </div>
</template>

虽然没有定义class和style属性,但是vue并不会抛弃他们,而是将他们加到这个组件的根元素上,与根元素的样式合并使用
但是并不是所有的非prop属性都会合并
假如prop-demo的模板根元素是input,定义了属性type为number

<template>
    <input type="number" />
</template>

而父组件中也传入了一个type为date,这是传入的type会替换掉子组件中的type,所以input的最终类型为date

<template>
    <div>
        <prop-demo type="date" />
    </div>
</template>
禁用特性继承

可以通过下面方式禁用根元素继承特性(class和style除外

<script>
    export default {
        inheritAttrs: false,//禁用根元素继承特性
        name: "PropDemo"
    }
</script>

禁用根元素继承特性更多的是和$attrs配合使用
$attrs可以选择子控件中的那个元素来继承父组件传入的特性(class和style除外
父组件

<template>
    <div>
        <prop-demo placeholder='Enter your age'/>
    </div>
</template>

子元素

<template>
    <div>
        <input type='number' v-bind='$attrs' />
    </div>
</template>

子元素的根元素为div,显然它不需要placeholder这个属性,而input需要
只需要在input标签中添加v-bind="$attrs"即可
在使用子组件的时候可以想html原生组件一样,不需要关系根元素是什么元素

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
回答: 在Vue中,我们可以通过自定义组件的v-model来实现双向数据绑定。默认情况下,v-model在组件上使用modelValue作为prop,并以update:modelValue作为对应的事件。可以通过给v-model指定一个参数来更改这些名字。例如,可以这样使用自定义组件v-model:`<MyComponent v-model:title="bookTitle" />`\[1\]。 另一种实现v-model的方式是使用一个可写的计算属性,同时具有getter和setter。getter方法返回modelValue prop的值,而setter方法触发相应的事件。下面是一个示例组件的代码: ```javascript // CustomInput.vue <script> export default { props: \['modelValue'\], emits: \['update:modelValue'\], computed: { value: { get() { return this.modelValue }, set(value) { this.$emit('update:modelValue', value) } } } } </script> <template> <input v-model="value" /> </template> ``` 通过这种方式,我们可以在自定义组件中使用v-model来实现双向数据绑定\[2\]。 此外,组件的v-model上添加的修饰符可以通过modelModifiers prop在组件内访问到。在组件中声明modelModifiers prop,并将其默认值设置为一个空对象。通过这种方式,我们可以在组件中访问到v-model的修饰符。例如,在下面的组件中,我们声明了modelModifiers这个prop,并在created钩子函数中打印出了modelModifiers的值: ```javascript <script> export default { props: { modelValue: String, modelModifiers: { default: () => ({}) } }, emits: \['update:modelValue'\], created() { console.log(this.modelModifiers) // { capitalize: true } } } </script> <template> <input type="text" :value="modelValue" @input="$emit('update:modelValue', $event.target.value)" /> </template> ``` 通过这种方式,我们可以在自定义组件中使用v-model的修饰符\[3\]。 #### 引用[.reference_title] - *1* *2* *3* [Vue 自定义组件中 v-model 的使用](https://blog.csdn.net/qq_40179479/article/details/126564499)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

bdawn

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值