Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/html/81.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 创建子元素并附加到父节点的通用函数_Javascript_Html_Function_Dom - Fatal编程技术网

Javascript 创建子元素并附加到父节点的通用函数

Javascript 创建子元素并附加到父节点的通用函数,javascript,html,function,dom,Javascript,Html,Function,Dom,我想创建并使用通用javascript函数,通过该函数可以轻松、快速、灵活地为父节点创建新的子节点 看看我的代码: <!DOCTYPE html> <html> <body> <style> div { border: 2px solid #eeeeee; background-color: #dff0d8; } ol { background-color: #dff0d8; } li { background-c

我想创建并使用通用javascript函数,通过该函数可以轻松、快速、灵活地为父节点创建新的子节点

看看我的代码:

<!DOCTYPE html>
<html>
<body>

<style>
div {
    border: 2px solid #eeeeee;
    background-color: #dff0d8;
}
ol {
    background-color: #dff0d8;
}
li {
    background-color: #eff0c8;
}
</style>

<script>
function addNewElement(newElementType,parentId) {
    var newElement = document.createElement(newElementType);
    newElement.innerHTML = 'new element';
    parentId.appendChild(newElement);
    // actually I want to use just this simple code, what makes this function universal, but it doesn't work..
    // while next commented lines work as it should
    /**
    if (parentId == "someThing"){
         someThing.appendChild(newElement);
    }
    if (parentId == "list"){
         list.appendChild(newElement);
    }
    **/
}
</script>

<p>In next example we can add new child element to this list:</p>
<ol id="list">
    <li>1</li>
    <li>2</li>
    <li>3</li>
</ol>
<button onclick="addNewElement('li','list')">Add new li-element to this list</button>
<p>In next example we can add new child element to this div:</p>
<div id="someThing">Something here</div>
<button onclick="addNewElement('div','someThing')">Add new div-element to this div</button>
</body>
</html>
我是JS的新手,所以我不完全理解为什么不能使用它
parentId.appendChild(newElement)
来获得相同的结果

我想即使没有任何jQuery或其他库,也应该很容易让它工作


因此,我问您如何实现这一点?

首先,您不应该多次使用同一个元素ID

根据:

id属性为HTML元素指定一个唯一的id(该值在HTML文档中必须是唯一的)

因此,我更改了您的HTML,即从按钮中删除ID,并将所需ID传递到
addNewElement
函数:

<p>In next example we can add new child element to this list:</p>
<ol id="list">
    <li>1</li>
    <li>2</li>
    <li>3</li>
</ol>
<button onclick="addNewElement('li', 'list')">Add new li-element to this list</button>
<p>In next example we can add new child element to this div:</p>
<div id="someThing">Something here</div>
<button onclick="addNewElement('div', 'someThing')">Add new div-element to this div</button>
function addNewElement(elementType, parentId) {
    let parentElement = document.getElementById(parentId);
    let newElement = document.createElement(elementType);

    newElement.innerHTML = 'new element';
    parentElement.appendChild(newElement);
}
它是有效的


请查看以了解更多详细信息。

好吧,我找到了修复它的简单方法,但我正在寻找更基本的方法:

document.getElementById(parentId).appendChild(newElement);
编辑: 另一种方法是:

<!DOCTYPE html>
<html>
<body>
<style>
div {
    border: 2px solid #eeeeee;
    background-color: #dff0d8;
}
ol {
    background-color: #dff0d8;
}
li {
    background-color: #eff0c8;
}
</style>
<script>
function addNewElement(newElementType,parentId,parentElementType) {
    //document.getElementById(clickedId).appendChild(newElement);
    var el = parentElementType + "[id=" + parentId + "]";
    el = document.querySelector(el);
    var newElement = document.createElement(newElementType);
    newElement.innerHTML = 'new element';
    el.appendChild(newElement);
}
</script>
<p>In next example we can add new child element to this list:</p>
<ol id="list">
    <li>1</li>
    <li>2</li>
    <li>3</li>
</ol>
<button onclick="addNewElement('li','list','ol')">Add new li-element to this list</button>
<p>In next example we can add new child element to this div:</p>
<div id="someThing">Something here</div>
<button onclick="addNewElement('div','someThing','div')">Add new div-element to this div</button>
</body>
</html>

div{
边框:2个实心#eeeeee;
背景色:#dff0d8;
}
ol{
背景色:#dff0d8;
}
李{
背景色:#eff0c8;
}
函数addNewElement(newElementType、parentId、parentElementType){
//document.getElementById(单击EDID).appendChild(新元素);
var el=parentElementType+“[id=“+parentId+”]”;
el=文档查询选择器(el);
var newElement=document.createElement(newElementType);
newElement.innerHTML='newElement';
el.appendChild(新元素);
}
在下一个示例中,我们可以将新的子元素添加到此列表中:

  • 一,
  • 二,
  • 三,
  • 将新的li元素添加到此列表中 在下一个示例中,我们可以向该div添加新的子元素:

    这里有东西 将新div元素添加到此div
    但现在我们需要在这个新示例中传递addNewElement函数中的父节点类型。或者我们也可以为ul和div元素定义类,并使用它们代替id。 这是一种更先进的方法,但在某些情况下可能更有用。这是关于和的纪录片


    如果您想获得更多信息,也请阅读此文。

    我知道您已经有了一个适合您的答案,但我只想添加一个,它显示了一种更灵活的方法,即使用配置对象而不是只传递标记名。为了使它更灵活,您可以传递对父对象的引用,而不是id。此外,如果您想在将新创建的元素添加到DOM后对其进行处理,它会返回对该元素的引用

    'use strict';
    
    var addNewElement = function (configItems, elParent) {
        var newElements = [];
    
        if (!Array.isArray(configItems)) {
          // if configItems is not an array, and therefore a
          // single config object or string, turn it into
          // a single element array
          configItems = [configItems];
        }
    
        // If elParent is a string assume it is
        // the id of an element in the page and select it
        if (typeof elParent === 'string') {
          elParent = document.getElementById(elParent);
        }
    
        configItems.forEach(function (config) {
          var option,
            elChild;
          // if a string is passed in, assume it is
          // the tagName and create a default config object
          if (typeof config === 'string') {
            config = {tag: config};
          }
    
    
          elChild = document.createElement(config.tag);
    
          for (option in config) {
            if (config.hasOwnProperty(option)) {
              switch (option) {
                case 'tag':
                  // do nothing, already used tag to create new element
                  break;
                case 'html':
                  // just a shortcut so we don't have to use
                  // innerHTML in our config object
                  elChild.innerHTML = config.html;
                  break;
                case 'text':
                  // another shortcut
                  elChild.textContent = config.text;
                  break;
                case 'class':
                  // if we are passed an array convert it to a space delimited string
                  elChild.className = Array.isArray(config.class) ?
                    config.class.join(' ') : config.class;
                  break;
                default:
                  // if we haven't already handled it, assume it is
                  // an attribute to add to the element
                  elChild.setAttribute(option, config[option]);
              }
            }
          }
    
          // default text if none was specified
          if (elChild.innerHTML === '') {
            elChild.innerHTML = 'new element';
          }
    
          newElements.push(elChild);
          elParent.appendChild(elChild);
        });
    
        // return a reference to the new element(s)
        // in case you want to do something else with it
        // after it was inserted into the document
        // returns a single item or an array depending on how many
        // items you passed it in configItems
        return newElements.length === 1 ? newElements[0] : newElements;
    };
    
    用法如下所示:

    // just add a new element with the default text by id
    addNewElement('li', 'list');
    
    var list = document.getElementById('list');
    
    // a little fancier, this time using an element reference
    addNewElement({
      tag: 'li',
      html: 'Custom List Item!',
      class: 'fancy'
    }, list);
    
    addNewElement({
      tag: 'input',
      placeholder: 'Type here',
      value: 'Delete me'
    }, document.body); // attach to the body
    
    // do something with the element
    // after we create it
    var houdini = addNewElement({
      tag: 'li',
      text: 'Now you see me.',
      class: ['houdini', 'show'],
    }, list);
    
    setTimeout(function () {
      houdini.textContent = "Now you don't";
      houdini.classList.remove('show');
    }, 2000);
    
    var checkElements = addNewElement([
      {
        tag: 'input',
        id: 'check',
        type: 'checkbox',
        checked: 'checked',
      },
      {
        tag: 'label',
        for: 'check',
        html: 'Uncheck me!'
      }
    ], document.body);
    
    在行动中展示它

    使用


    之所以出现
    'class'
    这种情况,是因为在ES3中不能使用保留字作为带有点符号的属性名,因此在设计DOM API时,它们使用
    className
    来表示类属性。从ES5开始我们就可以了。这允许我们添加一个
    'class'
    快捷方式属性。

    虽然您已经接受了答案,但我觉得提供一种更具扩展性的方法可能是值得的,它允许您使用不引人注目的JavaScript(而不是依赖于诸如
    onclick
    之类的在线事件处理程序)来简化维护

    它的可扩展性和可定制性也更高:

    // a simple function to help derive the correct element
    // from the supplied argument, 'needle':
    function derive(needle) {
    
      // if the needle has a nodeType and if that nodeType is
      // exactly equal to 1:
      if (needle.nodeType && needle.nodeType === 1) {
    
        // the needle is then an element-node, and here
        // we convert that node into an Array of one:
        needle = [needle];
    
      // otherwise, if the needle is a string, and
      // document.getElementById() finds an element
      // with that id:
      } else if ('string' === typeof needle && document.getElementById(needle)) {
        // we find that element-node again, using the string
        // and again convert it to an Array of one:
        needle = [document.getElementById(needle)];
    
      // otherwise, if the needle is - again - a string, and
      // document.querySelectorAll() can find a collection
      // (of one or more) elements matching the selector that
      // the needle is implied to be then we retrieve those
      // elements and, using Array.from(), we convert the
      // collection into an Array:
      } else if ('string' === typeof needle && document.querySelectorAll(needle)) {
        needle = Array.from(document.querySelectorAll(needle));
      }
    
      // here we return the results to the calling context:
      return needle;
    }
    
    
    function addNewElement(opts) {
    
      // the default settings for the function:
      // append:  Boolean, true: the content will be
      //          inserted after the found sibling-
      //          node; false: the content will be
      //          inserted before the found sibling-
      //          node.
      // classes: String, a string of white-space
      //          separated class-names to add to
      //          the new contents,
      //          Array, an array of class-names to
      //          add to the new contents.
      // content: String, a string of HTML you wish
      //          to appear in the newly-added content.
      // count:   Number, the number of elements you
      //          wish to insert at once.
      // create:  String, the element-type to create
      //          null, if you want the function to
      //          'decide' for itself.
      // parent:  Node, the element to which you want
      //          to add new elements,
      //          String, the id of the element to
      //          which you want to add new elements,
      //          or a CSS selector by which you want
      //          find the element(s) in the document
      //          to add new elements to.
      // sibling: Node, the node beside which the new
      //          element(s) should be added.
      //          Null, the function will try to determine
      //          the desired element beside which the
      //          content should be added, based on
      //          the 'append' setting (above).
      var settings = {
          'append': true,
          'classes' : null,
          'content': 'Newly-added element.',
          'count': 1,
          'create': null,
          'parent': document.body,
          'sibling': null
        },
    
        // uninitialised variables for use later, primarily
        // to declare/instantiate variables in one place:
        parents,
        childType,
        created,
        sibling,
        clone,
        classes,
        count,
    
        // a documentFragment to enable the addition of multiple
        // elements at the same time without triggering (quite so)
        // many redraws of the document/page:
        fragment = document.createDocumentFragment();
    
      // using Object.keys to iterate over the opts Object, if
      // one is supplied or an empty object to avoid errors,
      // using the Array.prototype.forEach() method:
      Object.keys(opts || {}).forEach(function(key) {
    
        // here we update/overwrite the keys of the
        // settings object to the values held in those
        // properties of the opts Object:
        settings[key] = opts[key];
      });
    
      // we call the derive function to retrieve an array
      // of element(s):
      parents = derive(settings.parent);
    
      // checking, and then storing, the value of
      // settings.append; it it's equal to true the
      // assessment returns true, if it's equal to
      // false the assessment returns false (this
      // is a naive check, because it requires that
      // a Boolean is stored in that property):
      appendCheck = settings.append === true;
    
      // ensuring that the settings.count number
      // is a number by parsing the potential
      // String, other-based number, into base-10:
      count = parseInt(settings.count, 10);
    
      // iterating over each of the parents:
      parents.forEach(function(pater) {
        // 'pater' the first argument is a reference
        // to the current array-element of the array
        // over which we're iterating.
    
        // retrieving the element-type to be created,
        // if a value was supplied in settings.create
        // then we use that (we don't check it's a
        // valid element, or that it can be validly
        // contained in the nominated parent), otherwise
        // if the current element node has children
        // then we retrieve the localName of its
        // lastElementChild, if it has no children
        // the ternary returns null and we move to
        // the string of 'div':
        childType = settings.create || (pater.children.length > 0 ? pater.lastElementChild.localName : null) || 'div';
    
        // here we create the element:
        created = document.createElement(childType);
    
        // if the earlier assessment of settings.append
        // resulted in true:
        if (appendCheck === true) {
    
          // we find the sibling beside which to insert the
          // new content; if a node was supplied we use that,
          // otherwise we use the lastElementChild or lastChild:
          sibling = settings.sibling || pater.lastElementChild || pater.lastChild;
        } else if (appendCheck === false) {
          // otherwise, we use either the supplied value or
          // we use the firstElementChild or firstChild:
          sibling = settings.sibling || pater.firstElementChild || pater.firstChild
        }
    
        // assign the supplied - or default - content to the
        // created element:
        created.innerHTML = settings.content;
    
        // if any class-names have been supplied:
        if (settings.classes) {
    
          // we first check whether the settings.classes
          // variable is an Array (using Array.isArray),
          // which returns a Boolean (true or false); if
          // it returns true we simply use the Array otherwise
          // we assume it's a String and split that String
          // on its white-space characters (/\s+/):
          classes = Array.isArray(settings.classes) ? settings.classes : settings.classes.split(/\s+/);
    
          // iterating over the array of class-names:
          classes.forEach(function(cN) {
            // the first argument (cN) is a reference
            // to the current array-element of the
            // Array over which we're iterating.
    
            // here we use the Element.classList API to
            // add each of the class-names:
            created.classList.add(cN);
          });
        }
    
        // a simple for loop to add the desired
        // number of new elements (as supplied in
        // the settings.count, or opts.count
        // setting):
        for (var i = 0; i < count; i++) {
    
          // clone the created-element (and its
          // child elements):
          clone = created.cloneNode(true);
    
          // append the cloned node to the 
          // documentFragment we created
          // earlier:
          fragment.appendChild(clone);
        }
    
        // here we use parentNode.insertBefore() to insert
        // the new contents (held in fragment) either the
        // sibling.nextSibling (if appendCheck is true) or
        // before the sibling (if appendCheck is false):
        pater.insertBefore(fragment, (appendCheck ? sibling.nextSibling : sibling));
      });
    }
    
    // retrieving the <button> elements on the page, and converting
    // to an Array, using Array.from():
    var buttons = Array.from(document.querySelectorAll('button'));
    
    // iterating over those <button> elements in the Array:
    buttons.forEach(function(button) {
    
      // using the anonymous function of the addEventListener()
      // to call the addNewElement function, in which
      // we set the opts.parent setting to the
      // previousElementSibling of the button
      // firing the event:
      button.addEventListener('click', function() {
        addNewElement({
          'parent': button.previousElementSibling
        });
      });
    });
    
    在下一个示例中,我们可以将新的子元素添加到此列表中:

  • 一,
  • 二,
  • 三,
  • 将新的li元素添加到此列表中 在下一个示例中,我们可以向该div添加新的子元素:

    这里有东西
    在这个div中添加新的div元素
    哈哈,你更快了:)谢谢你的回答!起初,我调用addNewElement函数时没有“this.id”参数,我只是在尝试它,当我第一次发布问题时,我忘了删除它。我同意,在这种情况下不应该使用相同的元素ID来避免问题。那么,你认为除了“getElementById”没有其他方法了吗?我在寻找更简单的东西,所以我忘了这个…)@WebSurfer是的:)我相信在这种情况下没有其他方法,因为你应该明确知道一个元素应该附加一个孩子。我发现了!至少还有一种方法可以做到这一点,尽管这是一种更高级的方法——document.querySelector或document.queryselectoral。不过,在某些情况下,它们可能更有用^_^@是的,我知道这些函数。无论如何,谢谢!但是在您的案例中使用它们需要对HTML进行一些额外的更改。而且,它们的性能不如
    getElementById
    。。由于它们相对较新,人们说它们可能是有车的,而且资源更密集。是的,我现在会坚持使用getElementById,或者在某些情况下会使用getElementsByClass,但是如果适合的话,我也会尝试在其他复杂的情况下使用这个新特性。谢谢你的帮助!我不明白这个问题。已经有了一个花孩子的函数,您还需要有一个元素来附加它。再简单不过了。如何获取父元素实际上并不相关,可以封装在函数中。我不明白你想达到什么目的。@DaveNewton也许是某个编辑了我的文章并替换了几个字的版主让你更难理解,请检查其他编辑。我希望您能理解,我提供的代码除了我想要改进的注释部分外,其他部分都不起作用,并且没有很多“if-else”检查,它更通用。。我希望通过ButtonOnClick和addNewElement函数读取传递的参数就可以访问它。主要原因是简化添加新孩子的过程,并获得更智能、更短的代码。现在可以了吗?您所需要添加的只是通过ID获取元素(或者任何您想要用来获取实际元素的机制)。我不明白怎么会更简单
    // a simple function to help derive the correct element
    // from the supplied argument, 'needle':
    function derive(needle) {
    
      // if the needle has a nodeType and if that nodeType is
      // exactly equal to 1:
      if (needle.nodeType && needle.nodeType === 1) {
    
        // the needle is then an element-node, and here
        // we convert that node into an Array of one:
        needle = [needle];
    
      // otherwise, if the needle is a string, and
      // document.getElementById() finds an element
      // with that id:
      } else if ('string' === typeof needle && document.getElementById(needle)) {
        // we find that element-node again, using the string
        // and again convert it to an Array of one:
        needle = [document.getElementById(needle)];
    
      // otherwise, if the needle is - again - a string, and
      // document.querySelectorAll() can find a collection
      // (of one or more) elements matching the selector that
      // the needle is implied to be then we retrieve those
      // elements and, using Array.from(), we convert the
      // collection into an Array:
      } else if ('string' === typeof needle && document.querySelectorAll(needle)) {
        needle = Array.from(document.querySelectorAll(needle));
      }
    
      // here we return the results to the calling context:
      return needle;
    }
    
    
    function addNewElement(opts) {
    
      // the default settings for the function:
      // append:  Boolean, true: the content will be
      //          inserted after the found sibling-
      //          node; false: the content will be
      //          inserted before the found sibling-
      //          node.
      // classes: String, a string of white-space
      //          separated class-names to add to
      //          the new contents,
      //          Array, an array of class-names to
      //          add to the new contents.
      // content: String, a string of HTML you wish
      //          to appear in the newly-added content.
      // count:   Number, the number of elements you
      //          wish to insert at once.
      // create:  String, the element-type to create
      //          null, if you want the function to
      //          'decide' for itself.
      // parent:  Node, the element to which you want
      //          to add new elements,
      //          String, the id of the element to
      //          which you want to add new elements,
      //          or a CSS selector by which you want
      //          find the element(s) in the document
      //          to add new elements to.
      // sibling: Node, the node beside which the new
      //          element(s) should be added.
      //          Null, the function will try to determine
      //          the desired element beside which the
      //          content should be added, based on
      //          the 'append' setting (above).
      var settings = {
          'append': true,
          'classes' : null,
          'content': 'Newly-added element.',
          'count': 1,
          'create': null,
          'parent': document.body,
          'sibling': null
        },
    
        // uninitialised variables for use later, primarily
        // to declare/instantiate variables in one place:
        parents,
        childType,
        created,
        sibling,
        clone,
        classes,
        count,
    
        // a documentFragment to enable the addition of multiple
        // elements at the same time without triggering (quite so)
        // many redraws of the document/page:
        fragment = document.createDocumentFragment();
    
      // using Object.keys to iterate over the opts Object, if
      // one is supplied or an empty object to avoid errors,
      // using the Array.prototype.forEach() method:
      Object.keys(opts || {}).forEach(function(key) {
    
        // here we update/overwrite the keys of the
        // settings object to the values held in those
        // properties of the opts Object:
        settings[key] = opts[key];
      });
    
      // we call the derive function to retrieve an array
      // of element(s):
      parents = derive(settings.parent);
    
      // checking, and then storing, the value of
      // settings.append; it it's equal to true the
      // assessment returns true, if it's equal to
      // false the assessment returns false (this
      // is a naive check, because it requires that
      // a Boolean is stored in that property):
      appendCheck = settings.append === true;
    
      // ensuring that the settings.count number
      // is a number by parsing the potential
      // String, other-based number, into base-10:
      count = parseInt(settings.count, 10);
    
      // iterating over each of the parents:
      parents.forEach(function(pater) {
        // 'pater' the first argument is a reference
        // to the current array-element of the array
        // over which we're iterating.
    
        // retrieving the element-type to be created,
        // if a value was supplied in settings.create
        // then we use that (we don't check it's a
        // valid element, or that it can be validly
        // contained in the nominated parent), otherwise
        // if the current element node has children
        // then we retrieve the localName of its
        // lastElementChild, if it has no children
        // the ternary returns null and we move to
        // the string of 'div':
        childType = settings.create || (pater.children.length > 0 ? pater.lastElementChild.localName : null) || 'div';
    
        // here we create the element:
        created = document.createElement(childType);
    
        // if the earlier assessment of settings.append
        // resulted in true:
        if (appendCheck === true) {
    
          // we find the sibling beside which to insert the
          // new content; if a node was supplied we use that,
          // otherwise we use the lastElementChild or lastChild:
          sibling = settings.sibling || pater.lastElementChild || pater.lastChild;
        } else if (appendCheck === false) {
          // otherwise, we use either the supplied value or
          // we use the firstElementChild or firstChild:
          sibling = settings.sibling || pater.firstElementChild || pater.firstChild
        }
    
        // assign the supplied - or default - content to the
        // created element:
        created.innerHTML = settings.content;
    
        // if any class-names have been supplied:
        if (settings.classes) {
    
          // we first check whether the settings.classes
          // variable is an Array (using Array.isArray),
          // which returns a Boolean (true or false); if
          // it returns true we simply use the Array otherwise
          // we assume it's a String and split that String
          // on its white-space characters (/\s+/):
          classes = Array.isArray(settings.classes) ? settings.classes : settings.classes.split(/\s+/);
    
          // iterating over the array of class-names:
          classes.forEach(function(cN) {
            // the first argument (cN) is a reference
            // to the current array-element of the
            // Array over which we're iterating.
    
            // here we use the Element.classList API to
            // add each of the class-names:
            created.classList.add(cN);
          });
        }
    
        // a simple for loop to add the desired
        // number of new elements (as supplied in
        // the settings.count, or opts.count
        // setting):
        for (var i = 0; i < count; i++) {
    
          // clone the created-element (and its
          // child elements):
          clone = created.cloneNode(true);
    
          // append the cloned node to the 
          // documentFragment we created
          // earlier:
          fragment.appendChild(clone);
        }
    
        // here we use parentNode.insertBefore() to insert
        // the new contents (held in fragment) either the
        // sibling.nextSibling (if appendCheck is true) or
        // before the sibling (if appendCheck is false):
        pater.insertBefore(fragment, (appendCheck ? sibling.nextSibling : sibling));
      });
    }
    
    // retrieving the <button> elements on the page, and converting
    // to an Array, using Array.from():
    var buttons = Array.from(document.querySelectorAll('button'));
    
    // iterating over those <button> elements in the Array:
    buttons.forEach(function(button) {
    
      // using the anonymous function of the addEventListener()
      // to call the addNewElement function, in which
      // we set the opts.parent setting to the
      // previousElementSibling of the button
      // firing the event:
      button.addEventListener('click', function() {
        addNewElement({
          'parent': button.previousElementSibling
        });
      });
    });