jQuery -返回具有特定类的元素列表中重复次数最多的内容文本



我需要在某个类中获得最常用的元素内容文本。在我的例子中,最经常出现的元素短语是:服务号1

<div class="service_list">
<span>Service number 1</span>
<span>Service number 2</span>
</div>
<div class="service_list">
<span>Service number 1</span>
<span> Service number 3</span>
</div>
<div class="service_list">
<span>Service number 1</span>
<span> Service number 4</span>
</div>

一种方法如下,在JavaScript中带有解释性注释:

// a collection of functions for use:
// create() takes and element-type ('div', 'span'...) along with an Object
// of properties ('className','textContent'...) and then returns the
// created Element with those properties:
let create = (tag, props) => Object.assign(
// creating the element:
document.createElement(tag),
// the Object-literal containing the element's properties:
props),
// a simple function to remove existing content from a node,
// taking a reference to a specific node:
empty = (node) => {
// while the node exists and that node has a firstChild:
while (node && node.firstChild) {
// we use parentNode.removeChild() to remove the
// firstChild node; we use this rather than
// Element.remove() because we wish to remove all
// nodes, rather than allow inadvertent white-
// space text-nodes to accumulate:
node.removeChild(node.firstChild);
}
},
// using an object of functions in order to allow related
// functions to be grouped/exported as one:
listServicePopularity = {
// ascending implies - but I have not written - a corresponding
// function of descending(); I leave this as an exercise for
// reader:
ascending: function() {
// mentions is the element to which the results will
// appended, and shown; here we use the get()
// method to retrieve the first/only element
// matching the selector:
let mentions = this.get('.mentions'),
// services consists of the elements the frequency
// of which we're going to display in ordered form:
services = this.getAll('.service_list > span'),
// usage is ordered frequency of mentions; the
// function this.getAll() returns an Array of
// elements, so here we can use Array methods:
usage = services
// such as Array.prototype.map():
.map(
// using Arrow functions, we're not using 'this'
// within the function, here we pass a reference
// to the current Array-element, which is an
// HTMLElement, and we create a new Array comprised
// of the text-content of the elements, after we
// remove leading/trailing white-space with
// String.prototype.trim():
(service) => service.textContent.trim()
)
// we then use Array.prototype.reduce to convert
// the Array of Strings into an Object of
// properties equal to the 
// Array of [String, Count] pairs:
.reduce(
// passing in a reference to the accumulator
// variable (the empty Object-literal that
// follows the function declaration, which
// is modified as the function iterates),
// and the current Array-value (a string
// comprised of the text-content of the
// original element):
(acc, curr) => {
// if the accumulator has a property equal to the
// text of the current Array-element:
if (acc[curr]) {
// we increment the property-value of that
// property:
acc[curr] = acc[curr] + 1;
// otherwise:
} else {
// we define that property, and initialise its
// value to 1:
acc[curr] = 1;
}
// and we then return the accumulator for the
// next iteration:
return acc;
// the Object literal - as mentioned - is the
// initial state of the accumulator:
}, {});
// we call the empty() function to remove the existing
// contents of the mentions element:
empty(mentions);

// and then call the this.output() function, passing
// in what should be output, and to where it should
// be inserted:
this.output(usage, mentions)
},
// creating a document fragment to append multiple elements
// to one parent-node at once, to minimise redrawing/repainting
// events:
fragment: document.createDocumentFragment(),
// a function which takes a CSS selector and an element Node
// (which defaults to document if no node is provided), and
// returns the result of either Element.querySelector() or
// document.querySelector() with the supplied CSS selector:
get: (selector, context = document) => context.querySelector(selector),
// much the same as above, except here we use document.querySelectorAll()
// (or Element.querySelectorAll(), depending on the context
// provided), and convert the result of that iterable NodeList
// as an Array, using an Array-literal and the spread syntax:
getAll: (selector, context = document) => [...context.querySelectorAll(selector)],
// the output function; which takes two arguments, an Object
// of what should be output (key-value pairs), and a reference
// to the node to which it should be inserted:
output: function(what, where) {
// using Object.entries() to obtain a two-dimensional Array
// of key-value pairs of the Object, and then calling
// Array.prototype.sort() on the result:
Object.entries(what).sort(
// here we use destructuring assignment to map the
// first array-element (the text of the original
// element) as aText or bText, and the second element
// (the frequency with which that text was mentioned)
// as aCount or bCount.
// in the function body we simply compare to see if aCount
// is greater than bCount, and if so we return -1 (so
// the first element (whose properties are aText, and cCount)
// precedes the second; otherwise we return 1 which moves
// after the second element (bText, bCount):
([aText, aCount], [bText, bCount]) => aCount > bCount ? -1 : 1
// we then use Array.prototype.forEach():
).forEach(
// here we again use destructuring to assign the Array-element
// of the sorted Array into two variables, 'key' and 'value':
([key, value]) => {
// we access the document-fragment, and append a newly-created
// 'li' element:
this.fragment.append(create('li', {
// and assign its text-content to be equal to the interpolated
// String - using a template-literal - of the 'key' and
// the 'value':
textContent: `${key} (${value})`
}));
});
// after the forEach(), once all elements have been appended
// to the document fragment, we then append that fragment
// to the 'where' node passed to the function:
where.append(this.fragment);
}
},
// in order to test the function, we have a randomize function:
randomize = () => {
// an Array of service numbers:
let services = [1, 2, 3, 4];
// arguably the 'getAll()' function may be better defined
// outside the listServicePopularity Object, but here we
// use that function to get an Array of elements, and then
// iterate over that Array with Array.prototype.forEach():
listServicePopularity.getAll('.service_list > span').forEach(
// passing in a reference to the current Array element of the Array
// of Elements over which we're iterating.
// in the function body we're setting the text-content of the
// current Array-element using a Template-literal, which
// outputs 'Service number <1-4>', using a naive call to
// Math.random() to generate a number between 1 and 4,
// this gives a pseudo-random Array-index which we
// retrieve and add to the String:
(el) => el.textContent = `Service number ${services[Math.floor( Math.random() * services.length )]}`
);

// we then call the function to generate, and ultimately output,
// the service frequency, to have the frequency of the new set
// of elements generated:
listServicePopularity.ascending();
};

// binding the randomize() function to the 'click' event on the 
// <button> element:
document.querySelector('button').addEventListener('click', randomize);
// using EventTarget.addEventListener() to bind the anonymous function
// as the event-handler for the 'DOMContentLoaded' event on the
// Window Object:
window.addEventListener('DOMContentLoaded', (e) => {
// calling the function once the DOM has loaded, to show the
// frequency of services on page-load:
listServicePopularity.ascending();
});
*,::before,::after {
box-sizing: border-box;
font-family: system-ui;
font-size: 16px;
margin: 0;
padding: 0;
}
main {
border: 2px solid hsl(120deg 30% 70%);
display: grid;
gap: 1em;
inline-size: clamp(15rem, 50vw, 800px);
margin-block: 1em;
margin-inline: auto;
padding: 0.25em;
}
.service_list {
display: grid;
gap: inherit;
grid-template-columns: repeat(2, 1fr);
}
.service_list > span:first-child {
text-align: end;
}
.mentions {
padding-block: 0.5em;
padding-inline: 1em;
}
.mentions::before {
content: "Frequency of mentions:";
}
.mentions ::marker {
color: hsl(120deg 70% 50%);
font-weight: 600;
font-style: italic;
}
.mentions li {
margin-inline-start: 10%;
margin-block-start: 0.5em;
padding-inline-start: 0.4em;
padding-block: 0.4em;
position: relative;
}
.mentions li::after {
content: '';
background: linear-gradient(to right, hsl(120deg 70% 50% / 1), transparent);
position: absolute;
block-size: 3px;
inline-size: 100%;
bottom: 0;
left: 0;
}
<main>
<button type="button">Randomize Services</button>
<div class="service_list">
<span>Service number 1</span>
<span>Service number 2</span>
</div>
<div class="service_list">
<span>Service number 1</span>
<span> Service number 3</span>
</div>
<div class="service_list">
<span>Service number 1</span>
<span> Service number 4</span>
</div>
<ol class="mentions"></ol>
</main>

JS Fiddle demo.

引用:

  • 箭头功能。
  • 数组文本。
  • Array.prototype.filter().
  • Array.prototype.forEach().
  • Array.prototype.map().
  • Array.prototype.sort().
  • Array.prototype.reduce().
  • Destructuring任务。
  • document.createDocumentFragment().
  • document.createElement().
  • document.querySelector().
  • [' document.querySelectorAll () (https://developer.mozilla.org/en-US/docs/Web/API/Document/querySelectorAll)。
  • Element.append().
  • Element.querySelector().
  • Element.querySelectorAll().
  • Element.remove().
  • EventTarget.addEventListener().
  • Math.floor().
  • Math.random().
  • Node.firstChild.
  • Node.removeChild().
  • Object.assign().
  • Object.entries().
  • 属性访问器。
  • String.prototype.trim().
  • Template-literals。
  • while.

最新更新