Задать вопрос
@msdoc11

Как переделать код для множества segmented control?

Здравствуйте, есть код
<div class="segmented-control">
        <span class="selection"></span>

        <div class="option">
            <input type="radio" id="metro" name="sample" value="metro" checked>
            <label for="metro"><span>Html</span></label>
        </div>

        <div class="option">
            <input type="radio" id="bus" name="sample" value="bus">
            <label for="bus"><span>Css</span></label>
        </div>

        <div class="option">
            <input type="radio" id="train" name="sample" value="train">
            <label for="train"><span>Javascript</span></label>
        </div>
    </div>

body,
html {
    height: 100%;
    margin: 0;
    padding: 0;
    text-rendering: geometricPrecision;
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
    font-family: -apple-system, system-ui, BlinkMacSystemFont, "Segoe UI",
        Roboto, "Helvetica Neue", Arial, sans-serif;
    -webkit-overflow-scrolling: touch !important;
    touch-action: manipulation !important;
    -webkit-tap-highlight-color: rgba(0, 0, 0, 0);
}

body {
    display: flex;
}

* {
    box-sizing: border-box;
}

body main {
    margin: auto;
}

label {
    cursor: inherit;
}

.segmented-control {
    --background: rgba(239, 239, 240, 1);
    background: var(--background);
    border-radius: 9px;
    margin: 0;
    padding: 2px;
    border: none;
    outline: none;
    display: grid;
    grid-auto-flow: column;
    grid-auto-columns: 1fr;
    -webkit-user-select: none;
    -moz-user-select: none;
    -ms-user-select: none;
    user-select: none;
}

.segmented-control .option {
    position: relative;
    cursor: pointer;
}

.segmented-control .option:hover input:not(:checked) + label span,
.segmented-control .option:active input:not(:checked) + label span,
.segmented-control .option:focus input:not(:checked) + label span {
    //opacity: 0.2;
}

.segmented-control .option:active input:not(:checked) + label span {
    transform: scale(0.95);
}

.segmented-control .option label {
    position: relative;
    display: block;
    text-align: center;
    padding: 3px 6vmin;
    background: rgba(255, 255, 255, 0);
    font-weight: 500;
    color: rgba(0, 0, 0, 1);
    font-size: 14px;
}

.segmented-control .option label::before,
.segmented-control .option label::after {
    content: "";
    width: 1px;
    background: rgba(142, 142, 147, 0.15);
    position: absolute;
    top: 14%;
    bottom: 14%;
    border-radius: 10px;
    will-change: background;
    -webkit-transition: background 0.2s ease;
    transition: background 0.2s ease;
}

.segmented-control .option label::before {
    left: 0;
    transform: translateX(-0.5px);
}

.segmented-control .option label::after {
    right: 0;
    transform: translateX(0.5px);
}

.segmented-control .option:first-of-type {
    grid-column: 1;
    grid-row: 1;
    box-shadow: none;
}

.segmented-control .option:first-of-type label::before {
    opacity: 0;
}

.segmented-control .option:last-of-type label::after {
    opacity: 0;
}

.segmented-control .option input {
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    width: 100%;
    height: 100%;
    padding: 0;
    margin: 0;
    -webkit-appearance: none;
    -moz-appearance: none;
    appearance: none;
    outline: none;
    border: none;
    opacity: 0;
}

.segmented-control .selection {
    background: rgba(255, 255, 255, 1);
    border: 0.5px solid rgba(0, 0, 0, 0.04);
    box-shadow: 0 3px 8px 0 rgba(0, 0, 0, 0.12), 0 3px 1px 0 rgba(0, 0, 0, 0.04);
    border-radius: 7px;
    grid-column: 1;
    grid-row: 1;
    z-index: 2;
    will-change: transform;
    -webkit-transition: transform 0.2s ease;
    transition: transform 0.2s ease;
}

.segmented-control .option label span {
    display: block;
    position: relative;
    z-index: 2;
    -webkit-transition: all 0.2s ease;
    transition: all 0.2s ease;
    will-change: transform;
    padding: 5px;
}

.segmented-control .option input:checked + label::before,
.segmented-control .option input:checked + label::after {
    background: var(--background);
    z-index: 1;
}

.segmented-control .option input:checked + label {
    cursor: default;
}

// Constants
const SEGMENTED_CONTROL_BASE_SELECTOR = ".segmented-control";
const SEGMENTED_CONTROL_INDIVIDUAL_SEGMENT_SELECTOR =
    ".segmented-control .option input";
const SEGMENTED_CONTROL_BACKGROUND_PILL_SELECTOR =
    ".segmented-control .selection";
// Main
document.addEventListener("DOMContentLoaded", setup);
// Body functions
function setup() {
    forEachElement(SEGMENTED_CONTROL_BASE_SELECTOR, (elem) => {
        elem.addEventListener("change", updatePillPosition);
    });
    window.addEventListener("resize", updatePillPosition); // Prevent pill from detaching from element when window resized. Becuase this is rare I haven't bothered with throttling the event
}

function updatePillPosition() {
    forEachElement(
        SEGMENTED_CONTROL_INDIVIDUAL_SEGMENT_SELECTOR,
        (elem, index) => {
            if (elem.checked) moveBackgroundPillToElement(elem, index);
        }
    );
}

function moveBackgroundPillToElement(elem, index) {
    console.log(elem.offsetWidth * index);
    document.querySelector(
        SEGMENTED_CONTROL_BACKGROUND_PILL_SELECTOR
    ).style.transform = "translateX(" + elem.offsetWidth * index + "px)";
}
// Helper functions
function forEachElement(className, fn) {
    Array.from(document.querySelectorAll(className)).forEach(fn);
}


Не могу понять как переделать, чтобы можно было множество сегментов иметь на странице, сейчас только один работает
  • Вопрос задан
  • 52 просмотра
Подписаться 1 Простой 1 комментарий
Решения вопроса 1
0xD34F
@0xD34F Куратор тега JavaScript
const controls = document.querySelectorAll('.segmented-control');
controls.forEach(n => n.addEventListener('change', updatePillPosition));
window.addEventListener('resize', () => controls.forEach(n => updatePillPosition.call(n)));

function updatePillPosition() {
  const inputs = [...this.querySelectorAll('.option input')];
  const x = this.offsetWidth / inputs.length * inputs.findIndex(n => n.checked);
  this.querySelector('.selection').style.transform = `translateX(${x}px)`;
}
Ответ написан
Комментировать
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы