Javascript.RU

Создать новую тему Ответ
 
Опции темы Искать в теме
  #1 (permalink)  
Старый 29.03.2022, 13:10
Профессор
Отправить личное сообщение для Teamur Посмотреть профиль Найти все сообщения от Teamur
 
Регистрация: 08.06.2015
Сообщений: 206

Прокрутка к первой картинке из добавленных через input[type='file']
В #bar отображается #box.scrollTop. <main> намеренно размещен так, чтобы были видны полосы прокрутки и была возможность увидеть что и куда сдвигается. #bar прокручивает список к текущей картинке img.c, чтобы она была первой в области просмотра. Но здесь вся страница сдвигается нежелательным образом.

Гипотетически, косяк может быть в том, что при переборе файлов нужна асинхронность.

<!DOCTYPE html><meta charset='utf-8'>
<style>
  body{margin: 0 }
  main{ width: 200px; display: grid; grid-template-rows: 24px 300px 24px;
    margin: 100px auto 50vh; user-select: none }
  #box{ border: 2px solid #000; overflow-y: auto; overscroll-behavior-y:contain }
  #bar,#bot{ border: 2px solid #777; padding-left: 1ch; }
  :is(#bar,#bot):hover{background-color: #eee;}
  :is(#bar,#bot):active{background-color: #ccc;}
  img{display: block; width: 100%;}
  .c{ outline: 5px solid #7cf; outline-offset: -5px; }
</style>
<main><div id=bar>0</div><div id=box></div><div id=bot>+ file</div></main>
<script>'use strict';
  const
  oo=console.log, {assign:set}=Object, {createObjectURL:url}=URL, {round}=Math,
  el=document.createElement.bind(document),

  cl_move=(from,to,...cl)=>( from.classList.remove(...cl), to.classList.add(...cl), to ),

  FI=set(el('input'),{
    type:'file',
    multiple:true,
    accept:'image/*',
    onchange(){
      let last=box.lastChild;
      for(let file of this.files){
        let image=el('img');
        image.src=url(file);
        box.append(image);
      };
      if(last!==null){
        oo('last',last);
        let next=last.nextSibling;
        oo('next',next);

        let c=box.getElementsByClassName('c');
        if(0 in c){ cl_move(c[0],next,'c') };

        next.scrollIntoView()
      }
      else{
        (last=box.firstChild).classList.add('c');
        last.scrollIntoView()
      }
    }
  });

  set(box,{
    onscroll(){
      bar.textContent=round(box.scrollTop)+', '+'?'
    },
    onclick({target:t}){
      if(t==this||this.childElementCount<1){ return };

      let c=this.getElementsByClassName('c');
      if(0 in c){
        [c]=c;
        if(t!=c){
          cl_move(c,t,'c')
        }
      }
      else{
        t.classList.add('c')
      }
    }
  });

  bar.onclick=function(){
    let c=box.getElementsByClassName('c');
    if(0 in c){
      c[0].scrollIntoView()
    }
  };

  bot.onclick=function(){
    FI.click()
  };

  ondragstart=()=>false

</script>

Есть 3 проблемы:
1) Когда box пуст, нужно чтобы он не сдвигался вместе со страницей, а именно, чтобы overscroll-behavior-y:contain сработал и при пустом box
2) Чтобы scrollIntoView прокручивал только список и ничего более. При этом, первая из добавленных картинок была бы в начале области просмотра
3) Если картинка ( кроме самой первой в box ) своей нижней частью не смогла перекрыть область просмотра, то принудительно добавить margin-bottom необходимой высоты так, чтобы картинка подтянулась к верхней границе области просмотра. При этом, если снова добавить картинки, margin-bottom удаляется, чтобы не было прогала.

И вместо знака вопроса во время прокрутки хотелось бы выводить расстояние от верхней границы области просмотра до текущей картинки ( img.c ). При этом, если она выше, то со знаком '-'.

Надеюсь, что всё получится !

Последний раз редактировалось Teamur, 29.03.2022 в 20:34.
Ответить с цитированием
  #2 (permalink)  
Старый 06.04.2022, 15:01
Профессор
Отправить личное сообщение для Teamur Посмотреть профиль Найти все сообщения от Teamur
 
Регистрация: 08.06.2015
Сообщений: 206

Что-то мало ответов, хотелось бы больше. Всё-таки, я описал проблемы и код приложил. Буду продолжать молиться )))
Ответить с цитированием
  #3 (permalink)  
Старый 06.04.2022, 15:56
Аватар для рони
Профессор
Отправить личное сообщение для рони Посмотреть профиль Найти все сообщения от рони
 
Регистрация: 27.05.2010
Сообщений: 33,105

Сообщение от Teamur
И вместо знака вопроса во время прокрутки хотелось бы выводить расстояние от верхней границы области просмотра до текущей картинки ( img.c ). При этом, если она выше, то со знаком '-'.
onscroll(){
            let t = document.querySelector('img.c');
            t = t ? (t.getBoundingClientRect().top - box.getBoundingClientRect().top)|0 : '?';
            bar.textContent=round(box.scrollTop)+', '+ t;
        },
Ответить с цитированием
  #4 (permalink)  
Старый 06.04.2022, 16:17
Аватар для рони
Профессор
Отправить личное сообщение для рони Посмотреть профиль Найти все сообщения от рони
 
Регистрация: 27.05.2010
Сообщений: 33,105

Teamur,
//next.scrollIntoView();
                window.setTimeout(_ => box.scrollTop = box.scrollHeight, 300);
Ответить с цитированием
  #5 (permalink)  
Старый 06.04.2022, 20:05
Профессор
Отправить личное сообщение для Teamur Посмотреть профиль Найти все сообщения от Teamur
 
Регистрация: 08.06.2015
Сообщений: 206

рони, спасибо.
Правильно ли я понимаю, что scrollIntoView срабатывает раньше, чем подгружаются все картинки, в этом причина?
Или причина в другом?
И при переборе файлов действия выполнять при событии onload?
Просто, хотелось бы обойтись без счётчиков setTimeout и тп.

Последний раз редактировалось Teamur, 07.04.2022 в 00:38.
Ответить с цитированием
  #6 (permalink)  
Старый 06.04.2022, 20:33
Аватар для рони
Профессор
Отправить личное сообщение для рони Посмотреть профиль Найти все сообщения от рони
 
Регистрация: 27.05.2010
Сообщений: 33,105

Teamur,
с помощью scrollIntoView затруднительно получить нужный вам эффект, и лучше управлять прокруткой в "ручном режиме", или по таймеру или по счётчику в onload.
Ответить с цитированием
  #7 (permalink)  
Старый 06.04.2022, 21:43
Аватар для рони
Профессор
Отправить личное сообщение для рони Посмотреть профиль Найти все сообщения от рони
 
Регистрация: 27.05.2010
Сообщений: 33,105

images preview
Teamur,

<!DOCTYPE html>
<meta charset='utf-8'>
<style>
    body {
        margin: 0
    }

    main {
        width: 200px;
        display: grid;
        grid-template-rows: 24px 300px 24px;
        margin: 100px auto 50vh;
        user-select: none
    }

    #box {
        border: 2px solid #000;
        overflow-y: auto;
        overscroll-behavior-y: contain
    }

    #bar,
    #bot {
        border: 2px solid #777;
        padding-left: 1ch;
    }

    :is(#bar, #bot):hover {
        background-color: #eee;
    }

    :is(#bar, #bot):active {
        background-color: #ccc;
    }

    img {
        display: block;
        width: 100%;
    }

    .c {
        outline: 5px solid #7cf;
        outline-offset: -5px;
    }
</style>
<main>
    <div id=bar>0</div>
    <div id=box></div>
    <div id=bot>+ file</div>
</main>
<script>
    'use strict';
    const
        oo = console.log,
        {
            assign: set
        } = Object,
        {
            createObjectURL: url
        } = URL,
        {
            round
        } = Math,
        el = document.createElement.bind(document),
        mainViewTopCenter = function() {
            let main = document.querySelector('main');
            let pos = main.getBoundingClientRect();
            let y = (document.documentElement.clientHeight - main.scrollHeight) / 2 - pos.top;
            window.scrollBy(0, -y);

        },
        imgViewCenter = function(img) {
            let y = (img.getBoundingClientRect().top - box.getBoundingClientRect().top) | 0;
            box.scrollTop += y
        },
        imgToggle = function(img) {
            let old = box.querySelector('img.c');
            if (old && old !== img) old.classList.remove('c');
            img.classList.toggle('c')
        },
        cl_move = (from, to, ...cl) => (from.classList.remove(...cl), to.classList.add(...cl), to),

        FI = set(el('input'), {
            type: 'file',
            multiple: true,
            accept: 'image/*',
            onchange() {
                for (let file of this.files) {
                    let image = el('img');
                    image.onload = function() {
                        imgToggle(image);
                        imgViewCenter(image);

                    }
                    image.src = url(file);
                    box.append(image);
                };

            }
        });

    set(box, {
        onscroll() {
            let t = box.querySelector('img.c');
            t = t ? (t.getBoundingClientRect().top - box.getBoundingClientRect().top) | 0 : '?';
            bar.textContent = round(box.scrollTop) + ', ' + t;
        },
        onclick({
            target: t
        }) {
            if (t = t.closest('img')) imgToggle(t)
        }
    });

    bar.onclick = function() {
        let img = box.querySelector('img.c');
        if (img) imgViewCenter(img);
    };

    bot.onclick = function() {
        mainViewTopCenter();
        FI.click();
    };

    ondragstart = () => false;
    mainViewTopCenter();
</script>

Последний раз редактировалось рони, 06.04.2022 в 21:49.
Ответить с цитированием
  #8 (permalink)  
Старый 07.04.2022, 15:24
Профессор
Отправить личное сообщение для Teamur Посмотреть профиль Найти все сообщения от Teamur
 
Регистрация: 08.06.2015
Сообщений: 206

рони, спасибо. Ваш код мне очень пригодится !
Ответить с цитированием
Ответ



Опции темы Искать в теме
Искать в теме:

Расширенный поиск


Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
Бесконечная прокрутка текстовых строк, с рандомным окрашиванием через n секунд Lefseq Общие вопросы Javascript 1 25.10.2019 09:34