preface
Since Vue 0.x, Vue has used v-model to implement bidirectional binding. Since Vue2.0, Vue is no longer bidirectional binding, and what is commonly referred to as double binding only looks like double binding.
The reason is that after the rise of FLUX one-way data flow, the authors of Vue re-examined “two-way binding” and found some problems with “two-way binding”, they preferred “one-way binding”.
The V-Model was split into two parts.
Basic usage
// template
<div id="app">
<h1>{{ name }}</h1>
value: <input type="text" :value="name" /><br/>
v-model: <input type="text" v-model="name" /><br/>The essence of the V-Model:<input type="text" :value="name" @input="inputEvent" /><br/>
<! -- You can also write the methods (methods) directly.
<input type="text" :value="name" @input=" name = $event.target.value " /><br/>
</div>
Copy the code
// script
export default {
data() {
return {
name: "hhh"}; },methods: {
inputEvent(event) {
this.name = event.target.value; ,}}};Copy the code
The page is rendered from the data in the data, when the data in the data changes, the page will automatically update; The page changes only when the data in data is allowed to change while manipulating the page. This is called ‘two-way data binding’, or MVVM.
Contenteditable bug
<! Add the following code to template:
BUG:
<span contenteditable @input="name = $event.target.innerText">
{{ name }}
</span>
Copy the code
Why does my cursor automatically go to the front?
When I type a 1 in a span and the 1 is actually written to the span, the SPAN will trigger the input event and execute name = $event.target.innerText.
When the name changes, the span is re-rendered. Vue remembers the contents of the span, but cannot remember the cursor position.
In this case, when I type 1 for the first time and span is rendered again, the cursor will automatically run to the front (Vue has forgotten the cursor position).
This is the “two-way binding” of Vue, which is actually a one-way binding at {{name}} and a one-way binding at @input=”name = $event.target.innertext “.
1 🌰 chestnut
Bidirectional binding is great if you have only one input, but what about two inputs?When I changed the first input to ‘Jack ‘, someone else changed the other input to’ Tom ‘. Now what are the contents of the two inputs? I’m not sure, because I’m not sure which one changed last.
graph TD
hhh --> tom --> jack
hhh --> jack -->tom
Because of uncertainty, it can lead to strange beginnings or strange outcomes in teamwork.
That’s the problem with bidirectional binding, because your data can be changed by anyone at any time, and you don’t know when it’s changed, you just know it’s not right when you use it. Although the probability of occurrence is low, it will always be a hidden danger.
Low probability events are bound to happen — Murphy’s Law
So two-way binding is OK as long as the sibling elements don’t tamper with each other. Once there are multiple sources that change the data, it becomes uncontrollable.
How to solve it?
A data can only be changed by one component, and whoever owns the data can change the data.
This APP passes the name as data to the two input components for display. These two components are not allowed to change the data, but only display the data.
If the change is to be made, the component must notify the owner of the data (the data in the figure is name), and then the owner of the data will change the data, and the owner will change the two data at the same time (for example, change the two data to Jack).If a component changes this to Tom, the component itself does not change, but notifies the data owner (name), and the component changes to Tom only after the owner changes.
<input type="text"
:value="name"
@input=" name =$event.target.value "/>
Copy the code
data(){
return {
name: 'hhh'}}Copy the code
In this way, the right to change the data goes back to the data owner.
Use a Contenteditable bug to understand one-way data flows.
Small 2 🌰 chestnuts
<input type="text" :value="amount" @input="inputEvent"/>
<input type="text" :value="amount" @input="inputEvent"/>
Copy the code
data() {
return {
amount: 500
};
},
methods: {
inputEvent(event) {
this.amount = event.target.value; }},Copy the code
When changing the value of the first input, it notifies its parent that I want to modify the data, and only with the parent’s consent can it modify the value data.
When do you disagree? Add the condition
data() {
return {
amount: 500
};
},
methods: {
inputEvent(event) {
if( event.target.value > 100) {this.amount = event.target.value
}else{
event.target.value = 100}}},Copy the code
This is a one-way data stream, and because it is cumbersome to write, Vue provides the syntactic sugar of the V-model
<input type="text" v-model="amount"/>
<input type="text" v-model="amount"/>
Copy the code
To think of it in terms of bidirectional binding, the amount changes when I input to amount, which it does not.
Vue simulates bidirectional binding with two one-way bindings, so we can intercept data.
Small 3 🌰 chestnuts
The source code
The following code is the full version of Vue
<div id="app">dad<div style="border: 1px solid red">
<child :selected="value"></child>
</div>
</div>
Copy the code
Vue.component('child', {
props: ['selected'].template: ` <div> selected: {{selected}} <! <button @click="selected=1">1</button> <button @click="selected=2">2</button> </div> '
})
var vm = new Vue({
el:"#app".data: {
value: 2}})Copy the code
When I click button 1, the data can change, but a warning appears telling you that you should avoid directly modifying prop data
A data can only have one person to change, this person is the owner of the data
Vue.component('child', {
props: ['selected'].template: `
selected: {{selected}}
`
})
let vm = new Vue({
el:"#app".data: {
value: 2
},
template:'
Dad
'
})
Copy the code
The above code hits the button without warning, indicating that Vue prefers one-way data flow.
And to reinforce this pattern, Vue specifies that a child component cannot modify props passed to it by its parent, and prints a warning if it does.
Vue.component('child', {
props: ['selected'].template: `
selected: {{selected}}
`
})
let vm = new Vue({
el:"#app".data: {
value: 2
},
template:'
dad
`
})
Copy the code
<child :selected. Sync ="value" @xxx="value=$event"></child> equals <child :selected="value" @update:selected="selected=$event"></child>Copy the code
.sync does exactly what v-Model does: it implements two one-way bindings using the syntax sugar of two-way bindings.
Advantages of one-way data flow
- The data owner knows exactly why and when the data is changing (because he is the one manipulating the data)
- Data owners can prevent data changes
These are difficult to do in bidirectional binding.
Incremental Vue
Another big feature of Vue is that it is “progressive”, meaning that it can be used gradually. React hardly does that.
- You can keep manipulating the DOM
- You can easily do SEO
- You can do a single page locally
- You can do single pages as a whole
computed V.S methods V.S. watch
- Trigger time watch: Executes a function when the value of watch changes methods: getMessage() appears in a view, or calls getMessage computed when the view is updated: A message appears in the view or the view is updated
- Values using the form watch need to be loaded with data, and the return value itself can be displayed directly in the view without the return value of methods, but for computed, parentheses are not allowed