Для некоторых быстрых итерационных продуктов, особенно мобильныхCтерминальные продукты, в зависимости от цели работы пользователя, вappДомашняя страница очень часто отображает различные всплывающие окна для пользователей.На ранней стадии продукта, поскольку итеративная версия и стратегия работы не слишком сильно изменились, это может показаться не таким уж большим, но когда продукт работает на более позднем этапе, различные Проблема возникает, когда стратегии операций, которые нельзя воспроизвести, меняются, а стиль и логика всплывающего окна менялись неизвестное количество раз.
Из-за отсутствия планирования на ранней стадии, на главной странице может быть более десяти или даже больше компонентов всплывающего окна. страницы.Эти подкомпоненты тоже включены.Возможно эти подкомпоненты нехорошие.Также есть подкомпоненты,и подкомпоненты подкомпонентов тоже имеют всплывающие окна.Каждому всплывающему окну соответствует набор отображения элементов управления и скрытой логики, разбросанных по множеству компонентов и множеству методов, но на домашней странице только одна страница, из-за которой могут всплывать сразу все всплывающие окна, удовлетворяющие условиям отображения, во всяком случае, такого я еще не видел случаться.app, то как управлять этими всплывающими окнами становится главным приоритетом
И часто, когда вы это понимаете, это, вероятно, также, когда ситуация выходит из-под контроля.Не лечится, жди смерти
Сценарий: всплывающее окно и всплывающее окно B расположены в основном компоненте, всплывающее окно C расположено в подкомпоненте C основного компонента, всплывающее окно D расположено в подкомпоненте B основного компонента, а всплывающее окно E расположено в подкомпоненте F основного компонента компонент G
ПМ: Я надеюсь, что при первом входе на эту страницу всплывающее окно D будет отображаться только тогда, когда всплывающее окно A, всплывающее окно B и всплывающее окно C не отображаются. всплывающее окно отображается, если только не отображается всплывающее окно B. Оно отображается снова, в противном случае всплывающее окно E не будет отображаться ни при каких обстоятельствах
ФЭ: ? ? ?
Поэтому очень важно предотвращать проблемы до того, как они произойдут.Не спрашивайте меня, как я получил это чувство
Если немного подумать, то на самом деле это не так уж и сложно.Просто предоставьте бэкенду возможность контролировать отображение и скрытие всех всплывающих окон через интерфейс.В основном предварительное планирование архитектуры и логика кода с низким уровнем связи.
Настройка всплывающих окон
Сначала определите общую идею.Прежде всего, вы должны четко знать, какие всплывающие компоненты являются общими для текущей страницы, включая подкомпоненты страницы и всплывающие компоненты в подкомпонентах подкомпонентов. .Это обязательно,а то у вас еще какие компоненты.Не знаете как это точно контролировать?
Итак, все еще вышеприведенное предложение, очень важно планировать заранее и предотвращать проблемы до того, как они возникнут, иначе, когда страница переделала десятки версий, а людей, которые написали код, больше нет, вам нужно только подсчитать, как на странице много пуль Окно, хватит тебе пить
Затем нужно записать все эти всплывающие окна в одно место для облегчения управления, таким образом можно получить следующую структуру данных:
// modalMap.js
export default {
// 记录首页 index页面内的弹窗项
index: {
modalList: [{
id: 1,
condition: 'modal_1',
level: 100,
feShow: true
}, {
id: 2,
condition: 'modal_2',
level: 22,
feShow: true
}, {
id: 3,
condition: 'modal_3',
level: 70,
feShow: false
}],
children: {
child1: {
modalList: [{
id: 11,
condition: 'condition_1_1',
level: 82,
feShow: true
}, {
id: 12,
condition: ['condition_1_2', 'condition_1_3', 'condition_1_4'],
level: 12,
feShow: true
}],
children: {
child1_1: {
modalList: [{
id: 21,
condition: ['condition_1_1_1', 'condition_1_1_2'],
level: 320,
feShow: true
}, {
id: 22,
condition: 'condition_1_1_3',
level: 300,
feShow: true
}]
}
}
}
}
}
// ...还可以继续记录其他页面的弹窗结构
}
modalMap.jsВ файл записываются все всплывающие элементы на каждой странице, например, на домашней странице.indexВсе всплывающие элементы внутри находятся в имени свойстваindexВ соответствующей структуре данных значенийindexВ этом главном компоненте страницы есть дваmodal,ихidсоответственно1а также2,еслиindexПодкомпоненты основного компонента этой страницы также имеютmodal, затем продолжить вложение, например,indexПодкомпонент основного компонентаchild1Также вmodal, затем поставьтеchild1помещатьindexизchildrenпродолжить запись и т.д.
Эта структура выглядит относительно ясно, основной компонент и подкомпоненты в основном компонентеmodalЭто очень ясно и понятно с первого взгляда.Конечно, вы не можете использовать эту структуру, это полностью на ваше усмотрение, вот определение на данный момент
каждыйmodalКромеidКроме того, естьcondition,levelа такжеshowАтрибуты
conditionОн существует как своего рода логотип, о котором будет сказано позже.levelиспользуется для определения текущегоmodalИерархический уровень, каждая страница может отображать только одну одновременноmodal, но если есть несколькоmodalвсе одновременно соответствуют условиям отображения, затем сравните ихlevelзначение, которое больше, будет отображаться первым, а остальные будут игнорироваться, чтобы предотвратить ситуацию, когда страница может предложить отобразить несколько всплывающих окон;
feShowсвойства находятся вmodalвнутренний решатьmodalОтображать ли его в конце, чтобы можно было игнорировать внешние условия и легко отключить отображение всплывающего окна через настройку в интерфейсе
Управление всплывающими окнами с помощью модели публикации/подписки
Структура конфигурации всплывающего окна определена, и следующим шагом является управление этими конфигурациями.
При нормальных обстоятельствах, когда несколько страниц соответствуют условиям и должны отображаться одновременно, большинство из них происходит, когда страница только что была открыта, и страница отправляет несколько запросов, а возвращаемые результаты этих запросов управляют отображением соответствующее всплывающее окно соответственно.
Поскольку эти отправленные запросы, скорее всего, принадлежат разным бизнес-направлениям или отделам и не зависят друг от друга, на самом деле немного сложно передать управление всплывающим окном серверной части, а запросы являются асинхронными. фронтенду непросто использовать спагетти-код для обеспечения взаимного исключения между всплывающими окнами.В совокупности это приводит к тому, что при переборе десятков всплывающих окон на странице, если заранее не планировать Ну, по-прежнему легко иметь проблему с одновременным отображением всплывающих окон.
Здесь пока мы возьмем случай простого входа на страницу в качестве примера, чтобы разобраться в логике.
В первую очередь мне нужно знать, какие всплывающие окна на странице могут всплывать при первом входе на страницу (т. получаются все всплывающие окна (т.е. следуйте интерфейсу, относящемуся к всплывающему окну, уже возвращены данные), а затем отображается всплывающее окно.
В этом случае удобнее использовать режим публикации/подписки.Отдача данных одного интерфейса — это подписка.При подписке на все интерфейсы — публикация, то есть отображение всплывающего окна
// modalManage.js
class ModalManage {
constructor () {
// ...
}
add () {
// ...
this.nodify()
}
notify () {
// ...
}
}
пройти черезModalManageкласс для управления всплывающими окнами, вnew ModalManageПри передаче идентификационного значения оно используется для предварительного информирования о том, что всегоnПодписки,addЭто метод подписки.Когда интерфейс возвращает информацию о том, отображает ли всплывающее окно информацию, он вызываетсяaddметод подписывается один раз и сразу послеaddвызов методаnotify, этот метод является методом публикации
notifyМетод проверит, достигнуто ли количество текущих подписокnЕсли да, значит подписка завершена и вся информация всплывающего окна получена, на следующем шаге собранная информация всплывающего окна может быть отображена по определенной логике, например, отображать толькоlevelВсплывающее окно с наибольшим значением
Согласно вышеизложенным представлениям,ModalManageКатегорияconstructorНачальное значение, которое необходимо задать в методе, почти известно.
constructor (modalList) {
this.modalFlatMap = {}
this.modalList = modalList
}
modalFlatMapИспользуется для кэширования информации обо всех подписанных всплывающих окнах.
conditionListдаModalManageПри инициализации класс получает параметр, фактически являющийся значением всех всплывающих окон, которые могут отображаться на странице (включая всплывающие окна подкомпонентов) при входе на страницу.idКоллекция, то есть необходимо знать, сколько всплывающих окон может отображаться одновременно на странице.С приведенным выше примером кодаmodalMap.jsНапример,indexстраницыmodalListзначение['1', '2', '3', '11', '12', '21', '22']
На самом деле здесь достаточно напрямую передать количество всплывающих окон.indexимеют7Одновременно могут отображаться два всплывающих окна, поэтому вы можете напрямую загружать7, причина, по которой я хочу передать это имя здесь, состоит в том, чтобы облегчить отладку.Если есть проблема с кодом, например, на самом деле есть5интерфейс может управлять5Всплывающее окно, но вы только подписались4Во-вторых, если вы передаете только числа, вам нужно найти их один за другим, чтобы увидеть, на какой из них вы забыли подписаться, но если вы передаете имя, вы можете отлаживать все сразу, а это означает, что ремонтопригодность кода будет будь лучше.
На самом деле здесь есть проблема
Если всплывающее окно управляется только одним асинхронным интерфейсом, то нет проблем с вышеизложенным, но если отображением всплывающего окна нужно управлять в соответствии с возвращаемым значением нескольких асинхронных интерфейсов, тогда проблема.idОн всего один, но поскольку он управляется несколькими интерфейсами, то, согласно приведенной выше логике, может бытьidПовторите операцию подписки, поэтому вам нужно изменить ее здесь
constructor (conditionList) {
this.modalFlatMap = {}
this.conditionList = conditionList
this.hasAddConditionList = []
}
idТолько в качестве идентификатора используйтеconditionЧтобы управлять подпиской, если всплывающее окно управляется асинхронным условием, тоconditionЗначением является строка (эта строка играет роль только в идентификации), еслиn(n>=1) асинхронное управление условием, значением является массив, а длина массиваn
conditionListвсе на страницеconditionколлекцияhasAddConditionListИспользуется для кэширования текущей операции подпискиcondition
Когда определяется статус любого всплывающего окна на странице (то есть соответствует ли оно условиям отображения), выполняется операция подписки:
// modalManage.js
add (condition, infoObj) {
if (!this.conditionList.includes(condition)) return console.log('无效订阅:', condition)
if (this.hasAddConditionList.includes(condition)) return console.log('重复订阅:', condition)
this.hasAddConditionList.push(condition)
const modalItem = getModalItemByCondition(condition, modalMap)
const existMap = this.modalFlatMap[modalItem.id]
if (existMap) {
// 说明当前弹窗由多个逻辑字段控制
const handler = existMap.handler
existMap.rdShow = existMap.rdShow && infoObj.rdShow
existMap.handler = () => {
handler && handler()
infoObj.handler && infoObj.handler()
}
} else {
this.modalFlatMap[modalItem.id] = {
level: modalItem.level,
feShow: modalItem.feShow,
rdShow: infoObj.rdShow,
handler: infoObj.handler
}
}
this.notify()
}
this.modalFlatMapИмя свойства — это всплывающее окно.id, значение каждого атрибута содержит4объект со свойствами,levelа такжеfeShowчуть вышеmodalMap.jsсерединаlevel,feShow,rdShow— это значение, возвращаемое асинхронным интерфейсом или другой логикой для управления отображением всплывающего окна.handlerЭто функция, которая будет выполняться, когда выбрано всплывающее окно, которое необходимо отобразить.
Если жеid, есть несколькоconditionЕсли вы подпишетесь, всплывающая информация об этих подписках будет объединена
this.hasAddConditionListЗаписывает информацию о списке подписки, когда длина списка подписки иthisconditionListКогда длина одинакова, это означает, что все всплывающие окна готовы и могут отображаться в соответствии с приоритетом этих всплывающих окон, то естьnotifyспособ сделать
notifyметод, сначала исключите атрибутfeShow && rdShowдляfalseэлементы всплывающих окон, а затем сравните оставшиеся всплывающие окнаlevel, показаны толькоlevelСамое большое всплывающее окно:
// modalManage.js
notify () {
if (this.hasAddConditionList.length === this.conditionList.length) {
const highLevelModal = Object.values(this.modalFlatMap).filter(item => item.rdShow && item.feShow).reduce((t, c) => {
return c.level > t.level ? c : t
}, { level: -1 })
highLevelModal.handler && highLevelModal.handler()
}
}
Используйте шаблон singleton для управления вложенными компонентами и всплывающими окнами на нескольких страницах.
вышеупомянутыйModalManageКлассов достаточно для управления всплывающими окнами, но остается проблема, что делать, если всплывающие окна на странице разбросаны по основному компоненту страницы и его подкомпонентам, или даже подкомпонентам подкомпонентов?
В этом случае вам нужно использовать синглтон
// 单例管理
const manageTypeMap = {}
// 获取单例
function createModalManage (type) {
if (!manageTypeMap[type]) {
manageTypeMap[type] = new ModalManage(getAllConditionList(modalMap[type]))
}
return manageTypeMap[type]
}
пройти черезcreateModalManageэтот метод для созданияModalManageнапример, по поступающимtypeрешить, создавать ли новый экземпляр, если синглтон управляет объектомmanageTypeMapне существует вtypeДля случая , тоnewОдинModalManageпример, сохранитьmanageTypeMap, и верните этот новый экземпляр, иначе вернитеmanageTypeMapЭкземпляры, которые уже были созданы в
Таким образом, независимо от того, сколько компонентов разбросано по всплывающему окну, независимо от того, насколько глубоко эти компоненты вложены, события могут быть гладко подписаны/опубликованы при условии обеспечения низкой связанности кода.
здесьgetAllConditionListметод — это вспомогательный метод, используемый дляmodalMapПолучите структуру данных всплывающего окна, соответствующую странице:
const getAllConditionList = modalInfo => {
let currentList = []
if (modalInfo.modalList) {
currentList = currentList.concat(
modalInfo.modalList.reduce((t, c) => t.concat(c.condition), [])
)
}
if (modalInfo.children) {
currentList = currentList.concat(
Object.values(modalInfo.children).reduce((t, c) => {
return t.concat(getAllConditionList(c))
}, [])
)
}
return currentList
}
Что касаетсяcreateModalManageпараметрыtype, его значение может быть строкой, например, если вам нужно управлять домашней страницейindexВсе всплывающие окна, которые могут отображаться одновременно наtypeЗначение указано какindex,существуетindexЧерез это поле получается основной компонент и его подкомпоненты, содержащие всплывающие окна.ModalManageОдноэлементный объект:
const modalManage = createModalManage('index')
Это также решает другую проблему, а именно проблему управления всплывающими окнами на нескольких страницах.indexстраница черезindexСоздайтеModalManageSingleton, страницу сведений можно пройти черезdetailсоздаватьModalManageСинглтон, обе стороны не мешают друг другу
Суммировать
Весь приведенный выше пример кода был загружен наgithub, вы можете взглянуть на
В этой статье анализируется только конкретный случай, такой как всплывающее окно.На самом деле его можно применить и к другим сценариям, например к управлению подвесными подвесками в том же месте на странице.
Будь то управление всплывающим окном или управление кулоном, поместите его вmvvmВо фреймворке это все управление данными.В основных интерфейсных фреймворках уже есть соответствующие решения для комплексного управления данными, такие какvuexа такжеreduxи т. д., эти решения, конечно, также могут решить вышеуказанные проблемы.
В этой статье в основном обсуждается эта концепция, чтобы изучить общее решение, используете ли выvue,react,angularещеjqueryШаттл или апплет WeChat, апплет Alipay, быстрое приложение и т. д. можно легко интегрировать и использовать по низкой цене, не полагаясь на другие библиотеки.