бизнес фон
При выполнении действий часто возникает необходимость реализации различных всплывающих окон.Существует несколько общих проблем, с которыми необходимо разобраться, в том числе:
- Проблема со скользящим проникновением: скользящие всплывающие элементы вызывают прокрутку фоновых элементов
- Проблема с несколькими всплывающими окнами: при наличии нескольких всплывающих окон последнее всплывающее окно всегда находится на верхнем уровне.
- Появление/исчезновение анимации перехода
выполнить
Опубликованный пакет npm приветствует отзыв и звезду~
npm install jdc-popup -S
github: GitHub.com/Winnie C имеет/просто…
demo: У Винни С есть .GitHub.io/motor-popup/…
Проблема со скользящим проникновением
исходное решение
При открытии плавающего слоя нижний элемент фиксируется, и чтобы положение тела соответствовало положению перед открытием плавающего слоя, установите верхнее смещение на текущий scrollTop;
Восстановить состояние нижнего элемента и высоту прокрутки при закрытии плавающего слоя;
controlledBgScrolled() {
let bgEle = document.getElementById('app');
// 打开浮层
if (this.showPopup) {
let top = document.documentElement.scrollTop
|| window.pageYOffset
|| document.body.scrollTop;
this.scrollTop = top;
bgEle.style.position = 'fixed';
bgEle.style.top = `-${top}px`;
bgEle.style.height = '100%';
}
else {
bgEle.style.position = 'relative';
bgEle.style.top = '';
bgEle.style.height = '100%';
document.documentElement.scrollTop = this.scrollTop;
window.pageYOffset = this.scrollTop;
document.body.scrollTop = this.scrollTop;
}
}
Недостатками этой схемы являются:
- Когда вы открываете/закрываете всплывающее окно, вы можете увидеть мигание
- На встроенной странице приложения есть вероятность конфликта с собственным приложением.
Реализовано с помощью библиотеки
Время для проверки ошибок актуально, поэтому для решения проблемы была непосредственно внедрена существующая библиотека.После тестирования под ios8+ и android4.4+ проблем не обнаружено.
Исходный код библиотеки относительно ясен. Предыдущая личная идея заключалась в том, чтобы получить набор кодов, совместимых с каждым концом. Эта библиотека подразделяет проблему и обрабатывает разные концы по-разному, что упрощает совместимость. Ни одна из этих трех схем не совместима полностью со всеми терминалами, подробности см. в [2].
Сторона ПК
Реализация на стороне ПК относительно проста, установив телоoverflow: hiddenПросто нормально.
const $body = document.querySelector('body')
const bodyStyle = { ...$body.style }
const scrollBarWidth = window.innerWidth - document.body.clientWidth
// 打开浮层时
$body.style.overflow = 'hidden'
$body.style.boxSizing = 'border-box'
$body.style.paddingRight = `${scrollBarWidth}px`
// 关闭浮层时,恢复原始设置
['overflow', 'boxSizing', 'paddingRight']
.forEach((x: OverflowHiddenPcStyleType) => {
$body.style[x] = bodyStyle[x] || ''
}
Сторона Android
Реализация на стороне Android в основном такая же, как и личное решение.При открытии всплывающего слоя фиксируется нижний элемент и устанавливается верхнее смещение.При закрытии плавающего слоя сцена восстанавливается.Обратите внимание, что нижний элемент должен быть установлен одновременно с html и телом.
const scrollTop = $html.scrollTop || $body.scrollTop
const htmlStyle = { ...$html.style }
const bodyStyle = { ...$body.style }
// 打开浮层时,fixed底部
$html.style.height = '100%'
$html.style.overflow = 'hidden'
$body.style.top = `-${scrollTop}px`
$body.style.width = '100%'
$body.style.height = 'auto'
$body.style.position = 'fixed'
$body.style.overflow = 'hidden'
// 关闭浮层时,恢复现场
$html.style.height = htmlStyle.height || ''
$html.style.overflow = htmlStyle.overflow || ''
['top', 'width', 'height', 'overflow', 'position']
.forEach((x: OverflowHiddenMobileStyleType) => {
$body.style[x] = bodyStyle[x] || ''
})
window.scrollTo(0, scrollTop)
Сторона iOS
Когда плавающий слой открыт на стороне iOS, нижний слой отключается.touchmoveСобытие, если элемент внутри всплывающего окна должен прокручиваться, он будет обработан другой функцией. Удаляет все прослушиватели событий при закрытии оверлея. После тестирования это решение имеет шанс прокрутить нижний элемент, когда всплывающее окно прокручивается до границы под Android. Библиотека не прокручивается при первом открытии на iPhone 6p.
/*** 打开浮层时,处理浮层和底部元素的滚动事件 ***/
// 1. targetElement为需要滚动的元素容器,处理其滚动
if (targetElement && lockedElements.indexOf(targetElement) === -1) {
targetElement.ontouchstart = (event) => {
initialClientY = event.targetTouches[0].clientY
}
targetElement.ontouchmove = (event) => {
if (event.targetTouches.length !== 1) return
// 手动处理滚动
handleScroll(event, targetElement)
}
// 记录可滚动元素
lockedElements.push(targetElement)
}
const handleScroll = (event, targetElement) => {
const clientY = event.targetTouches[0].clientY - initialClientY
if (targetElement) {
const { scrollTop, scrollHeight, clientHeight } = targetElement
// 向上滚动时 且 已经到达顶部
const isOnTop = clientY > 0 && scrollTop === 0
// 当向下滚动 且 已经到达底部
const isOnBottom = clientY < 0
&& scrollTop + clientHeight + 1 >= scrollHeight
if (isOnTop || isOnBottom) {
return preventDefault(event)
}
}
event.stopPropagation()
return true
}
// 2. 禁止document的touchMove事件
if (!documentListenerAdded) {
document.addEventListener(
'touchmove',
preventDefault,
eventListenerOptions)
documentListenerAdded = true
}
/*** 关闭浮层时,移除时间监听 ***/
if (targetElement) {
const index = lockedElements.indexOf(targetElement)
if (index !== -1) {
targetElement.ontouchmove = null
targetElement.ontouchstart = null
lockedElements.splice(index, 1)
}
}
if (documentListenerAdded) {
document.removeEventListener(
'touchmove',
preventDefault,
eventListenerOptions)
documentListenerAdded = false
}
Как реализованы библиотеки компонентов пользовательского интерфейса?
Библиотека может лучше выполнить это требование, но для небольших проблем, таких как скользящее проникновение, каждый раз вводить библиотеку довольно сложно. Исходя из вышеизложенных соображений, для сравнения их реализаций были выбраны nutui/youzi vant/mintui от JD.com.Сравнение выглядит следующим образом:
| Библиотека компонентов | Реализовать идеи | форма реализации |
|---|---|---|
| vant | сенсорная обработка событий | миксины, извлекающие сложную логику мультиплексирования |
| mint | сенсорная обработка событий | миксины, извлекающие сложную логику, но схема реализации зависит от структуры компонента, да и переиспользование не сильно |
| nut | фиксированный нижний фон | Внутренняя функция компонента лаконична и легко читается, а повторное использование не сильно |
После сравнения трех схем и собственно тестирования (iOS8+/Android4+) все равно совместима не со всеми моделями, в итоге компоненты упакованы по основной идее библиотеки.
Кроме того, несмотря на плохую совместимость overscroll-behavior, собственный браузер Android и браузер Chrome по-прежнему имеют частичную поддержку.
// 对于半透明蒙层阻止滚动
mask.addEventListener(
'touchmove',
this.preventDefault,
{ capture: false, passive: false },
false);
// 对可滚动元素容器手动处理滚动
onTouchMove(event, targetElement) {
...
if (targetElement) {
const {
scrollTop,
scrollHeight,
clientHeight
} = targetElement
// 向上滚动时 且 已经到达顶部
const isOnTop = this.deltaY > 0 && scrollTop === 0
// 当向下滚动 且 已经到达底部
const isOnBottom = this.deltaY < 0
&& scrollTop + clientHeight + 1 >= scrollHeight
if (isOnTop || isOnBottom) {
this.preventDefault(event)
}
}
event.stopPropagation()
return true
}
// 关闭弹窗时,移除所有事件
...
Проблема с несколькими всплывающими окнами
Когда два всплывающих окна открываются в текущий момент времени, пользователь ожидает, что всплывающее окно, открытое позже, будет на верхнем уровне.Короче говоря, новое всплывающее окно всегда будет на верхнем уровне. Вы можете создать новое всплывающее окно, записав текущий максимальный zIndexzIndex = zIndex+1. Кроме того, проблема скользящего проникновения также должна быть решена в случае нескольких всплывающих окон.Для нетекущих всплывающих окон верхнего уровня на них не должна влиять прокрутка.
this.$el.style.zIndex = context.zIndex + 1;
context.zIndex += 1;
расширять
Стиль всплывающего окна в бизнесе, как правило, более сложный. Если это простой и общий всплывающий стиль окна, если вы хотите решить проблему проникновения скольжения, вы можете использоватьVue.extendРасширение, непосредственно монтирует компонент всплывающего окна под документ (аналогичный подход используется в element-ui), оно не повлияет на основной контент, и его более гибко вызывать.
Ссылаться на
[1] tua-scroll-body-lock:Кролик A team.GitHub.IO/figure-body-generate…
[2] Скользящее проникновение (корпус замка) окончательное исследование]:nuggets.capable/post/684490…
[3] всплывающее окно]:blog.CSDN.net/riddle1981/…
[4] НУТУИ:github.com/jdf2e/nutui
коммерческое время
Feishu — это офисный пакет ByteDance, который глубоко интегрирует такие функции, как мгновенная связь, совместная работа в Интернете, аудио- и видеоконференции, календарь, облачный диск и рабочее место, чтобы предоставить пользователям универсальные возможности для совместной работы. В настоящее время клиенты услуг Feishu охватывают многие области, такие как Интернет-технологии, информационные технологии, производство, строительство и недвижимость, корпоративные услуги, образование и средства массовой информации. Добро пожаловать в команду ByteDance Feishu, существует большое количество front-end и back-end HC ~ отсканируйте QR-код или нажмите на ссылку для доставки, ищите команду Feishu👍~
【Набор в школу】Внутренний push-код: HZNVPHS, ссылка для доставки:job.toutiao.com/s/JaeUCoc
【Социальный набор】Ссылка для доставки:job.toutiao.com/s/JaevUNo