We can use the v-for instruction to render a list based on an array. There are five ways to use it, as follows:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Document</title> <script src="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script> </head> <body> <script> Vue.config.productionTip=false; Vue.config.devtools=false; </script> <div id="app"> <p v-for="item in items">{{item}}</p> <!--Array format 1, rendering result:<p>11</p><p>12</p> --> <p v-for="(item,index) in items">{{index}}->{{item}}</p> <!--Array format 2, rendering result:<p>0->11</p><p>1->12</p>--> <p v-for="item in infos">{{item}}</p> <!--Object format 1, rendering results:<p>gege</p><p>12</p>--> <p v-for="(item,key) in infos">{{key}}:{{item}}</p> <!--Object format 2, rendering results:<p>name:gege</p><p>age:12</p>--> <p v-for="(item,key,index) in infos">{{index}}:{{key}}:{{item}}</p> <!--Object format 3, rendering results:<p>0:name:gege</p><p>1:age:12</p>--> </div> <script> var app = new Vue({ data(){ return { items:[11,12], //v-for Can be an object infos:{name:'gege',age:12} //It can also be an array } }, el:'#app' }) </script> </body> </html>
Very simple. As long as an interface is provided in the background to return an array or object, the front end can be rendered through v-for. Let's take the third format of the above object as an example to talk about the source code, as follows:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Document</title> <script src="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script> </head> <body> <script> Vue.config.productionTip=false; Vue.config.devtools=false; </script> <div id="app"> <p v-for="(item,key,index) in infos">{{index}}:{{key}}:{{item}}</p> </div> <script> var app = new Vue({ data(){return {infos:{name:'gege',age:12}}}, el:'#app' }) </script> </body> </html>
Source code analysis
When parsing the template, Vue's processfor() - > parsefor() function will parse these four variables according to the different contents of v-for, and save them to the properties of AST object:
function processFor (el) { //Line 9367 for instructions var exp; if ((exp = getAndRemoveAttr(el, 'v-for'))) { //If you get v-for attribute var res = parseFor(exp); //call parseFor Function resolves the property if (res) { //If res existence extend(el, res); //Then call extend()Add to AST On object } else { warn$2( ("Invalid v-for expression: " + exp) ); } } }
parseFor() is used to parse the value of v-for and return an object, as follows:
function parseFor (exp) { //Line 9383 parsing v-for attribute exp:v-for Value ;for example:"(item,key,index) in infos" var inMatch = exp.match(forAliasRE); //Using regular matching forAliasRE Defined on line 9403 equal to:/([^]*?)\s+(?:in|of)\s+([^]*)/; if (!inMatch) { return } //If not, return false var res = {}; res.for = inMatch[2].trim(); //for Is equal to:infos var alias = inMatch[1].trim().replace(stripParensRE, ''); //Remove the brackets on both sides, and alias Be equal to:item,key,index var iteratorMatch = alias.match(forIteratorRE); //Match alias and index if (iteratorMatch) { //If it matches, this is the format:v-for="(item,index) in data" res.alias = alias.replace(forIteratorRE, ''); //Get aliases res.iterator1 = iteratorMatch[1].trim(); //Get index if (iteratorMatch[2]) { res.iterator2 = iteratorMatch[2].trim(); } } else { res.alias = alias; } return res //Return objects, such as:{alias: "item",for: "infos",iterator1: "key",iterator2: "index"} }
After execution, the v-for in the example stores four attributes related to v-for, as follows:
Next, when generate generates the rendre function, it will call genFor() to generate the corresponding function, as follows:
function genFor ( //Rendering v-for instructions el, state, altGen, altHelper ) { var exp = el.for; //Obtain for Value var alias = el.alias; //Get aliases var iterator1 = el.iterator1 ? ("," + (el.iterator1)) : ''; //Get index(v-for When the value of is an object key) var iterator2 = el.iterator2 ? ("," + (el.iterator2)) : ''; ///Get index(v-for When the value of is an object)) if ("development" !== 'production' && state.maybeComponent(el) && el.tag !== 'slot' && el.tag !== 'template' && !el.key ) { state.warn( "<" + (el.tag) + " v-for=\"" + alias + " in " + exp + "\">: component lists rendered with " + "v-for should have explicit keys. " + "See https://vuejs.org/guide/list.html#key for more info.", true /* tip */ ); } el.forProcessed = true; // avoid recursion return (altHelper || '_l') + "((" + exp + ")," + //Piece together_l function "function(" + alias + iterator1 + iterator2 + "){" + "return " + ((altGen || genElement)(el, state)) + '})' }
The last generated render function is equal to:
with(this){return _c('div',{attrs:{"id":"app"}},_l((infos),function(item,key,index){return _c('p',[_v(_s(index)+":"+_s(key)+":"+_s(item))])}))}
The v-for is as follows:
_l((infos),function(item,key,index){return _c('p',[_v(_s(index)+":"+_s(key)+":"+_s(item))
_The first parameter of l is the target of our v-for, that is, infos, which will traverse the object later.
When rendering to generate VNode, the l function inside Vue, that is, the global renderList, is executed as follows:
function renderList ( //Line 3691 rendering v-for instructions val, render ) { var ret, i, l, keys, key; if (Array.isArray(val) || typeof val === 'string') { //If val It's an array. ret = new Array(val.length); //take ret Cheng Yi Cheng val Same size array for (i = 0, l = val.length; i < l; i++) { //ergodic val array ret[i] = render(val[i], i); //Call in turn render Function, parameter 1 is the value, parameter 2 is the index return VNode,And the results VNode Save to ret inside } } else if (typeof val === 'number') { ret = new Array(val); for (i = 0; i < val; i++) { ret[i] = render(i + 1, i); } } else if (isObject(val)) { keys = Object.keys(val); ret = new Array(keys.length); for (i = 0, l = keys.length; i < l; i++) { key = keys[i]; ret[i] = render(val[key], key, i); } } if (isDef(ret)) { //If ret existence(Successfully called) (ret)._isVList = true; //Add an_isVList Tag with value true } return ret //Last return ret }
Finally, it is packed into VNode array and returned as the child node of other elements (﹤ c's third parameter).