作用
在表单输入元素或组件上创建双向绑定,即表单可以拿到vue中的数据,表单中的数据也可以传到vue中,而v-bind:value 只能是表单拿到vue的数据,vue无法拿到表单的数据
原理
一个组件上的v-model默认会利用名为value的props和名为input的事件
<vx-card-list v-model="policyNoList" ref="list">
<vx-card-item
v-for="(item, index) in PolicyList"
:key="index"
v-model="value"
:name="item.policyNo"
:title="item.riskName"
:status="item.policySts"
:info="item.info"
></vx-card-item>
</vx-card-list>
cardList组件
<template>
<div class="vx-card-list">
<slot />
</div>
</template>
<script>
export default {
name: "vx-card-list",
props: {
//用于接受父组件中v-model绑定的值(policyNoList)
value: {
type: [Array, String],
default: () => ([])
},
},
}
</script>
v-model相当于写两件事情
- v-bind:绑定响应式数据
- 触发oninput 事件并传递数据
<input v-model="sth" />
// 等同于
<input :value="sth" @input="sth = $event.target.value" /> //自html5开始,input每次输入都会触发input事件,所以输入时input的内容会绑定到sth中,于是sth的值就被改变;
//$event 指代当前触发的事件对象;
//$event.target 指代当前触发的事件对象的dom;
//$event.target.value 就是当前dom的value值;
//在@input方法中,value => sth;
//在:value中,sth => value;
举例
场景:父子组件响应式传递数据
父组件
<template>
<div>
<common-input-box name="工单编号" :input.sync="currentBillNum"></common-input-box>
</div>
</template>
<script>
import commonInputBox from '@/common/commonInputBox.vue';
export default{
components:{
commonInputBox
},
}
</script>
子组件commonInputBox.vue
<template>
<view class="input">
<view :class="['input-box',{'input-box-active':titleActive}]">
<view :class="['title',{'title-active':titleActive}]">
<view class="name">
<view v-for="(item,index) in nameArr" :key="index">{{item}}</view>
</view>
<view class="star" v-if="isShowStar">*</view>
</view>
<template>
// input输入框
<input :class="{'grey-bg-color':disabled}" v-if="!titleActive" :disabled=disabled :maxlength="inputLength" placeholder="请输入" v-model.trim="inputValue" @input="getValue">
<textarea :class="{'grey-bg-color':disabled}" v-else placeholder="请输入" :disabled=disabled :maxlength="textLength" v-model.trim="inputValue" @input="getValue"></textarea>
</template>
</view>
</view>
</template>
<script>
export default{
data(){
return{
// 输入框的值
inputValue:this.input
}
},
props:{
// 标题
name:{
type:String,
default:''
},
// 控制flex主轴方向、输入框为单行还是多行(标题和输入框之间有padding)
// true:flex主轴方向为column,输入框为多行,标题和输入框之间的padding
// false:flex主轴方向为row,输入框为单行
titleActive:{
type:Boolean,
default:false
},
// 是否展示*,默认为true(展示)
isShowStar:{
type:Boolean,
default:true
},
// input输入框的最大长度
inputLength:{
type:Number,
default:50
},
// textarea输入框的最大长度
textLength:{
type:Number,
default:50
},
// 接受父组件传过来的值
input:{
type:String,
default:''
},
// 禁用,默认不禁用
disabled: {
type: Boolean,
default: false
},
},
computed:{
// 输入框前面文字没有达到最小宽度时保持两端对齐
nameArr(){
return this.name.split('')
}
},
watch:{
input:{
handler(value){
this.inputValue = value
},
immediate: true
}
},
methods:{
// 通过此方法向父组件抛出输入框的值
getValue(){
this.$emit('update:input',this.inputValue)
}
}
}
</script>
<style lang="scss" scoped>
.input-box-active{
flex-direction: column !important;
}
.title-active{
padding-bottom: 20rpx;
}
.input{
padding-bottom: 28rpx;
}
.input-box{
display: flex;
font-family: $base-fontFamily;
font-weight: 400;
.title{
display: flex;
align-items: center;
font-size: 30rpx;
color: #333333;
.name{
white-space: nowrap;
min-width: 116rpx;
display: flex;
justify-content: space-between;
}
.star{
color: #FF3B3B;
padding: 5rpx 34rpx 0 14rpx;
}
}
input,textarea{
width: 100%;
background: #F7F8FC;
border-radius: 12px;
padding: 26rpx 30rpx;
color: #333333;
font-size: 28rpx;
}
textarea{
height: 225rpx;
box-sizing: border-box;
}
}
</style>