1. v-model
Implement custom component bidirectional binding
V-model is a syntactic sugar, and writing v-Model will not work if the component is not defined according to the corresponding specification. Again, similar to v-on:click can be shortened to @click, v-model is shorthand for two expressions put together. So keep that in mind, and I’m going to explain it.
1.1 input
Two-way binding
Child component myinput.vue:
<template>
<div>The input<input :value="value" @input="input"/>
</div>
</template>
<script>
export default {
name: "MyInput".props: {
value: {type: [String.Number]}},methods: {
input(e) {
this.$emit('input', e.target.value)
}
}
}
</script>
Copy the code
Used in parent component app.vue:
<template>
<div id="app">
<my-input v-model="haha" />
<div>{{haha}}</div>
</div>
</template>
<script>
import MyInput from '@/components/MyInput'
export default {
name: 'App',
components: { MyInput },
data() {
return {
haha: '66666',
}
}
}
</script>
<style>
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
</style>
Copy the code
<my-input
:value="haha"
@input="onInput"
/>
onInput(e) {
this.haha = e
}
Copy the code
V-model has the same effect. It saves a lot of code by not having to manually assign values to HAHA and defining one less method. The effect is quite obvious.
The value in the MyInput component cannot be called anything else, and the method thrown by $emit can only be called input. Otherwise, the v-model syntax will not work. Otherwise, the $event argument is omitted from the $event.target.value method to obtain the input value.
1.2. checkbox
Two-way binding
The value it binds to is not called value, and the event it triggers is not called input.
MyCheckBox subcomponent code:
<template> <div> <input type="checkbox" :checked="checked" @change="change"/> </div> </template> <script> export default { name: "MyCheckBox", model: { prop: 'checked', event: 'zhuangbi' }, props: { checked: Boolean }, methods: { change(e) { this.$emit('zhuangbi', e.target.checked) } } } </script>Copy the code
Used in parent component app.vue:
<template>
<div id="app">
<my-check-box v-model="changeV"></my-check-box>
<div>{{changeV}}</div>
</div>
</template>
<script>
import MyCheckBox from '@/components/MyCheckBox'
export default {
name: 'App',
components: { MyCheckBox },
data() {
return {
changeV: true,
}
}
}
</script>
Copy the code
Except that the binding value becomes checked, the @input becomes @change, and the argument passed to the parent component is E.target.checked
Note: in most cases, the event emitted by $emit is “change”. I write “zhuangbi”, as long as it has the same value as the event attribute in the model module.
Also, outside props are necessary.
2. .sync
To achieve bidirectional binding
If you need to bind a prop bidirectionally, you can use the.sync syntax sugar. As an example of a usage scenario, someone else’s CheckBox component needs to make some style changes or function combinations to be reused, which requires another bidirectional binding of the V-Model values.
Subcomponent DiyCheckBox code:
<template> <div> <my-check-box v-model="diyCheck" @change="dChange"/> </div> </template> <script> import MyCheckBox from './MyCheckBox' export default { name: "DiyCheckBox", components: {MyCheckBox}, props: { diyCheck: Boolean, test: String }, methods: { dChange(e) { this.$emit('update:diyCheck', e) } } } </script>Copy the code
Used in parent component app.vue:
<template>
<div id="app">
<diy-check-box :diyCheck.sync="dCheck" />
<div>{{dCheck}}</div>
</div>
</template>
<script>
import DiyCheckBox from '@/components/DiyCheckBox'
export default {
name: 'App',
components: { DiyCheckBox },
data() {
return {
dCheck: true,
}
}
}
</script>
Copy the code
: diycheck. sync=”dCheck”
:diyCheck="dCheck"
@update:diyCheck="dCheck = $event"
Copy the code
Syntactic sugar is obvious and greatly simplifies code.
The above code does what you want, but the console has a warning:
[Vue warn]: Avoid mutating a prop directly since the value will be overwritten whenever the parent component re-renders. Instead, use a data or computed property based on the prop's value. Prop being mutated: "diyCheck"
found in
---> <DiyCheckBox> at src/components/DiyCheckBox.vue
<App>
<Root>
Copy the code
Avoid changing props directly, use data or computed instead. So let’s optimize it and write it this way:
<template> <div> <my-check-box v-model="comDiyCheck"/> </div> </template> <script> import MyCheckBox from './MyCheckBox' export default { name: "DiyCheckBox", components: {MyCheckBox}, props: { diyCheck: Boolean, test: String }, computed: { comDiyCheck: { get() { return this.diyCheck }, set(e) { this.$emit('update:diyCheck', e) } } } } </script>Copy the code
$emit = MyCheckBox (); $emit = MyCheckBox (); $emit = MyCheckBox (); $emit = mycheck (); The parent component still has the.sync binding and the code is unchanged.
.sync can not be used to perform bidirectional binding of checkboxes, and can be used to implement bidirectional binding of props.
.sync
Pass the whole object
If there are many props properties that need to be bidirectionally bound, the tag is long, like this:
<coverage-charge
v-for="(item, index) in chargingPiles"
:key="index + 'index'"
:code.sync="item.code"
:address.sync="item.address"
:addressType.sync="item.addressType"
:kind.sync="item.kind"
:yearLimitType.sync="item.yearLimitType"
>
</coverage-charge>
Copy the code
The official document says you can abbreviate it like this:
<text-document v-bind.sync="doc"></text-document>
<! -- our example is: -->
<coverage-charge
v-for="(item, index) in chargingPiles"
:key="index + 'index'"
v-bind.sync='item'
>
</coverage-charge>
Copy the code
Officials also said:
This passes each property (such as title) in the doc object as a separate prop, and then adds a separate V-on listener for updates.
All five attributes of item are passed to the child component via prop, and I can add different computed attributes to the child component:
<script> export default { name: 'CoverageCharge', props: {}, computed: { code: { get() { return this.code }, set(val) { this.$emit('update:code', val) } }, address: { get() { return this.address }, set(val) { this.$emit('update:address', val) } } ... }} </script>Copy the code
This. Code and this. Address are both undefined, so we need to define the props for the subcomponent.
props: [ 'code', 'address', 'addressType', 'kind', 'yearLimitType' ]
Copy the code
That’s it..sync is powerful and has a lot of uses.
If there are too many things in the props, you can also define an object and pass in the parent component via v-bind or v-model:
2.1.1 v-bind
way
<! -- subcomponent --> props: {zb: {
type: Object.default: () = >{}}},computed: {
code: {
get() {
return this.zb.code
},
set(val) {
this.$emit('update:code', val)
}
},
address: {
get() {
return this.zb.address
},
set(val) {
this.$emit('update:address', val)
}
}
}
Copy the code
<! <coverage-charge v-for="(item, index) in chargingPiles" :key="index + 'index'" v-bind.sync='item' :zb='item' > </coverage-charge>Copy the code
2.2.2 v-model
way
<! -- subcomponent --> export default {model: {prop: 'zb', event: 'update'}, props: {zb: {type: Object, default: () => {} } }, computed: { code: { get() { return this.zb.code }, set(val) { this.$emit('update:code', val) } }, address: { get() { return this.zb.address }, set(val) { this.$emit('update:address', val) } } } }Copy the code
<! <coverage-charge v-for="(item, index) in chargingPiles" :key="index + 'index'" v-bind.sync='item' v-model='item' > </coverage-charge>Copy the code
Note that the event value in model is update.
3. v-model
and.sync
To compare
The purpose of the first example in Section 2 above is to wrap the V-Model in another layer, which can be done using the V-Model method as in Section 1. Here only write the main point, not paste the source code:
- define
model
Module:model: {prop: 'checked', event: 'zhuangbi' }
props
Defined in thechecked
attributecomputed
Defined in theMyChecked: {get(){return this.checked}, set(val) {this.$emit('zhuangbi', val)}}
DiyCheckBox
Components used in:<my-check-box v-model="MyChecked"/>
- Used in the parent component:
<diy-check-box v-model=suibian" />
.suibian
Is the parent componentdata
Variables defined in
Sync is used for bidirectional binding of one props (one tag cannot have more than one V-model), and. Sync is used for bidirectional binding of one props (one tag can have more than one :xxx.sync=yyy).
The source code
Click to view source code