With vue, {{MSG}} can be changed to the corresponding value of data. MSG, hello.

This article step by step to achieve the effect of compiled text in the final VUE.

{{msg}} => ‘hello’

Instead of focusing on the DOM and all that stuff, just focus on the logic.

How to implement compileText

let data = {
  msg: "hello"
};

let text = "{{msg}} world";

function compileText(data, text) {
  // How to do that
}

text = compileText(data, text);
// Want to output => Hello world
console.log(text);
Copy the code

The logic here is not that hard, just find {{MSG}} and replace the entire string with the value of data.msg.

function compileText(data, text) {
  // Matches the re
  let reg = / \ {\ {(. +) \} \} /;
  let newText = text.replace(reg, (. args) = > {
    / / get the MSG
    let expr = args[1];
    // data specifies the value of the MSG attribute
    let value = data[expr];
    return value;
  });
  // Return the replaced string
  return newText;
}
Copy the code

{MSG :’hello’,person:{name:’hua’}}

Text might be {{person.name}} like west Lake

{{person.name}} => ‘hua’

You can do more to fetch value from compileText.

How do you implement getValue

let data = { person: { name: "hua"}};let expr = "person.name";
function getValue(data, expr) {
  // How to write this
}
// Want to output => hua
console.log(getValue(data, expr));
Copy the code

So we’re just going to go back one layer at a time, and in order to write it in common, we’re going to take into account a lot of layers. The difficulty to understand is reduce. If you do not understand, you can see how to use reduce

function getValue(data, expr) {
  // Separate each key into an array
  let arr = expr.split(".");
  // Use reduce as init and fn
  let init = data;
  let fn = (acc, cur) = > acc[cur];
  let value = arr.reduce(fn, init);
  return value;
}
Copy the code

Then upgrade to compileText

function compileText(data, text) {
  // Matches the re
  let reg = / \ {\ {(. +) \} \} /;
  let newText = text.replace(reg, (. args) = > {
    / / get the MSG
    let expr = args[1];
    // We can support multiple keys
    let value = getValue(data, expr);
    return value;
  });
  // Return the replaced string
  return newText;
}

/ / the demo presentation
let data = {
  person: { name: "hua"}};let text = "{{person. Name}} like west Lake";

text = compileText(data, text);
Hua likes the West Lake
console.log(text);
Copy the code

Text node compiled < div id = ‘app’ > {{MSG}} < b > 1 < / b > {{MSG}} < / div >

First try to compile the expression inside the child text node in div correctly.

let data = { msg: "hello" };
let app = document.querySelector("#app");
// Find all child nodes
let children = [...app.childNodes];
children.forEach(child= > {
  // If it is a text node, compile
  if (child.nodeType === 3) { compileTextNode(child, data); }});function compileTextNode(node, data) {
  // Just one line of code
}
Copy the code

Mm-hmm. Here’s the result

function compileTextNode(node, data) {
  node.textContent = compileText(data, node.textContent);
}
Copy the code

<div id=’app’> <span>{{MSG}}</span></div>

Now, if it’s in the SPAN element, how do you compile it? If it’s an element node, pick out its text element. If you nested deeply here, you still have recursion involved. Try to think about it first, or even hit compileElement.

let data = { msg: "hello" };
let app = document.querySelector("#app");
compileElement(app, data);
// Add a method to compile the element node. Note that only the text node will be compiled. If it is an element node, find its child text node
function compileElement(node, data) {
  let children = [...node.childNodes];
  children.forEach(child= > {
    if (child.nodeType === 1) {
      compileElement(child, data);
    }
    if (child.nodeType === 3) { compileTextNode(child, data); }}); }Copy the code

To avoid frequent dom manipulation, try fragmenting

Here, the nodes in the APP are constantly operating frequently, which is very bad for performance.

  • Start by putting all the nodes in your app into a document fragment
  • And then after you compile it, you stuff it into your app, perfect.

It’s no big deal when you think about the code

let data = { msg: "hello" };
let app = document.querySelector("#app");
// Insert fragments
let appFragment = moveToFragment(app);
// Edit the fragment
compileElement(appFragment, data);
// The fragment is being inserted into the app
app.appendChild(appFragment);

function moveToFragment(node) {
  let fragment = document.createDocumentFragment();
  // Try writing here to implement the function
  return fragment;
}
Copy the code

Here’s the answer

function moveToFragment(node) {
  let fragment = document.createDocumentFragment();
  // Higher order can do this
  // let firstNode;
  // while ((firstNode = node.firstChild)) {
  // fragment.appendChild(firstNode);
  // }
  let children = [...node.childNodes];
  children.forEach(child= > {
    fragment.appendChild(child);
  });
  return fragment;
}
Copy the code

Merge the whole demo written, compiled

You can copy it directly and try it locally. I hope the method inside can give some inspiration.

<body>
  <div id="app">
    {{msg}}
    <div>{{msg}}</div>
    {{msg}}
  </div>
  <script>
    let data = { msg: "hello" };
    let app = document.querySelector("#app");
    // Insert fragments
    let appFragment = moveToFragment(app);
    // Edit the fragment
    compileElement(appFragment, data);
    // The fragment is being inserted into the app
    app.appendChild(appFragment);

    function moveToFragment(node) {
      let fragment = document.createDocumentFragment();
      // let firstNode;
      // while ((firstNode = node.firstChild)) {
      // fragment.appendChild(firstNode);
      // }
      let children = [...node.childNodes];
      children.forEach(child= > {
        fragment.appendChild(child);
      });
      return fragment;
    }

    function compileElement(node, data) {
      let children = [...node.childNodes];
      children.forEach(child= > {
        if (child.nodeType === 1) {
          compileElement(child, data);
        }
        if (child.nodeType === 3) { compileTextNode(child, data); }}); }function compileTextNode(node, data) {
      node.textContent = compileText(data, node.textContent);
    }
    function compileText(data, text) {
      // Matching re comments are advanced matching points hahaha I won't paste them here first
      // let reg = /\{\{((? :.|\r? \n)+?) \}\}/g;
      let reg = / \ {\ {(. +) \} \} /;
      let newText = text.replace(reg, (. args) = > {
        / / get the MSG
        let expr = args[1];
        // We can support multiple keys
        let value = getValue(data, expr);
        return value;
      });
      // Return the replaced string
      return newText;
    }

    function getValue(data, expr) {
      // Separate each key into an array
      let arr = expr.split(".");
      // Use reduce as init and fn
      let init = data;
      let fn = (acc, cur) = > acc[cur];
      let value = arr.reduce(fn, init);
      return value;
    }
  </script>
</body>
Copy the code