如何构建价格滑块 - HTML 和原生 JavaScript
如果您销售的是按需付费或订阅计划,您可能需要一个带有价格表的落地页,该价格表可通过价格范围滑块进行控制——就像下面的示例一样👇
我最近为Cruip 的着陆页模板构建了它,所以我决定写一系列文章来向您展示我是如何开发它(使用 HTML、React 和 Vue),以及我遵循哪些流程来实现最棘手的部分。
让我们先从HTML 和 JavaScript版本开始,然后我们将在下一篇文章中介绍 React 和 Vue 版本!
创建 HTML 结构
我创建了一个非常基本的 HTML 结构,并使用了Cruip 框架中的一些现成 CSS 。
<div class="pricing">
<div class="pricing-slider">
<label class="form-slider">
<span>How many users do you have?</span>
<input type="range" />
</label>
<div class="pricing-slider-value"></div>
</div>
<div class="pricing-items">
<div class="pricing-item">
<div class="pricing-item-inner">
<div class="pricing-item-content">
<div class="pricing-item-header">
<div class="pricing-item-title">Basic</div>
<div class="pricing-item-price">
<span class="pricing-item-price-currency">$</span>
<span class="pricing-item-price-amount">13</span>
<span class="pricing-item-price-after">/m</span>
</div>
</div>
<div class="pricing-item-features">
<ul class="pricing-item-features-list">
<li class="is-checked">Excepteur sint occaecat</li>
<li class="is-checked">Excepteur sint occaecat</li>
<li class="is-checked">Excepteur sint occaecat</li>
<li>Excepteur sint occaecat</li>
<li>Excepteur sint occaecat</li>
</ul>
</div>
</div>
<div class="pricing-item-cta">
<a class="button" href="#">Buy Now</a>
</div>
</div>
</div>
</div>
</div>
请注意,我们有输入元素⬇️和输出元素⬆️。
输入元素
- 该
<input type="range" />元素,即滑块控件 <div class="pricing-slider-value">我们将把当前滑块值写入该元素中。
输出元素
我们可以设置多个定价标签页,这意味着会有多个输出结果。每个输出结果包含一个<div class="pricing-item-price">元素,该元素又包含三个子元素:
<span class="pricing-item-price-currency">货币符号<span class="pricing-item-price-amount">金额<span class="pricing-item-price-after">如需了解其他信息,例如账单周期,请联系我们。
结果如下👇
输入和输出数据的结构化
现在我们需要设计数据方案。我已经定义了一系列滑块值(输入)和相应的价格值(输出)。
| 钥匙 | 滑块值 | 价格,货币 | 价格,金额 | 价格(之后) |
|---|---|---|---|---|
| 0 | 1,000 | 自由的 | ||
| 1 | 1,250 | $ | 13 | /m |
| 2 | 1,500 | $ | 17 | /m |
| 3 | 2,000 | $ | 21 | /m |
| 4 | 2,500 | $ | 25 | /m |
| 5 | 3,500 | $ | 42 | /m |
| 6 | 6,000 | $ | 58 | /m |
| 7 | 15,000 | $ | 117 | /m |
| 8 | 50,000 | $ | 208 | /m |
| 9 | 50,000+ | 联系我们 |
继续通过数据属性向HTML添加输入和输出数据。
输入数据👇
<input
type="range"
data-price-input='{
"0": "1,000",
"1": "1,250",
"2": "1,500",
"3": "2,000",
"4": "2,500",
"5": "3,500",
"6": "6,000",
"7": "15,000",
"8": "50,000",
"9": "50,000+"
}'
/>
输出数据的结构看起来略有不同,因为每个值都不是一个字符串,而是一个字符串数组。
<div
class="pricing-item-price"
data-price-output='{
"0": ["", "Free", ""],
"1": ["$", "13", "/m"],
"2": ["$", "17", "/m"],
"3": ["$", "21", "/m"],
"4": ["$", "25", "/m"],
"5": ["$", "42", "/m"],
"6": ["$", "58", "/m"],
"7": ["$", "117", "/m"],
"8": ["$", "208", "/m"],
"9": ["", "Contact us", ""]
}'
>
定义 JavaScript 变量
由于我们可能需要在页面上显示多个价格滑块,让我们收集所有具有pricing-slider该类名的元素,并遍历它们。
const pricingSliders = document.querySelectorAll(".pricing-slider");
if (pricingSliders.length > 0) {
for (let i = 0; i < pricingSliders.length; i++) {
const pricingSlider = pricingSliders[i];
}
}
现在我们已经用常量定义了价格滑块,我们可以继续存储元素和数据,包括输入和输出。
为此,我们将创建:
pricingInput包含与范围滑块(输入)相关的内容的对象- 一个
pricingOutput包含输出元素和数据的变量。它是一个数组,因为正如前面所说,我们可能有多个输出😉
if (pricingSliders.length > 0) {
for (let i = 0; i < pricingSliders.length; i++) {
const pricingSlider = pricingSliders[i];
// Build the input object
const pricingInput = {
el: pricingSlider.querySelector("input")
};
pricingInput.data = JSON.parse(
pricingInput.el.getAttribute("data-price-input")
);
pricingInput.currentValEl = pricingSlider.querySelector(
".pricing-slider-value"
);
pricingInput.thumbSize = parseInt(
window
.getComputedStyle(pricingInput.currentValEl)
.getPropertyValue("--thumb-size"),
10
);
// Build the output array
const pricingOutputEls = pricingSlider.parentNode.querySelectorAll(
".pricing-item-price"
);
const pricingOutput = [];
for (let i = 0; i < pricingOutputEls.length; i++) {
const pricingOutputEl = pricingOutputEls[i];
const pricingOutputObj = {};
pricingOutputObj.currency = pricingOutputEl.querySelector(
".pricing-item-price-currency"
);
pricingOutputObj.amount = pricingOutputEl.querySelector(
".pricing-item-price-amount"
);
pricingOutputObj.after = pricingOutputEl.querySelector(
".pricing-item-price-after"
);
pricingOutputObj.data = JSON.parse(
pricingOutputEl.getAttribute("data-price-output")
);
pricingOutput.push(pricingOutputObj);
}
}
}
让我们看看这些物体里面有什么📦
| 多变的 | 返回 |
|---|---|
pricingInput.el |
<input type="range" />元素 |
pricingInput.data |
{0: "1,000", 1: "1,250", ... }目的 |
pricingInput.currentValEl |
<div class="pricing-slider-value">元素 |
pricingInput.thumbSize |
36滑块滑块大小(从 CSS 解析) |
pricingOutput[n].currency |
<span class="pricing-item-price-currency">元素 |
pricingOutput[n].amount |
<span class="pricing-item-price-amount">元素 |
pricingOutput[n].after |
<span class="pricing-item-price-after">元素 |
pricingOutput[n].data |
{0: ["", "Free", ""], ... }目的 |
设置范围滑块属性
现在我们可以继续设置范围滑块min、max和value属性。
if (pricingSliders.length > 0) {
for (let i = 0; i < pricingSliders.length; i++) {
const pricingSlider = pricingSliders[i];
// [ ... previously defined variables ... ]
// set input range min attribute (0)
pricingInputEl.setAttribute("min", 0);
// set input range max attribute (9, i.e. the number of values)
pricingInputEl.setAttribute("max", Object.keys(priceInput).length - 1);
// initial slider value (0, or any other value if assigned via HTML)
!pricingInputEl.getAttribute("value") &&
pricingInputEl.setAttribute("value", 0);
}
}
太棒了!我们有一个范围滑块,数值从 0 到 9 🙌
下一步是将与当前范围值(例如)对应的滑块值(例如)输出到元素中。1,0000<div class="pricing-slider-value">
为此,我们需要创建一个函数,以便在用户每次与幻灯片交互时调用该函数。显然,我们需要将输入和输出对象作为参数传递。
function handlePricingSlide(input, output) {
// output the current slider value
if (input.currentValEl)
input.currentValEl.innerHTML = input.data[input.el.value];
}
我们把这个函数叫做📢
if (pricingSliders.length > 0) {
for (let i = 0; i < pricingSliders.length; i++) {
const pricingSlider = pricingSliders[i];
// [ ... previously defined variables ... ]
// [ ... previous range slider attributes assignment ... ]
handlePricingSlider(pricingInput, pricingOutput);
window.addEventListener("input", function() {
handlePricingSlider(pricingInput, pricingOutput);
});
}
}
结果如下👇
使用 JavaScript 绑定输入和输出数据
我们已经有了可用的价格范围滑块,但它仍然与可视化的价格数据脱节。现在需要将滑块的输入值与输出价格数据绑定起来。
function handlePricingSlide(input, output) {
// output the current slider value
if (input.currentValEl)
input.currentValEl.innerHTML = input.data[input.el.value];
// update prices
for (let i = 0; i < output.length; i++) {
const outputObj = output[i];
if (outputObj.currency) outputObj.currency.innerHTML = outputObj.data[input.el.value][0];
if (outputObj.amount) outputObj.amount.innerHTML = outputObj.data[input.el.value][1];
if (outputObj.after) outputObj.after.innerHTML = outputObj.data[input.el.value][2];
}
}
我们基本上是遍历每个pricingOutput对象,并将值输出currency到amount目标after元素中。
调整滑块值元素位置
快完成了。🏁 我们希望滑块的值能够跟随滑块滑块的移动而变化。
让我们创建一个函数来计算要应用于滑块值元素的左侧值。
function handleSliderValuePosition(input) {
const multiplier = input.el.value / input.el.max;
const thumbOffset = input.thumbSize * multiplier;
const priceInputOffset =
(input.thumbSize - input.currentValEl.clientWidth) / 2;
input.currentValEl.style.left =
input.el.clientWidth * multiplier - thumbOffset + priceInputOffset + "px";
}
该函数用于确定滑块值的正确位置,使元素与滑块滑块水平对齐。以下是该函数功能的示意图👇
请注意,缩略图大小值是通过该getComputedStyle()方法解析的(参见我们定义 JS 变量的段落)。这样,我就可以在 CSS 中更改缩略图大小,而无需更改 JavaScript 文件中的任何内容。
设置默认滑块值
如果您想设置除 0 以外的初始滑块值Free,只需value="n"向范围滑块添加一个属性即可。
例如,<input type="range" value="1" />将返回一个范围滑块,其1,000初始滑块值为。
结论
以下是最终结果。点击“打开沙盒”查看完整代码。
希望您喜欢这篇教程。如果您想查看实际应用示例,这里有一个应用了此功能的落地页模板 👉 Surface
文章来源:https://dev.to/cruip/how-to-build-a-pricing-slider-html-vanilla-js-53d0


