使用内置滑块编写图库生成器



朋友们,美好的一天!

代替介绍(问题陈述)


这一切都开始与其他人的滑块(在网络上现成的解决方案,如研究bxsliderowlcarousel光滑)。有一天,我将撰写有关使用这些工具的详细教程(美梦)。有一种写滑块的愿望。但是,很快(包括在阅读有关Habré的几篇文章后),人们意识到只有滑块才是w夫。需要一些更激进的东西。

结果,我提出了以下任务:编写带有内置滑块的自适应图库生成器。

条件:

  • 能够上传任意数量的图像(从硬盘上的任何位置)。
  • 画廊由上载的图像组成,标记是根据HTML5语义“即时”形成的。
  • 在不同分辨率的屏幕上,图库看起来同样不错。
  • 当您单击任何图像时,将生成一个滑块。
  • 生成滑块时,背景变暗。
  • 单击的图像是第一张幻灯片。
  • 幻灯片切换是通过DOM实现的。
  • 滑动开关平稳。
  • 使用按钮和键盘控制幻灯片切换的能力。
  • 通过单击当前幻灯片和按钮以及使用键盘可以返回画廊。
  • 纯JavaScript(所有标记都通过JS)。
  • 最小代码。

所以,让我们走(正如加加林所说的,去太空)。

标记如下所示:
<div class="wrap">
    <input type="file" multiple accept="image/*">
    <button>generate gallery</button>
</div>

在有趣的事情中,也许是输入标签的multiple和accept属性。第一个属性允许您上传多个文件,第二个属性-对可以下载的文件类型设置过滤器。在这种情况下,accept的值为“ image / *”,这意味着只能上传图像(任意)。

立即带来美丽(添加样式):
* {
    margin: 0;
    padding: 0;
    box-sizing: border-box;
}

body {
    min-height: 100vh;
    background: radial-gradient(circle, skyblue, steelblue);
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;
}

button {
    padding: 0.25em;
    font-family: monospace;
    text-transform: uppercase;
    cursor: pointer;
}

.darken {
    position: absolute;
    width: 100%;
    height: 100%;
    background: rgba(0, 0, 0, 0.4);
    z-index: -1;
}

.slider {
    width: 100%;
    display: inherit;
    flex-wrap: wrap;
    justify-content: center;
    align-items: center;
}

figure {
    margin: 0.5em;
    width: 300px;
    display: inherit;
    flex-direction: column;
    justify-content: center;
    align-items: center;
    transition: 0.2s;
}

figcaption {
    font-size: 1.2em;
    text-transform: capitalize;
    text-align: center;
    margin-bottom: 0.25em;
    color: #ddd;
    text-shadow: 1px 1px rgba(0, 0, 0, 0.4);
}

img {
    max-width: 80%;
    max-height: 80vh;
    cursor: pointer;
}

.button {
    position: absolute;
    top: 50%;
    transform: translateY(-50%);
    width: 30px;
    background: none;
    border: none;
    outline: none;
    filter: invert();
}

.left {
    left: 2em;
}

.right {
    right: 2em;
}

.close {
    top: 2em;
    right: 1em;
}


没有什么可谈的(.darken-变暗)。

继续...到JS。

我们找到按钮并将监听器挂在其上:
let button = document.querySelector("button");
button.addEventListener("click", generateGallery);

所有进一步的代码将在generateGallery函数中,以避免“未定义”而不返回:
function generateGallery() {
    //    
}

我们找到输入,检查它是否为空,获取下载文件的集合,删除.wrap并为图库创建一个容器:
let input = document.querySelector("input");
// ,  input  
if(input.files.length == 0) return;
let files = input.files;
//  
let i;

//  .wrap,     
let wrap = document.querySelector(".wrap");
document.body.removeChild(wrap);

//    , ,    gallery
let slider = document.createElement("div");
slider.className = "slider";
document.body.appendChild(slider);

我们对文件集合进行排序,获取每个文件的名称和地址,创建标记,创建图像标题和图像本身:
for (i = 0; i < files.length; i++) {
    let file = files[i];
    // URL.createObjectURL         ,         
    // ,   ,       
    //             ,      
    /*let src = URL.createObjectURL(file);*/

    //   
    let name = file.name;

    //   ,      img     
    let src = `img/${name}`;

    //  : figure, figcaption, img
    let figure = document.createElement("figure");
    slider.appendChild(figure);

    let figcaption = document.createElement("figcaption");

    //  ,             ,   
    // (?=\.) -  :     ,    
    //       \w,         
    let regexp = /.+(?=\.)/;
    name = name.match(regexp);
    //   ["", index: 0, input: ".jpg", groups: undefined]
    //    
    figcaption.innerText = name[0];
    figure.appendChild(figcaption);

    //  
    let img = document.createElement("img");
    img.src = src;
    figure.appendChild(img);
}

我们想在单击图像时生成一个滑块。为此,我们找到整个图形并将其挂在每个侦听器上:
let figures = document.querySelectorAll("figure");
for (i = 0; i < figures.length; i++) {
    let figure = figures[i];
    figure.addEventListener("click", () => {
        //  ,       figure,   
        generateSlider(figure);
    });
}

接下来,我们在generateSlider函数内部进行工作:
function generateSlider(figure) {
    //  
}

调暗背景:
darkenBack();
function darkenBack() {
    // ,   
    //  , ,   , 
    if (document.querySelector(".darken") == null) {
        let div = document.createElement("div");
        div.className = "darken";
        document.body.appendChild(div);
    } else {
        let div = document.querySelector(".darken");
        document.body.removeChild(div);
    }
}

我们将一次显示一张幻灯片。不要忘记滑动开关应该平滑。通过透明性和较小的过渡,这很容易实现。因此,我们将图像叠加在一起,将它们放置在中间,并使所有图像(“单击”的图像除外)透明:
for (i = 0; i < figures.length; i++) {
    if (figures[i].hasAttribute("style")) {
        figures[i].removeAttribute("style");
    } else {
        figures[i].setAttribute("style", "margin: 0; width: auto; position: absolute; opacity: 0;");
    }
}

//      / 
if (figure.hasAttribute("style")) {
    figure.style.opacity = 1;
    generateButtons();
} else generateButtons();

接下来,创建按钮以切换幻灯片并关闭图库。结果是很长很枯燥的代码(也许每次启动滑块时都生成按钮不是一个好主意):
按钮创建代码:
function generateButtons() {
    if (document.querySelector(".buttons") == null) {
        //    
        let buttons = document.createElement("div");
        buttons.className = "buttons";
        slider.appendChild(buttons);

        //   
        let leftButton = document.createElement("button");
        leftButton.className = "button left";
        let leftImg = document.createElement("img");
        leftImg.src = "https://thebestcode.ru/media/sliderGenerator/buttons/left.png";
        leftButton.appendChild(leftImg);
        buttons.appendChild(leftButton);
        leftButton.addEventListener("click", () => changeSlide("-"));

        //   
        let rightButton = document.createElement("button");
        rightButton.className = "button right";
        let rightImg = document.createElement("img");
        rightImg.src = "https://thebestcode.ru/media/sliderGenerator/buttons/right.png";
        rightButton.appendChild(rightImg);
        buttons.appendChild(rightButton);
        rightButton.addEventListener("click", () => changeSlide("+"));

        //    
        let closeButton = document.createElement("button");
        closeButton.className = "button close";
        let closeImg = document.createElement("img");
        closeImg.src = "https://thebestcode.ru/media/sliderGenerator/buttons/close.png";
        closeButton.appendChild(closeImg);
        buttons.appendChild(closeButton);
        closeButton.addEventListener("click", () => generateSlider(figure));
    } else {
        //   ,  
        let buttons = document.querySelector(".buttons");
        slider.removeChild(buttons);
    }
}


切换幻灯片是使用changeSlide函数实现的,该函数分别作为参数“ +”或“-”传递:
function changeSlide(e) {
    //    
    for (i = 0; i < figures.length; i++) {
        figures[i].style.opacity = 0;
    }
    if (e == "-") {
        //      ,    
        if (figure == figures[0]) {
            figure = figures[figures.length - 1];
        } else {
            figure = figure.previousElementSibling;
        }
    } else if (e == "+") {
        //      ,    
        if (figure == figures[figures.length - 1]) {
            figure = figures[0];
        } else {
            figure = figure.nextElementSibling;
        }
    }
    //    
    figure.style.opacity = 1;
}

添加使用键盘切换幻灯片和关闭图库的功能:
document.addEventListener("keydown", e => {
    //  
    if (e.keyCode == 37 || e.keyCode == 189) {
        changeSlide("-");
    //  
    } else if (e.keyCode == 39 || e.keyCode == 187) {
        changeSlide("+");
    // esc
    } else if(e.keyCode == 27) {
        generateSlider(figure);
    }
});

到此,带有内置滑块的自适应图库生成器已准备就绪。任务完成。满足条件。最后,我意识到“最小代码”和“使用JS即时形成所有标记”相互矛盾,但是为时已晚(道歉还为时已晚还是“一个共和国”呢?)。

结果可以在这里看到

请注意,在Codepen上,我们使用URL.createObjectURL链接到图像,因为Codepen看不到img文件夹。

感谢您的关注。

Source: https://habr.com/ru/post/undefined/


All Articles