Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Open
fanmingfei opened this issue Mar 10, 2020 · 7 comments
Open

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

fanmingfei opened this issue Mar 10, 2020 · 7 comments

Comments

@fanmingfei
Copy link
Member

fanmingfei commented Mar 10, 2020

<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
Copy link

Vince-9 commented Mar 10, 2020

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

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
Copy link

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
Copy link

    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
Copy link

LiZhaji commented Mar 10, 2020

<!-- 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
Copy link
Member

<!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
Copy link
Member

terrykingcha commented Mar 10, 2020

继续另一波骚操作

<!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
Copy link

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

7 participants