什么是使用普通旧JS动态呈现DOM元素的好方法?

时间:2016-10-16 21:32:54

标签: javascript html dom

我面临的挑战是使用普通的旧Javascript构建单页应用程序,不允许使用任何库或框架。虽然在React和Angular中创建动态DOM元素相当简单,但我提出的vanilla JS解决方案似乎很笨拙。我想知道是否有一种特别简洁或有效的方法来构建动态呈现的DOM元素?

下面的函数接收一个从GET请求接收的数组,并为每个项目呈现一个div,传入该值(就像你在React和渲染子元素中映射结果一样)。

 function loadResults(array) {
  array.forEach(videoObject => {
    let videoData =  videoObject.snippet;
    let video = {
       title : videoData.title,
       img : videoData.thumbnails.default.url,
       description : videoData.description
    };
    let div = document.createElement("DIV");
    let img = document.createElement("IMG");
    img.src = video.img;
    let h4 = document.createElement("h4");
    let title = document.createTextNode(video.title);
    h4.appendChild(title);
    let p = document.createElement("p");
    let desc = document.createTextNode(video.description);
    p.appendChild(desc);

    div.appendChild(img);
    div.appendChild(h4);
    div.appendChild(p);
    document.getElementById('results')
      .appendChild(div);
  });
}

这感觉不必要地笨重,但我还没有找到一种更简单的方法来做到这一点。

提前致谢!

4 个答案:

答案 0 :(得分:10)

  

注意:我在这里说的一切都是概念证明等级,仅此而已。它不处理错误或例外情况,也不处理   它在生产中进行了测试请自行决定使用。

一个好的方法是创建一个为您创建元素的函数。像这样:

const crEl = (tagName, attributes = {}, text) => {
  const el = document.createElement(tagName);
  Object.assign(el, attributes);
  if (text) { el.appendChild(document.createTextNode(text)); }

  return el;
};

然后你可以像这样使用它:

results
  .map(item => crEl(div, whateverAttributes, item.text))
  .forEach(el => someParentElement.appendChild(el));

我见过的另一个很酷的概念证据是使用 ES6 Proxies as a sort of templating engine



const t = new Proxy({}, {
  get(target, property, receiver) {
    return (children, attrs) => {
      const el = document.createElement(property);
      for (let attr in attrs) {
        el.setAttribute(attr, attrs[attr]);
      }
      for (let child of(Array.isArray(children) ? children : [children])) {
        el.appendChild(typeof child === "string" ? document.createTextNode(child) : child);
      }
      return el;
    }
  }
})

const el = t.div([
  t.span(
    ["Hello ", t.b("world!")], {
      style: "background: red;"
    }
  )
])

document.body.appendChild(el);




代理捕获目标对象(为空)上的get,并呈现一个名为被调用方法的元素。这会导致您在const el =时看到非常酷的语法。

答案 1 :(得分:3)

如果你可以使用ES6,模板字符串是另一个想法 - >



var vids = [
  {
    snippet: {
      description: 'hello',
      title: 'test',
      img: '#',
      thumbnails: { default: {url: 'http://placehold.it/64x64'} }
    }
  }
];

function loadResults(array) {
  array.forEach(videoObject => {    
    let videoData =  videoObject.snippet;
    let video = {
       title : videoData.title,
       img : videoData.thumbnails.default.url,
       description : videoData.description
    };
    document.getElementById('results').innerHTML = `
<div>
  <img src="${video.img}"/>
  <h4>${video.title}</h4>
  <p>${video.description}</p>
</div>
`;
  });
}

loadResults(vids);
&#13;
<div id="results"></div>
&#13;
&#13;
&#13;

答案 2 :(得分:2)

在我看来,如果你没有使用任何模板引擎,你需要尽可能多地控制你如何组合你的元素。因此,合理的方法是抽象常见任务并允许链接调用以避免额外的变量。所以我会选择这样的东西(不是很花哨):

 function CE(el, target){
    let ne = document.createElement(el);
    if( target )
       target.appendChild(ne);
    return ne;
 }

  function CT(content, target){
    let ne = document.createTextNode(content);
    target.appendChild(ne);
    return ne;
 }


 function loadResults(array) {
  var results = document.getElementById('results');
  array.forEach(videoObject => {
    let videoData =  videoObject.snippet;
    let video = {
       title : videoData.title,
       img : videoData.thumbnails.default.url,
       description : videoData.description
    };
    let div = CE('div');
    let img = CE("IMG", div);
    img.src = video.img;
    CT(video.title, CE("H4", div));
    CT(video.description,  CE("p", div););

    results.appendChild(div);
  });
}

您获得的是,您仍然可以很好地控制元素的组合方式,以及与之相关的元素。但是您的代码更容易理解。

答案 3 :(得分:0)

关于这个code review问题的两个观察结果:

重构
  1. 添加辅助函数以创建具有可选文本内容的元素,
  2. 删除video对象抽象,因为它以相同的名称复制了三个属性中的两个,
  3. 生成可读但香草类型的Javascript:

    function loadResults(array) {
        function create (type,text) {
           let element = document.createElement(type);
           if( text)
               element.appendChild( document.createTextNode( text));
           return element;
        }
        array.forEach(videoObject => {
           let vid =  videoObject.snippet;
           let div = create("DIV");
           let img = create("IMG");
           img.src = vid.thumbnails.default.url;
           let h4 = create("H4", vid.title);
           let p = create("P", vid.description);
    
           div.appendChild(img);
           div.appendChild(h4);
           div.appendChild(p);
           document.getElementById('results').appendChild(div);
        });
     }