繁体   English   中英

使用带有上下文/变量的JavaScript创建HTML

[英]Create HTML using javascript with context/variables

我想使用javascript从存储的对象创建HTML。 它们包括带有onclick函数的按钮,这些按钮在对象内部调用一个函数。

我尝试使用document.createElement(“ Div”)创建每个节点并设置其内容/类...,但是发现此解决方案非常笨拙。

目前,我正在将节点的innerHTML设置为我创建的字符串,这样更具可读性。

let objHTML = document.createElement("Div");
objHTML.innerHTML = 
`<div class="ObjWrap ${status}">
    <p class="objName">${name}</p>
    <p class="objContent">${content}</p>
    <button class="objEdit" onclick="${edit(evt)}">e</button>
    <button class="objActive" onclick="${activity(evt)}">x</button>
</div>`;

编辑和活动功能是对象的局部变量和访问变量,因此我无法编写“ onclick =“ edit(evt)” ...-但我的解决方案也不起作用,我猜想编辑和活动功能只是经过评估而已我可以使用eventlisteners来代替按钮上的onclick事件,但这又不那么可读,我还必须再次访问该按钮以附加eventlistener(在这种情况下,类似于objHTML.getElementsByTagName( 'div')[0] .getElementsByTagName('div')[0] .getElementsByTagName('button')[0/1])。

我的问题是如何创建HTML,同时保持其原有的可读性,并允许我添加将按钮变量或按钮元素引用到其中的onclick函数。 由于这些元素被多次创建,因此我无法使用ID。

编辑:Codepen显示我的意思,切入上下文,所以有些事情可能不会出现: https ://codepen.io/anon/pen/jdEqwQ

我相信您正在寻找的是一个视图框架。 基本上,是一个完成所有有趣的数据绑定业务,数据转换之类的库。

它们很多 ,但是如今最受欢迎和受支持的是ReactAngularVue

他们将处理此类数据绑定,并确保值在代码和UI之间保持同步,并在可能的情况下有效地重用元素。 他们每个人都有不同的工作流程,您需要进行一些研究以找到您认为最适合您的用例和知识的工作流程。

如果您的应用程序很小,则可能不需要使用它们,但是如果您已经感到这种痛苦,请考虑一下,它们是非常完善的工具。

是否可以定义您希望按钮执行的功能?

这将创建您要查找的div并向其添加已定义函数的处理程序。

function test() { console.log('test') };
let obj = document.createElement("Div");
obj.innerHTML = '<div>test <button onclick="test()">run</button></div>';
document.body.appendChild(obj)

但是除此之外,我会同意使用vue之类的框架表示的意见。

编辑:这样的事情是否朝您期望的方向发展?

function generate() {
    function test() {
        return function(e) {
            console.log('event', e);
        }
    };

    const btn1 = document.createElement('button');
    btn1.onclick = test();
    btn1.innerHTML = 'Run'


    const obj = document.createElement("Div");


    obj.innerHTML = '<div>test<br></div>';
    obj.appendChild(btn1);
    document.body.appendChild(obj)
}

generate()

我怀疑是否有可能以不在全局范围内的字符串形式获取函数引用。 但是,这违背了您编写HTML模板的干净方法。

实际上,创建起来并不难。 它有助于使实用程序功能处理繁重的工作:

let create = (tag, opts = {}) => (Object.assign(document.createElement(tag), opts)),
nested = (p, c) =>(c) ?(p.appendChild(c), (c2) => nested.call(p, p, c2)) : p;

create全部作用是使您可以轻松,更快地创建具有属性和属性的元素。

所有nested操作都是将节点依次放置在原始容器中。 容器是嵌套中的第一个元素,第一个子元素是第二个,依此类推。

然后我们加载一些虚拟数据:

//your template stuff
let template=new Map([["status","online"],["name","Zak"],["content","This is some 
content"],["edit",function(){alert("editing!")}],["activity",function(){alert("some 
activity!")}]]);

并将其放在一起:

let objHTML = nested(create("DIV", {
  className: "container"
}), create("p", {
  className: "objName"
}))(create("button", {
  className: "objEdit",
  onclick: template.get("edit"),
  textContent: "edit!"
}))(create("button", {
  className: "objContent",
  textContent: template.get("content"),
  onclick: () => alert("clicking does nothing... oh wait")
}))(create("button", {
  className: "objActive",
  onclick: template.get("activity"),
  textContent: "activity"
}))();

瞧。 仅此而已,显然,仅凭上述两个功能,我们就可以做更多的事情。

这是您上面的代码的演示( 无论如何,请快速浏览一下

 let create = (tag, opts = {}) => (Object.assign(document.createElement(tag), opts)), nested = (p, c) => (c) ?(p.appendChild(c), (c2) => nested.call(p, p, c2)) : p; //your template stuff let template=new Map([["status","online"],["name","Zak"],["content","This is some content"],["edit",function(){alert("editing!")}],["activity",function(){alert("some activity!")}]]); let objHTML = nested( create("DIV", { className: "container" }), create("p", { className: "objName" }))(create("button", { className: "objEdit", onclick: template.get("edit"), textContent: "edit!" }))(create("button", { className: "objContent", textContent: template.get("content"), onclick: ()=>alert("clicking does nothing... oh wait"), }))(create("button", { className: "objActive", onclick: template.get("activity"), textContent: "activity" }) )(); document.body.appendChild(objHTML); console.log(objHTML); 

我确实同意其他人的观点,有很多可以为这类事情提供服务的库,但是重要的是要意识到,当您只需滚动自己的库时,其中的许多库并不需要足够大的外部资源来提供服务-当然,前提是任务足够小,您不需要大量额外的钟声。

注意 :顺便说一句,没有JSX编译器的React看起来很像这段代码-尽管如上所述,React仍然可以访问很多东西,您将不得不花很多时间来重新创建-只是不要不要卖空自己。 深入了解基础并有时检查齿​​轮是一件好事! 编码愉快!

如果您正在学习JavaScript,并且不想为新的库或框架而烦恼,则可以使用普通的JS类。 这意味着您将设置用于处理侦听器的方法,而不是将其包含在HTML中,但这更加干净。

这个小例子并不完美,但可能会让您有所作为。 如果您决定最终决定使用React的功能,则将其故意设计成类似于React的功能。

 class Component { constructor(props, i) { // Assign the component index as `id` this.state = { id: i }; // Loop over the passed in data and add them // to the class context for (let [p, v] of Object.entries(props)) { this.state[p] = v; }; // Bind the edit handler so that the context sticks this.handleEdit = this.handleEdit.bind(this); // Now create the wrapper element, render the HTML // and set the listeners this.addElement(); this.render(); this.setListeners(); } // `querySelector` and `addEventListener` shortcut // Takes a selector and a function to call when the button // is clicked qsl(s, fn) { const el = document.querySelector(s); return el.addEventListener('click', fn, false); } // set the button listeners for HTML corresponding // to this component id setListeners() { const { id } = this.state; const selector = `[data-id="${id}"]`; this.qsl(`${selector} .edit`, this.handleEdit); } // An example based on your code - toggle // the status and then re-render the HTML handleEdit() { const { status } = this.state; this.state.status = !status; this.render(); } // Adds the wrapper element to the DOM and caches it addElement() { const { id } = this.state; const html = `<div data-id="${id}" class="component"></div>`; document.body.insertAdjacentHTML('beforeend', html); this.wrapper = document.querySelector(`[data-id="${id}"].component`); } // return your compiled template getHTML() { const { id, status, name } = this.state; return `<div data-id="${id}"><p>${status} - ${name}</p><button class="edit">e</button></div>`; } // Render the output. // Sadly, because we're not using a virtual DOM (like React // for example) we're destroying the existing HTML and replacing it // so we need to re-add the event listeners to that new markup render() { this.wrapper.innerHTML = this.getHTML(); this.setListeners(); } } // Set up the data for the new objects const data = [ { status: false, name: 'Bob', content: '' }, { status: true, name: 'Mick', content: '' } ]; // Loop over the data to create the components // We pass in the index to the class as it makes for // a good id const components = data.map((component, i) => { return new Component(component, i); }); 
 .component { border: 1px solid #454545; width: 50%; padding: 0.2em; margin-bottom: 0.1em; } 
 <div class="wrapper"></div> 

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM