eva-engine / 2021questions

12 stars 1 forks source link

2020-03-10 HTML与对象数据进行单向绑定 #5

Open fanmingfei opened 4 years ago

fanmingfei commented 4 years ago
<div id="content">
    My name is {name}, I love {language}.
</div>
function bindHTMLContentWithObject(el, obj) {
  // ...
}
const obj = {
  name: 'LiLei',
  language: 'JavaScript'
}

const newObj = bindHTMLContentWithObject(document.querySelector('#content'), obj)
// content 内容 My name is LiLin, I love JavaScript.

newObj.name = 'HanMeimei' // #content 内容为 My name is HanMeimei, I love JavaScript.

newObj.language = 'Java' // #content 内容为 My name is HanMeimei, I love Java.
Vince-9 commented 4 years ago

虽然功能不是很完善,但是实现了基本的需求

function bindHTMLContentWithObject(el, obj) {
  let content = el.innerHTML;
  const content_backup = content;
  const newObj = {};
  const reg = /\{\s*([\w]*?)\s*\}/m;

  while (reg.test(content)) {
    content = content.replace(reg, ($1, $2) => {
      let val = newObj[$2] = obj[$2];
      Object.defineProperty(newObj, $2, {
        enumerable: true,
        configurable: true,
        get() {
          return val;
        },
        set(newVal) {
          if (newVal === val) return;
          val = newVal;
          compile(el, newObj, content_backup);
        }
      })
      return obj[$2];
    })
  }
  el.innerHTML = content;
  return newObj;
}

function compile(el, obj, content) {
  const reg = /\{\s*([\w]*?)\s*\}/m;
  while (reg.test(content)) {
    content = content.replace(reg, ($1, $2) => {
      return obj[$2];
    });
  }
  el.innerHTML = content;
}
xiaosen7 commented 4 years ago

function bindHTMLContentWithObject(el, obj = {}) { let str = el.innerHTML;

update();

function update() {
    el.innerHTML = str.replace(/\{([^}]+)\}/g, function () {
        return obj[arguments[1]]
    })
}

let temp = {
    get(target, key) {
        if (typeof target[key] === 'object') return new Proxy(obj, temp)
        return Reflect.get(target, key);
    },
    set(target, key, value) {
        update();
        return Reflect.set(target, key, value);
    }
}

return new Proxy(obj, temp);

}

joker1148 commented 4 years ago
    const obj = {
      name: 'LiLei',
      language: 'JavaScript',
    }
    function bindHTMLContentWithObject(el,obj){
        var object = {}
        let reg = /\{\s*([^}]+\S)\s*\}/g
        let content = el.innerHTML
        for(let key in obj){
            Object.defineProperty(object,key,{
                set(val){
                    el.innerHTML += val
                }
            })
            object[key] = obj[key]
        }
        while (reg.test(content)) {
            content = content.replace(reg, (one, two) => {
                return obj[two]}) 
        } 
        el.innerHTML = content
    }
    bindHTMLContentWithObject(document.getElementById("content"),obj)
LiZhaji commented 4 years ago
<!-- html部分 -->
<div id="content">
    My name is {a.b.name}, I love {language}.
  </div>
  <button id='btn'>change</button>
// js部分
function bindHTMLContentWithObject(el, obj) {
      const text = el.innerText
      replace(obj)

      function replace(obj) {
        const newText = text.replace(/{[\d,\w,_,.]+}/g, vari => {
          const keys = vari.trim().slice(1, -1).split('.')
          let val = obj[keys.shift()] || ''
          while (keys.length) {
            val = val[keys.shift()] || ''
          }
          return val
        })
        el.innerText= newText
      }

      // 使用Object.defineProperty
      function watchByDp(obj) {
        const backup = JSON.parse(JSON.stringify(obj))
        Object.keys(obj).forEach(key => {
          if (Object.prototype.toString.call(obj[key]) === '[object Object]') {
            watchByDp(obj[key])
          }
          Object.defineProperty(obj, key, {
            get(){
              return backup[key]
            },
            set(val){
              backup[key] = val
              replace(backup)
            }
          })
        })
        return obj
      }

      // return watchByDp(obj)

      // 使用Proxy
      function watchByProxy(obj, oldObj){
        let newObj = {}
        Object.keys(obj).forEach(key => {
          if (Object.prototype.toString.call(obj[key]) === '[object Object]') {
            obj[key] = watchByProxy(obj[key], oldObj)
          }
        })
        return new Proxy(obj, {
          set(obj, key, val) {
            obj[key] = val
            replace(oldObj)
          }
        })
      }

      return watchByProxy(obj, obj)
    }

    const obj = {
      a:{b:{name: 'LiLei'}},
      language: 'JavaScript'
    }
    const newObj = bindHTMLContentWithObject(document.querySelector('#content'), obj)

    document.querySelector('#btn').addEventListener('click', e => {
      newObj.a.b.name = '222'
      newObj.language = 'dwdwew'
    })
terrykingcha commented 4 years ago
<!DOCTYPE html>
<html>
  <body>
    <div id="content">
      My name is {name}, I love {language}.
    </div>
    <script>
      const bindHTMLContentWithObject = (() => {
        const registers = [];

        function update() {
          requestIdleCallback(update);

          for (const [el, obj, tokens, contents] of registers) {
            let newContent = "";
            let needUpdate = false;
            for (let i = 0; i < tokens.length; i++) {
              const [key, oldValue] = tokens[i];
              const newValue = obj[key];
              if (newValue !== oldValue) {
                needUpdate = true;
                tokens[i][1] = newValue;
              }

              newContent += `${contents[i]}${newValue}`;
            }
            newContent += content[tokens.length] || "";

            if (needUpdate) {
              el.innerHTML = newContent;
            }
          }
        }

        requestIdleCallback(update);

        return (el, obj) => {
          const reg = /\{[^{}]+?\}/g;
          const tokens = el.innerHTML
            .match(reg)
            .map(token => [token.substr(1, token.length - 2), undefined]);
          const contents = el.innerHTML.split(reg);
          registers.push([el, obj, tokens, contents]);
        };
      })();

      const obj = {
        name: "LiLei",
        language: "JavaScript"
      };

      const newObj = bindHTMLContentWithObject(
        document.querySelector("#content"),
        obj
      );
    </script>
  </body>
</html>
terrykingcha commented 4 years ago

继续另一波骚操作

<!DOCTYPE html>
<html>
  <body>
    <div id="content">
      My name is {name}, I love {language}.
    </div>
    <script>
      const bindHTMLContentWithObject = (() => {
        const registers = [];

        function update() {
          requestIdleCallback(update);

          for (const [el, obj] of registers) {
            for (let i = 0; i < el.childNodes.length; i += 1) {
              const node = el.childNodes[i];
              if (node.nodeType === 8) {
                const key = node.textContent;
                i += 1;
                const tokenNode = el.childNodes[i];
                if (tokenNode.textContent !== obj[key]) {
                  tokenNode.textContent = obj[key];
                }
              }
            }
          }
        }

        requestIdleCallback(update);

        return (el, obj) => {
          const reg = /\{[^{}]+?\}/g;
          const contents = el.textContent.split(reg);
          const fragment = document.createDocumentFragment();

          el.textContent.match(reg).forEach((token, i) => {
            const key = token.substr(1, token.length - 2);
            const content = contents.shift();
            const contentNode = document.createTextNode(content);
            const commondNode = document.createComment(key);
            const tokenNode = document.createTextNode(obj[key]);
            fragment.appendChild(contentNode);
            fragment.appendChild(commondNode);
            fragment.appendChild(tokenNode);
          });

          if (contents.length) {
            fragment.appendChild(document.createTextNode(contents.shift()));
          }

          el.textContent = "";
          el.appendChild(fragment);

          registers.push([el, obj]);
        };
      })();

      const obj = {
        name: "LiLei",
        language: "JavaScript"
      };

      const newObj = bindHTMLContentWithObject(
        document.querySelector("#content"),
        obj
      );
    </script>
  </body>
</html>
qimiaowan commented 4 years ago
function bindHTMLContentWithObject(el, obj) {
    var obj1 = JSON.parse(JSON.stringify(obj));
    var html = el.innerHTML;

    el.innerHTML = html.replace(/{(.*?)}/g,function(a,b){
      Object.defineProperty(obj,b,{
        get(){
          return obj1[b]
        },
        set(val){
          obj1[b] = val;
          el.innerHTML = html.replace(/{(.*?)}/g,function(a,b){
            return obj1[b]
          });
        }
      })
      return obj1[b];
    });
  return obj;
  }
const obj = {
  name: 'LiLei',
  language: 'JavaScript'
}

const newObj = bindHTMLContentWithObject(document.querySelector('#content'), obj)
// content 内容 My name is LiLin, I love JavaScript.

newObj.name = 'HanMeimei' // #content 内容为 My name is HanMeimei, I love JavaScript.

newObj.language = 'Java' // #content 内容为 My name is HanMeimei, I love Java.