introduce
React/Vue/MVVM/MVVM/MVVM/MVVM/MVVM/MVVM/MVVM
- Compile means parse, parse the template syntax that we use. My article is mainly copy Vue Compile,
The effect
- Vue implementation effect
<div id="app">
<input type="text" v-model="a">
<p>{{ b.c }}</p>
<div v-html="c"></div>
</div>
let vm = new Vue({
el : "#app",
data: {
a: 1,
b: {
c: 1
},
c: "<p>165165</p>"}});Copy the code
- We simulate the effect of implementation
<div id="app">
<ul>
<input type="text" v-model="b.c">
<li>{{ a }}</li>
<li>
<span>9</span>
</li>
<div v-html="c"></div>
<div v-html="<b>56156</b>"></div>
{{ b.c }}
</ul>
</div>
let vm = new MVVM({
el: "#app",
data: {
a: 1,
b: {
c: 2
},
c: "<p>56165</p>"}});Copy the code
Analog implementation
- We define a custom MVVM class to simulate the process of New Vue.
let vm = new MVVM({
el: "#app",
data: {
a: 1,
b: {
c: 2
},
c: "<p>56165</p>"}});Copy the code
- MVVM
class MVVM {
constructor(options) {
this.$el= options.el; // Mount point this.$data= options.data; // data new Compile(this.$el, this.$data); // Parse the template}}Copy the code
- Parsing the template
- See if the EL passed in is an element or a string
- If it’s a string, look for the element by class or ID
- If the element is used directly
- If the element exists, it is added to memory and the template is parsed
- See if the EL passed in is an element or a string
class Compile {
constructor(el, data) {
this.$el = this.isElement(el) ? el : document.querySelector(el);
this.$data = data;
if (this.$el) {// Step 1: Add memorylet fragment = this.toFragment(this.$el); This.com pileDirect(fragment); this.compileDirect(fragment); // Step 3: Add this to DOM.$el.appendChild(fragment); }}}Copy the code
Check if it’s an element
IsElement (node) {// 1 indicates an elementreturn node.nodeType === 1;
}
Copy the code
- Add to memory
ToFragment (Element) {// Create a document fragmentlet fragment = document.createDocumentFragment();
letfirstChild; // Add the first element to the fragment one by one until there are no child elements in the documentwhile (firstChild = element.firstChild) {
fragment.appendChild(firstChild);
}
return fragment;
}
Copy the code
The effect
- Parse command
- Get child nodes
- If the child node is an element, the element is parsed, iterating through the child element recursively.
- If it is text, parse the text.
compileDirect(el) {
let children = el.childNodes;
[...children].forEach(child => {
if(this.iselement (child)) {this.iselement (child); This.piledirect (child); this.piledirect (child); }elseThis.piletext (child); this.piletext (child); }}); }Copy the code
2.1 Creating a Tool Class
CompileUtil = {/ / v - text | | text text (value) node, {node. TextContent = value; }, // v-model model(node, value) { node.value = value; }, // v-html html(node, value) { node.innerHTML = value; }}Copy the code
2.2 Parsing Text
CompileText (node) {// Fetch text, {{a}}let text = node.textContent;
if(text) {// Regex matches, with or without instructions, {{a}}let value = text.match(/{{([^}])+}}/g);
if(value) {/ / access to {{a}} : the data from a value = value [0]. Replace (/ {{([^}] +)}} / g,'$1').trim();
compileUtil["text"](node, this.getValue(value)); }}}Copy the code
2.2.1 Obtaining the value of the text instruction
- If it is a cascading property, A.B.C needs to fetch values layer by layer
getValue(value) {
value = value.split("."); // The first time for this.$data["a"] // The second time is this.$data["a"] ["b"] // The third time is this.$data["a"] ["b"] ["c"]
return value.reduce((prevRes, next) => {
return prevRes[next];
}, this.$data);
}
Copy the code
2.3 Parsing the value of element attribute directives
- Gets all attributes of the element
- If I had to iterate over every property
- Get attribute names such as class, V-model (v-bind is not implemented here and the abbreviation is not implemented)
- Get the corresponding function by name, and get the corresponding value
compileNode(node, data) {
let attrs = [...node.attributes];
if(attrs.length > 0) {attrs.foreach (attr => {// v-model → model // v-text → text // v-html → HTMLlet type= attr.name.slice(2); // handle compileUtil[if there is onetype] && compileUtil[type](node, this.getValue(attr.value) || attr.value); }); }}Copy the code
- Insert into the document
this.$el.appendChild(fragment);
Copy the code
conclusion
- Simple implementation of a Compile process, knowledge is to achieve some simple instruction parsing, has not implemented V-bind, V-ON and their abbreviations: @.
- The emphasis is on understanding, not only knowing and using, but also learning to use them flexibly and knowing their simple principles and being able to implement them.
- If you are interested, take a look at my other two articles
- Implement a simple virtual DOM
- Implement a simple DOM diff algorithm