Как определить, находится ли элемент вне его контейнера? - PullRequest
1 голос
/ 28 октября 2019

Итак, я создал следующие codesandbox . У меня есть веб-приложение, которое сильно зависит от пользовательского ввода. В демонстрационных целях я упростила задачу, разместив группу авторов на странице в формате a4. Оба устройства page и font-size используют устройство vw, чтобы сделать его отзывчивым.

Как видно из кода и окна, последние несколько авторов вынуждены покинуть страницу, поскольку она больше не помещается внутри контейнера. В идеале я хотел бы обнаружить контент, который больше не помещается на странице, и сгенерировать вторую идентичную страницу a4 для отображения этого конкретного контента.

В настоящее время в моем веб-приложении я только что добавил overflow: scroll; на страницу div, где размещен весь контент, чтобы он хотя бы выглядел несколько «хорошо». Но это не очень хороший пользовательский опыт, и я хотел бы улучшить его.

Я понятия не имею, с чего начать, поэтому любая помощь в правильном направлении будет очень цениться.

Заранее спасибо.

CSS

#app {
  -webkit-font-smoothing: antialiased;
  font: 12pt "Tahoma";
}

.book {
  margin: 0;
  padding: 0;
  background-color: #FAFAFA;
  font: 3vw "Tahoma";
}

* {
  box-sizing: border-box;
  -moz-box-sizing: border-box;
}

.page {
  /* overflow: scroll; */
  display: block;
  width: calc(100 / 23 * 21vw);
  height: calc(100 / 23 * 29.7vw);
  margin: calc(100 / 23 * 1vw) auto;
  border: 1px #D3D3D3 solid;
  border-radius: 5px;
  background: white;
  box-shadow: 0 0 5px rgba(0, 0, 0, 0.1);
}

.subpage {
  margin: calc(100 / 23 * 1vw);
  width: calc(100 / 23 * 19vw);
  height: calc(100 / 23 * 27.7vw);
  line-height: 2;
  border: 1px solid red;
  outline: 0cm #FAFAFA solid;
}

.subpage-content {
  height: 100%;
}

Javascript

export default {
  name: "App",
  data() {
    return {
      authors: [
        { id: 1, name: "Smith" },
        { id: 2, name: "Johnson" },
        { id: 3, name: "Williams" },
        { id: 4, name: "Jones" },
        { id: 5, name: "Brown" },
        { id: 6, name: "Davis" },
        { id: 7, name: "Miller" },
        { id: 8, name: "Wilson" },
        { id: 9, name: "Moore" },
        { id: 10, name: "Taylor" },
        { id: 11, name: "Anderson" },
        { id: 12, name: "Thomas" },
        { id: 13, name: "Jackson" },
        { id: 14, name: "White" },
        { id: 15, name: "Harris" },
        { id: 16, name: "Martin" },
        { id: 17, name: "Thomspson" },
        { id: 18, name: "Garcia" },
        { id: 19, name: "Martinez" },
        { id: 20, name: "Robinson" },
        { id: 21, name: "Clark" },
        { id: 22, name: "Rodeiquez" },
        { id: 23, name: "Lewis" },
        { id: 24, name: "Lee" }
      ]
    };
  }
};

HTML

<template>
  <div id="app">
    <div class="container-fluid">
      <div class="book">
        <div class="page">HEADER
          <div class="subpage" id="editor-container">Authors:
            <!-- <div class="subpage-content">The real content</div> -->
            <div v-for="item in authors" :key="item.id">{{ item.name }}</div>
          </div>
        </div>
      </div>
    </div>
  </div>
</template>

1 Ответ

1 голос
/ 02 ноября 2019

Вы можете просмотреть вилку вашей песочницы кода здесь .

Я изменил структуру данных (и шаблон), чтобы иметь массив pages, в котором каждая страница имеет authors массив, а не один. Первоначально первая страница содержит всех авторов.


data() {
  return {
    pages: [
      {
        authors: [
          { id: 1, name: "Smith" },
          ...
        ]
      }
    ]
  }
}
<div class="page" v-for="(page, pageIndex) in pages" :key="pageIndex">HEADER
  <div class="subpage" id="editor-container">
    <template v-if="pageIndex < 1">Authors:</template>
    <!-- <div class="subpage-content">The real content</div> -->
    <div v-for="item in page.authors" :key="item.id" class="author">{{ item.name }}</div>
  </div>
</div>

Затем я создал метод recalcPages, который вызывается при монтировании компонента:

  methods: {
    recalcPages() {
      let pageElements = this.$el.querySelectorAll(".page");
      Array.from(pageElements).some((p, pi) => {
        let authors = p.querySelectorAll(".author");
        if (authors.length) {
          return Array.from(authors).some((a, ai) => {
            let offPage = a.offsetTop + a.offsetHeight > p.offsetHeight;
            if (offPage) {
              let currentAuthors = this.pages[pi].authors;
              var p1 = currentAuthors.slice(0, ai);
              var p2 = currentAuthors.slice(ai);

              this.pages[pi].authors = p1;
              this.pages.push({ authors: p2 });
            }
            return offPage;
          });
        }
        return false;
      });
    }
  },

Итерируетфактические узлы DOM и используют offsetTop + offsetHeight, чтобы вычислить, находится ли автор на странице или нет. Как только элемент покидает страницу, он и все последующие элементы отделяются от authors текущей страницы и вставляется вторая страница.

Вам также потребуется вызвать this.recalcPages() после обновления содержимогоудалив все страницы и установив новый массив authors на первом, который будет автоматически разделяться снова, если только вы не добавляете только последнюю страницу. Вы также можете попытаться использовать хук updated для достижения этого автоматически, я не пробовал этого.

Конечно, это довольно тяжелая операция, так как она рендерит компонент только для повторного рендеринга с помощьюизменение данных. Но если вы не знаете точную высоту каждого элемента, вы не сможете обойти его (по крайней мере, я не знаю).

Кстати (хотя ваши окончательные данные, вероятно, будут выглядеть иначе, нопросто для полноты этой демонстрации) Я также завернул ваш Authors: заголовок в <template v-if="pageIndex < 1">Authors:</template>, чтобы отображать его только на первой странице.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...