Form v – model
In VUE, v-Model is undoubtedly one of the most commonly used apis, such as input, Textarea, radio, Checkbox, select, etc., can use V-Model for bidirectional binding. So how exactly does it work? Below through oneself write a demo to analyze concretely?
directives
The instructions defined on the elements are collected during vue’s parse phase, which is the process of generating code from the AST tree
model = $event.target.value
Copy the code
Going back to genDefaultModel, two very important methods will be executed
addProp(el, 'value', ("(" + value + ")"));
addHandler(el, event, code, null, true);
Copy the code
The first method, addProp, adds a prop to the input tag, dynamically binding the value to it. The second method, addHandler, adds an input event to the input tag and dynamically modifs the model value when the event is triggered. In this way, bidirectional binding is implemented.
<input
v-bind:value="model"
v-on:input="model=$event.target.model">
Copy the code
Finally, back to the genDirectives, a render function is generated according to the directives
V – model components
let baseSpan = {
template: '
+ '< button@click ="changeValue">,
props: ['value'],
name: 'baseSpan'.data() {return {
isShow: this.value
}
},
methods: {
changeValue() {
this.isShow = true
this.$emit('input'.true)
}
}
}
var app = new Vue({
el: '#app',
data: {
visible: false
},
components: {
baseSpan
}
})
Vue.component('base-span',baseSpan);
Copy the code
The HTML code looks like this
<div id='app'>
<base-span v-model='visible'></base-span>
<span>{{visible}}</span>
</div>
Copy the code
The parent component’s visible data is associated with the child baseSpan V-Model directive, which defines an props for value and a changeValue method that passes data to the parent component by sending an input event. This is typical father-child communication and is necessary for the V-Model to work. Of course, the value and input are not writable. We can customize them in the model configuration of the child component as needed. For example, the event we dispatch can also be a change. So how is the source code designed?
if (el.component) {
genComponentModel(el, value, modifiers);
// component v-model doesn't need extra runtime return false }Copy the code
The component’s V-Model also executes the instruction’s Model function, and then hits the if statement above to execute the genComponentModel(EL, Value, MODIFIERS) method.
function genComponentModel (
el,
value,
modifiers
) {
var ref = modifiers || {};
var number = ref.number;
var trim = ref.trim;
var baseValueExpression = '? v';
var valueExpression = baseValueExpression;
if (trim) {
valueExpression =
"(typeof " + baseValueExpression + " === 'string'" +
"? " + baseValueExpression + ".trim()" +
":" + baseValueExpression + ")";
}
if (number) {
valueExpression = "_n(" + valueExpression + ")";
}
var assignment = genAssignmentCode(value, valueExpression);
el.model = {
value: ("(" + value + ")"),
expression: ("\" " + value + "\" "),
callback: ("function (" + baseValueExpression + "{" + assignment + "}")}; }Copy the code
For our example, the following el. Model is generated
// component v-model
if (el.model) {
data += "model:{value:" + (el.model.value) + ",callback:" + (el.model.callback) + ",expression:" + (el.model.expression) + "},";
}
Copy the code
In this case, the parent component’s Render function will contain configuration items for the child component model, and the child vNode will be created by executing the createComponent function. Then execute the following logic
// transform component v-model data into props & events
if (isDef(data.model)) {
transformModel(Ctor.options, data);
}
Copy the code
So transformModel basically adds model-bound data visible to data.props. Then add data.model.callback to on.
// transform component v-model info (value and callback) into
// prop and event handler respectively.
function transformModel (options, data) {
var prop = (options.model && options.model.prop) || 'value';
var event = (options.model && options.model.event) || 'input'; (data.props || (data.props = {}))[prop] = data.model.value; var on = data.on || (data.on = {});if (isDef(on[event])) {
on[event] = [data.model.callback].concat(on[event]);
} else{ on[event] = data.model.callback; }}Copy the code
This is equivalent to the parent passing visible to the child component’s value via props. When the child changes data, the parent is notified to update visible by sending an event. When I click the button, the span in the isShow=true subcomponent is displayed. The visible = true.
You can see both the V-Model of the form element and the V-Model of the component. They are essentially grammatical sugar.
tips
The company is currently using VUE. In my spare time, I write demo by myself and understand the source code of VUE step by step through the method of single step debugging. If there is something wrong, please give me your advice.