组件系统作为Vue最重要的部分之一,多人协作开发的时候,写好一个可复用的组件灰常重要,别的同事用到你写的组件的时候会觉得:“诶,这个小伙汁有点东西!”
- 如果不用v-model,在原生input标签上怎么实现双向绑定呢?
<template>
<input :value="text" @input="handler" />
</template>
<script>
export default {
name: 'customInput',
data () {
return {
text: 'message'
}
},
methods: {
handler (event) {
// 这里有个点要注意一下,v-model不会处理输入法组合文字过程中得到更新
if (event.target.composing) return
this.text = event.target.value
}
}
}
</script>
这里有个点要注意一下,对于input标签,v-model不会处理输入法组合文字过程中得到更新
文档地址,如果对源码感兴趣可以参考这里
v-model就是上面操作的语法糖
- 下面我们来实现一个简单的星级组件并兼容v-model
<template>
<div class="component-star" @click.stop="">
<ul class="star-list">
<li v-for="(item, index) in list" :key="index" @click="change(index)">{{item}}</li>
</ul>
<span class="label">{{label}}</span>
</div>
</template>
<script>
export default {
name: 'myStar',
props: {
value: { // 必须是value属性,名字不能变
type: [Number, String],
required: true
}
},
data () {
return {
}
},
computed: {
list () {
return '★★★★★☆☆☆☆☆'.slice(5 - this.value, 10 - this.value).split('')
},
label () {
const arr = ['1星', '2星', '3星', '4星', '5星']
return arr[this.value - 1]
}
},
watch: {
},
methods: {
// 当星级变化
change (val) {
let num = val + 1
this.$emit('input', num) // 必须是input事件
}
}
}
</script>
<style lang="less">
.component-star {
.star-list {
display: inline-flex;
font-size: 20px;
li {
cursor: pointer;
margin-right: 5px;
color: #f7ba2a;
transform: scale(1);
transition: transform .1s linear;
&:hover {
transform: scale(1.3);
}
}
}
}
</style>
有两个关键的地方:
1、组件的props中必须要定义value属性
2、当值变化后,一定要用input事件回传修改后的值
写好注册就可以在任意组件中使用了
<template>
<div class="parent">
<my-star v-model="star"></my-star>
</div>
</template>
<script>
export default {
name: 'parent',
data () {
return {
star: 3
}
},
watch: {
star (val) {
console.log(val)
}
}
}
</script>
那么问题来了:如果我编写的组件内部还有一个使用v-model的组件怎么办呢?
比如刚才的组件我想在element提供的el-rate组件基础上做一层封装,只需要把"v-model"替换为":value",这样功能即可正常使用。(当然,如果你是按需加载element组件的话,不要忘了先注册组件)
<template>
<div class="component-star" @click.stop="">
<!--只需要把v-model替换为:value-->
<el-rate :value="value" @change="change" ref="rate"></el-rate>
</div>
</template>
如果报了这个错:
[Vue warn]: Invalid prop: type check failed for prop "value". Expected Number, got String.
说明你传进来的value是个String类型的值,el-rate的value参数只接受Number类型的值,把组件v-model绑定的变量改成数字类型就好了。