【问题标题】:Can't call function on HTML element无法在 HTML 元素上调用函数
【发布时间】:2016-08-17 04:05:31
【问题描述】:

我开始在 Vanilla JS 中编写 jQuery,并且我的选择器可以工作,但是当我在 HTML 元素上调用 append 函数时,我收到“不是函数”错误。

var $ = function(){
    this.select = function(input) {
        if (input.split("")[0] == "#") {
            input = input.slice(1, input.length)
            return document.getElementById(input)

        }
        else if (input.split("")[0] == ".") {
            input = input.slice(1, input.length)
            return document.getElementsByClassName(input)

        }
        else {
            return document.getElementsByTagName(input)

        }
    },

    this.append = function(text) {
     return this.innerhtml = this.innerhtml + text

}
};

我的控制台尝试:

var myQuery = new $();

返回未定义

myQuery.select("#testspan")

在这里返回我的span 标签

myQuery.select("#testspan").append("hellohello")

返回错误

VM2207:1 Uncaught TypeError: myQuery.select(...).append is not a function(...)

【问题讨论】:

  • 如果你想链接你的函数,他们需要返回this(返回当前实例)或使用new $()创建一个新实例并返回它。当前,您的 select() 方法返回一个对象,该对象是单个 DOM 元素或 DOM 元素列表,两者都没有 .append() 方法。
  • 您可能还想将整个 select 函数替换为 querySelectorAll :) 您不需要自己解析选择器。
  • @nnnnnn 我猜这应该是一个(接受的)答案。
  • 顺便说一句,input.split("")[0] 是一种获取字符串第一个字符的奇怪方法。请改用input.charAt(0)input[0]

标签: javascript html


【解决方案1】:

从你的sn-p 返回的每个select 方法返回一个DOM 元素(或集合)。您真正想要做的是调用Chaining,其中方法的结果返回原始对象。因此,您可以继续在同一个对象上调用其他方法。

现在,在您的示例中,您将需要一个元素集合 (nodes),然后对象可以再次访问该位置。这是一个简单的例子。

var $ = function () {
    this.nodes = [];
    this.select = function (input) {
        var self = this;
        if (input.split("")[0] == "#") {
            input = input.slice(1, input.length)
            var node = document.getElementById(input);
            if (node)
                this.nodes.push(node);

        }
        else if (input.split("")[0] == ".") {
            input = input.slice(1, input.length)
            Array.prototype.slice.call(document.getElementsByClassName(input), 0).forEach(function (node) {
                self.nodes.push(node);
            });
        }
        else {
            Array.prototype.slice.call(document.getElementsByTagName(input), 0).forEach(function (node) {
                self.nodes.push(node);
            });
        }
        return this;
    },

    this.append = function (text) {
        this.nodes.forEach(function (i) {
            i.innerHTML += text;
        });
        return this;
    }
};

示例 HTML:

<p id="test">This is test </p>
<p>This is number to</p>

控制台(Chrome):

$ = new $()
$ {nodes: Array[0]}
$.select('p').append('hi')

现在有个小问题是你(在控制台中)设置$ = new $(),它有效地覆盖了在同一个脚本中再次调用new $() 的能力。我在下面提供了一个小提琴,将其重命名为myQuery。还更改了每次调用 select 时都会清除 node 数组。

修订:

var myQuery = function () {
    this.nodes = [];
    this.select = function (input) {
        this.nodes = [];
        var self = this;
        if (input.split("")[0] == "#") {
            input = input.slice(1, input.length)
            var node = document.getElementById(input);
            if (node)
                this.nodes.push(node);

        }
        else if (input.split("")[0] == ".") {
            input = input.slice(1, input.length)
            Array.prototype.slice.call(document.getElementsByClassName(input), 0).forEach(function (node) {
                self.nodes.push(node);
            });
        }
        else {
            Array.prototype.slice.call(document.getElementsByTagName(input), 0).forEach(function (node) {
                self.nodes.push(node);
            });
        }
        return this;
    },

    this.append = function (text) {
        this.nodes.forEach(function (i) {
            i.innerHTML += text;
        });
        return this;
    }
};


$ = new myQuery();
$.select('p').append(' test selection by tag name ');

$ = new myQuery();
$.select('.p1').append(' test selection by class ');

$ = new myQuery();
$.select('#p1').append(' test selection by id ');

$ = new myQuery();
$.select('#p2').append(' test selection by id ').append('and then chanined').select('.p2').append(' still chaining');

小提琴:https://jsfiddle.net/kxwt9gmg/

【讨论】:

    【解决方案2】:

    你需要稍微改变你的方法。您想要存储一个结果并在其上调用一个方法。您只能调用该特定对象具有的方法。你返回的那个对象,原始的 html 元素,没有那个方法。您要做的是存储 html 元素,然后返回一个对存储的内容执行操作的 OBJECT。您可以使用闭包来完成此操作。例如:

    function miniQuery(input){
    
      function elementIterate(collection, action){
        for (var i = elements.length -1; i >= 0; i-- ){
          collection[i].style.display = action;
        }
      }
    
      var isCollection = function(element){
        if(element instanceof HTMLCollection){
          return true
        } else{
          return false
        }
      }
    
      function findElement(element){
        if (element.startsWith("#")) {
        // id element selector
        return document.getElementById(element.substring(1));
      } else if (element.startsWith(".")) {
        // class element selector
        return document.getElementsByClassName(element.substring(1));
      } else {
        // tag element selector
        return document.getElementsByTagName(element);
      };
    }
    if (input != undefined) {
      var _this = this;
      this.element = findElement(input);
      var elements = findElement(input);
    }
    return {
    
      append: function(content, position = 'beforeend'){
        var elements = _this.element;
        if (isCollection(elements)) {
          for(var i = elements.length -1; i >= 0; i--){
            elements[i].insertAdjacentHTML(position, content)
          }
        }else{
          elements.insertAdjacentHTML(position, content);
        }
      }
    
      }
    }
    
    function $(input){
      return selector(input);
    }
    
    
    
    function selector(input){
      var query = new miniQuery(input);
      return query;
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2022-07-13
      • 1970-01-01
      • 1970-01-01
      • 2021-05-08
      • 2014-03-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多