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
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
  1. 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

  1. 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
  1. 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