首页 > 解决方案 > 如何从尺寸中获得最大的图标?

问题描述

<link rel="apple-touch-icon" sizes="57x57" href="/apple-touch-icon-57x57.png">
<link rel="apple-touch-icon" sizes="114x114" href="/apple-touch-icon-114x114.png">
<link rel="apple-touch-icon" sizes="72x72" href="/apple-touch-icon-72x72.png">
<link rel="apple-touch-icon" sizes="144x144" href="/apple-touch-icon-144x144.png">
<link rel="apple-touch-icon" sizes="60x60" href="/apple-touch-icon-60x60.png">
<link rel="apple-touch-icon" sizes="120x120" href="/apple-touch-icon-120x120.png">
<link rel="apple-touch-icon" sizes="76x76" href="/apple-touch-icon-76x76.png">
<link rel="apple-touch-icon" sizes="152x152" href="/apple-touch-icon-152x152.png">

如何使用 DOM 从上述代码中获取最大尺寸的图标?document.querySelector()

标签: javascripthtmldom

解决方案


首先要说的是,您不能只使用 only 来执行此操作document.querySelector(),因为没有选择器可以找到给定元素的“最大”。

然而,这对于函数调用来说相对简单,例如:

// defining the function 'getLargest()' as a constant, using
// arrow syntax; the function is defined as accepting one
// argument, the opts Object:
const getLargest = (opts) => {

  // here we set the default settings, which mean that
  // if you call the function with no argument the largest
  // <link> element with a 'rel' attribute equal to
  // "apple-touch-icon" will be selected (with some caveats);
  // the largest element is defined by the 'sizes' attribute,
  // and the largest found will have the class-name 'largest'
  // applied to it:
  let settings = {
    selector: 'link[rel=apple-touch-icon]',
    attribute: 'sizes',
    indicator: 'largest'
  };

  // here we iterate over the Array of Object keys returned
  // from the Object.keys() method, and we use
  // Array.prototype.forEach() to iterate over that Array
  // using arrow notation; in the event that no opts
  // Object is passed to the function we use the empty
  // Object-literal in order to prevent errors:
  Object.keys(opts || {}).forEach(
    // here we update the settings Object with the value
    // value from the opts Object:
    (key) => settings[key] = opts[key]
  );

  // using destructuring to retrieve the variables to retrieve
  // the values held in those Object keys as variables in the
  // function:
  let {
    selector,
    attribute,
    indicator
  } = settings,

  // retrieving the elements that match the given selector, that
  // also have the appropriate attribute by which we're sorting:
  elements = document.querySelectorAll(`${selector}[${attribute}]`);

  // if there are no elements, or any of the properties passed into
  // the function are undefined we quit here, and return false; we
  // use Object.values() to retrieve an Array of the values held in
  // the settings Object, with Array.prototype.includes() to see if
  // that Array contains the value undefined:
  if (elements.length === 0 || Object.values(settings).includes(undefined)) {
    return false;
  }

  // here we determine the largest element, first converting the
  // NodeList of elements into an Array using an Array literal
  // along with the spread operator, and then making use of
  // Array.prototype.reduce():
  const result = [...elements].reduce(
    // here we use two of the arguments automatically available to
    // the reduce function:
    // acc: the initial value/property passed into the function,
    // curr: the current element of the Array we're iterating over:
    (acc, curr) => {

      // here we parse the value of the accumulator's attribute-value
      // into a decimal number (the radix of 10), and compare it to
      // the decimal parsed value of the attribute-value of the current
      // element (the 'attribute' variable is the attribute passed into
      // the function, or the default). If the accumulator's value is
      // greater then we retain the accumulator:
      if (parseInt(acc[attribute], 10) > parseInt(curr[attribute])) {
        return acc;
      } else {
        // ...otherwise we retain the current Array element:
        return curr;
      }
    },
    // here we pass in an Object-literal with a key-name of the
    // attribute you're searching by/for, and set it to 0; that
    // way we prevent errors caused by the accumulator, or its
    // attribute-property being undefined, and 0 means it's unlikely
    // to me the largest (although you could arguably set it to
    // Number.NEGATIVE_INFINITY to (almost) guarantee that it will
    // never be a larger number than one you're looking for):
    {
      [attribute]: 0
    });

  // here we take the result Node and use the Element.classList API
  // to add the 'indicator' class-name to that resulting Node:
  result.classList.add(indicator);

  // and finally we return the Node to the calling context:
  return result;
};

演示:

// here we retrieve <img> elements (for easier visualisation):
const img = getLargest({
  selector: 'img',
  attribute: 'height'
}),
// now we find the <link> elements (the required arguments are
// the function's default settings:
    link = getLargest(),
// retrieving the <ul> element in the document (added for more
// visual confirmation, absolutely unessential):
    list = document.querySelector('ul'),
// creating an <li> element (again unessential, and purely for
// confirmation/visualisation):
    li = document.createElement('li');

// using NodeList.prototype.forEach(), retrieving elements via
// the class-name added by the function:
document.querySelectorAll('.largest').forEach(
  // passing the current Node of the NodeList over which
  // we're iterating into the anonymous function:
  (node) => {
     // cloning the <li>:
     let clone = li.cloneNode();
     // setting the textContent to be equal to the HTML of
     // the found element (and of its children, should any
     // node have children):
     clone.textContent = node.outerHTML;

     // appending that created clone to the list:
     list.appendChild(clone);
  });

const getLargest = (opts) => {
  let settings = {
    selector: 'link[rel=apple-touch-icon]',
    attribute: 'sizes',
    indicator: 'largest'
  };

  Object.keys(opts || {}).forEach(
    (key) => settings[key] = opts[key]
  );

  let {
    selector,
    attribute,
    indicator
  } = settings,
  elements = document.querySelectorAll(`${selector}[${attribute}]`);

  if (elements.length === 0 || Object.values(settings).includes(undefined)) {
    return false;
  }

  const result = [...elements].reduce(
    (acc, curr) => {
      if (parseInt(acc[attribute], 10) > parseInt(curr[attribute])) {
        return acc;
      } else {
        return curr;
      }
    }, {
      [attribute]: 0
    });
  result.classList.add(indicator);
  return result;
};

const img = getLargest({
  selector: 'img',
  attribute: 'height'
}),
    link = getLargest(),
    list = document.querySelector('ul'),
    li = document.createElement('li');
    
[...document.querySelectorAll('.largest')].forEach(
  (node) => {
     let clone = li.cloneNode();
     clone.textContent = node.outerHTML;
     list.appendChild(clone);
  });
*, ::before, ::after {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}
html, body {
  background-color: #000;
  width: 100%;
  height: 100%;
}

body {
  display: block flex;
  align-items: center;
  justify-content: space-around;
  flex-wrap: wrap;
  gap: 1em;
}

.largest {
  box-shadow: 0 0 1rem 0.2rem limegreen;
}

ul {
  display: grid;
  width: 100%;
  min-height: 3em;
  grid-auto-rows: max-content;
  gap: 0.5em 0;
}

li {
background-color: #fff9;
padding: 0.2em 0.1em;
}
<link rel="apple-touch-icon" sizes="57x57" href="/apple-touch-icon-57x57.png">
<link rel="apple-touch-icon" sizes="114x114" href="/apple-touch-icon-114x114.png">
<link rel="apple-touch-icon" sizes="72x72" href="/apple-touch-icon-72x72.png">
<link rel="apple-touch-icon" sizes="144x144" href="/apple-touch-icon-144x144.png">
<link rel="apple-touch-icon" sizes="60x60" href="/apple-touch-icon-60x60.png">
<link rel="apple-touch-icon" sizes="120x120" href="/apple-touch-icon-120x120.png">
<link rel="apple-touch-icon" sizes="76x76" href="/apple-touch-icon-76x76.png">
<link rel="apple-touch-icon" sizes="152x152" href="/apple-touch-icon-152x152.png">

<img src="https://placekitten.com/200/200" alt="" height="200px">
<img src="https://www.fillmurray.com/50/50" height="50px">
<img src="https://placekitten.com/20/20" height="20px">
<img src="https://www.fillmurray.com/g/300/300" height="300px">

<ul></ul>

JS 小提琴演示

在代码中,我说过在寻找最大元素时需要注意。需要注意的是,代码假设我们正在搜索sizesheight在演示中使用的属性是“正方形”(因此我们可以仅通过一个属性而不是两个属性来比较大小,例如我们仅height在图像中使用,而不是比height width)。

在生产代码中——尽管您没有真正提供足够的信息来确定在这种情况下是否有必要——我很想查看“表面积”而不是单个维度,否则:

<img src="..." height="500px" width="1px" />

会被认为大于

<img src="..." height="300px" width="100000px" />

也就是说,尽管根据您的问题中存在的少量信息,这应该足够了。如果您需要更多细节或调整,请随时发表评论并根据您的要求更新您的问题。

参考:


推荐阅读