In Vue2. X, the props properties of the parent component cannot be changed in the child component and propagating to the parent component. However, there are some problems when we want to implement some custom components. Then you must determine the child node based on the state of the parent node.
Although bidirectional data streaming is officially recommended, there are a few ways to avoid error reporting, implement, or hack bidirectional data streaming:
Event Bus / Vuex
The easiest thing to do would be to manage our variables through state management, but it would be too wasteful for parent-child interactions with uncomplicated data flows, so we usually don’t give it much thought, especially with basic components like popup/Checkbox.
Use the Object
The value of an Object is its memory address. Changing only the internal value of an Object without changing the address will not cause an error.
Use event-emit processing
$emit(‘eventName’, value); this.$emit(‘eventName’, value); Bind @event-name to the parent component and modify the value in the function. But if it’s an input base component, it’s crazy to write functions.
v-model
Fortunately, we also have a syntactic sugar called v-model: A V-model is equivalent to giving a prop named value to a child component, which then accepts an input event from the child and assigns a value to the corresponding variable of the parent component.
So we need to do the following things:
- The child component definition is named
value
的prop
值 - Send when the parent component value needs to be changed
input
Events.
But in the child component we need to change a value scoped to the child component before we can use the listener, so we bind a _value and then we can use the V-model in the parent component. :
computed: { _value: { get() { return this.value; }, set(val) { this.$emit('input', val); this.$emit('change', val); }}Copy the code
A complete base component code:
<template> <label class="radio"> <input type="radio" :name="name" v-model="_value" :value="label" :disabled="disabled"> <div>{{ text }}</div> </label> </template> <style lang="scss" scoped> .radio { display: block; height: 50px; margin-bottom: 10px; input[type=radio] { display: none; } div { position: relative; line-height: 30px; top: -10px; right: 20px; } div:after { position: relative; right: -20px; top: 10px; transition: .1s; } input[type=radio] + div:after { content: ''; display: inline-block; border: 1px solid #b3bbc2; height: 30px; width: 30px; border-radius: 50%; } input[type=radio]:checked + div:after { border: 10px solid #7ebcff; height: 30px; width: 30px; } } </style> <script> export default { name: 'CustomRadio', props: { value: { type: [ Boolean, String, Number ] }, text: { type: String, required: false }, name: { type: String, default: '' }, disabled: { type: Boolean, required: false, default: false }, label: { type: [ Boolean, String, Number ], required: false } }, computed: { _value: { get() { return this.value; }, set(val) { this.$emit('input', val); this.$emit('change', val); }}}}; </script>Copy the code