javascript - 如何从尺寸中获得最大的图标?
问题描述
<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()
解决方案
首先要说的是,您不能只使用 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>
在代码中,我说过在寻找最大元素时需要注意。需要注意的是,代码假设我们正在搜索sizes
或height
在演示中使用的属性是“正方形”(因此我们可以仅通过一个属性而不是两个属性来比较大小,例如我们仅height
在图像中使用,而不是比height
和 width
)。
在生产代码中——尽管您没有真正提供足够的信息来确定在这种情况下是否有必要——我很想查看“表面积”而不是单个维度,否则:
<img src="..." height="500px" width="1px" />
会被认为大于
<img src="..." height="300px" width="100000px" />
也就是说,尽管根据您的问题中存在的少量信息,这应该足够了。如果您需要更多细节或调整,请随时发表评论并根据您的要求更新您的问题。
参考:
- 箭头函数。
Array.prototype.filter()
.Array.prototype.forEach()
.Array.prototype.includes()
.Array.prototype.reduce()
.- 解构分配。
document.createElement()
.document.querySelector()
.document.querySelectorAll()
.Node.appendChild()
.Node.cloneNode()
.Node.textContent
.NodeList.prototype.forEach()
.Object.keys()
.Object.values()
.- 展开语法 (
...
)。 - 模板文字。
推荐阅读
- javascript - for循环和数组有问题
- angular - DataTables 加载数据,但按钮和排序在 Angular 4 中没有按预期运行
- vb.net - 一个子的多个事件
- openshift - 挂载到 VPC 的 minishift 文件夹不可写
- node.js - 带有 Upsert 的 findOneAndUpdate 总是插入一个新用户
- python - Python/Scrapy 转到不同的 URL
- python - 如何理解二进制表示函数的递归
- python - 将列表对象转换为字典
- r - 计算矩阵列表的元素分位数 R
- javascript - 同时使用 Laravel 和 Angularjs 路由