Сначала рассмотрим примерный внешний вид:
Основные идеи и шаги:
Для макета используется список dl, где первичные пункты находятся в dt, а вторичные — внутри dd с использованием ul и li. В плане взаимодействия, при клике на любой первичный пункт меню закрываются все братские вторичные пункты, а при клике на второй уровень меню закрываются все пункты.
Используйте dt для создания первичных пунктов меню.
Используйте dd для вложения вторичных пунктов меню, начальное скрытие, положение absolute и z-index для плавного выхода за границы страницы.
/* Общий контейнер меню */
.menu {
display: block;
height: 38px;
}
/* Первичные пункты меню */
.menu dt {
font-size: 15px;
float: left;
/* Hack */
width: 33%;
height: 38px;
border-right: 1px solid #d2d2d2;
border-bottom: 1px solid #d2d2d2;
text-align: center;
background-color: #f4f4f4;
color: #5a5a5a;
line-height: 38px;
}
/* Внешний контейнер вторичных пунктов меню */
.menu dd{
position: absolute;
width: 100%;
/* Hack */
top: 39px;
left: 0;
z-index: 999;
}
/* Обычный стиль вторичных пунктов меню */
.menu li{
font-size: 14px;
line-height: 34px;
color: #575757;
height: 34px;
display: block;
padding-left: 8px;
background-color: #fff;
border-bottom: 1px solid #dbdbdb;
}
Просмотрите результат, затем реализуйте событие нажатия.
Как показано на рисунке ниже:
3. Элемент dt привязывается к событию tapMainMenu, а флаг управляет отображением toggle, предоставляя два класса hidden и show для управления отображением. Примечание: элемент dt также может быть связан с событием tap, а не только с view.```css
/* Отображение и скрытие */
.show {
display: block;
}
.hidden { display: none; }
4. Закройте все первичные пункты меню, каждый из которых имеет уникальный index, передаваемый через событие tapMainMenu, который соответствует массиву subMenuDisplay. Текущий элемент subMenuDisplay[index] решает, будет ли он отображен или скрыт, в зависимости от его текущего состояния.
Ключевые части кода:
```html
<dl class="menu">
<dt data-index="0" bindtap="tapMainMenu">Цена</dt>
<dd class="{{subMenuDisplay[0]}}">
<ul><li>Подпункт 1</li><li>Подпункт 2</li></ul>
</dd>
</dl>
``````javascript
// Use the function to initialize an array which helps avoid issues with deep copy and makes the approach more flexible as you can use different methods and quantities of elements.
function initSubMenuDisplay() {
return ['hidden', 'hidden', 'hidden'];
}
``````markdown
Страница({
данные: {
subMenuDisplay: initSubMenuDisplay()
},
нажатиеГлавногоМеню: function(e) {
// Get the current index of the displayed main menu item
var index = parseInt(e.currentTarget.dataset.index);
// Create a new array with hidden state for all items
var новыйSubmenuDisplay = initSubMenuDisplay();
// If the current state of the element is hidden, change it to show,
// otherwise change it to hidden, and also hide all other elements
if (this.данные.subMenuDisplay[index] === 'hidden') {
новыйSubmenuDisplay[index] = 'show';
} else {
новыйSubmenuDisplay[index] = 'hidden';
}
// Set the new array as the value of subMenuDisplay
this.setData({
subMenuDisplay: новыйSubmenuDisplay
});
}
});
Выберите текущий пункт вторичного меню, но при этом используйте системный значок и измените цвет фона, сделайте текст жирным. Также измените заголовок первого уровня меню. В демонстрационном режиме показаны всплывающие окна.Объявите метод tapSubMenu
для отслеживания событий клика по пункту вторичного меню:
tapSubMenu: function(e) {
// Получение текущего значения первичного меню
var index = parseInt(e.currentTarget.dataset.index);
console.log(index);
// Скрытие всех первичных меню
this.setData({
subMenuDisplay: initSubMenuDisplay()
});
}
Добавьте эффект выделения:
/* Выделенный стиль для пунктов вторичного меню */
.menu li.highlight {
background-color: #f4f4f4;
}
Для реализации выделения с использованием двумерного массива, чтобы можно было точно определить, какой пункт вторичного меню был выбран, а также какое первичное меню должно быть видимым, измените файл разметки следующим образом:
<dd class="{{subMenuDisplay[0]}}">
<ul>
<li class="{{subMenuHighLight[0][0]}}" data-index="0-0" bindtap="tapSubMenu">100以内</li>
<li class="{{subMenuHighLight[0][1]}}" data-index="0-1" bindtap="tapSubMenu">100–500</li>
<li class="{{subMenuHighLight[0][2]}}" data-index="0-2" bindtap="tapSubMenu">500–1000</li>
<li class="{{subMenuHighLight[0][3]}}" data-index="0-3" bindtap="tapSubMenu">1000–3000</li>
<li class="{{subMenuHighLight[0][4]}}" data-index="0-4" bindtap="tapSubMenu">3000以上</li>
</ul>
</dd>
Эффект представлен на следующем рисунке:
Соответствующий JavaScript код следует оформить так:
// Объявление начального состояния выделения массива
function initSubMenuHighLight() {
return [
['','','','',''],
['',''],
['','','']
];
}
```Клик событие:
```javascript
tapSubMenu: function(e) {
// Скрытие всех первичных меню
this.setData({
subMenuDisplay: initSubMenuDisplay()
});
// Обработка вторичного меню, получаем текущее значение вторичного меню
var indexArray = e.currentTarget.dataset.index.split('-');
console.log("indexArray : " + indexArray);
var newSubMenuHighLight = initSubMenuHighLight();
// Для первого уровня меню нет необходимости проверять текущее состояние, достаточно присвоить класс highlight
newSubMenuHighLight[indexArray[0]][indexArray[1]] = 'highlight';
console.log(newSubMenuHighLight);
// Установка нового массива
this.setData({
subMenuHighLight: newSubMenuHighLight
});
}
Таким образом, была реализована возможность выделения и снятия выделения. Однако это ещё не всё, поскольку для вторичного меню отличается от первого уровня — братские пункты вторичного меню не являются взаимоисключающими, то есть выбор одного пункта вторичного меню не должен автоматически снимать выделение других пунктов. Поэтому мы дорабатываем наш JavaScript код. Способ объявления, замените на переменную для удобства хранения.
// Определение начальных данных для хранения при выполнении
var initSubMenuHighLight = [
['','','','',''],
['',''],
['','','']
];
Обработка события нажатия```javascript tapSubMenu: function(e) { // Скрыть все первичные меню this.setData({ subMenuDisplay: initSubMenuDisplay() }); // Обработка вторичных меню, сначала получаем текущий показатель вторичного меню var indexArray = e.currentTarget.dataset.index.split('-'); // Инициализация состояния // var newSubMenuHighlight = initSubMenuHighlight; for (var i = 0; i < initSubMenuHighlight.length; i++) { // Если выбрано первичное меню, то сначала очистить состояние, затем выделить выбранное вторичное меню; если это не текущее меню, то игнорировать его. Таким образом можно сохранить выделение других меню if (indexArray[0] === i) { for (var j = 0; j < initSubMenuHighlight[i].length; j++) { // Очистка initSubMenuHighlight[i][j] = ''; } // Возврат вторичного меню в начальное состояние } } }
// Для вторичных меню нет необходимости проверять текущее состояние, достаточно присвоить класс highlight после клика
initSubMenuHighLight[indexArray[0]][indexArray[1]] = 'highlight';
// Установка нового массива
this.setData({
subMenuHighLight: initSubMenuHighLight
});
}
```
Необходимые доработки:
1. Добавление анимации при отображении и скрытии (вниз)
2. Абстрагирование, использование обратного вызова для прослушивания каждого клика вторичного меню
3. Отделение источника данных от представления, ключи и значения первичных и вторичных меню должны быть разделены, система должна распознавать только индекс, а затем выполнять действия по кликам, переходы страниц и фильтрацию результатов
[2016-10-18]
Официальная документация: [https://mp.weixin.qq.com/debug/wxadoc/dev/api/api-animation.html](https://mp.weixin.qq.com/debug/wxadoc/dev/api/api-animation.html)

Для реализации анимированной версии требуется поддержка анимации перемещения и маски. Предположительный подход следующий:
1. Вторичное меню начинается скрытым и находится за пределами экрана устройства
2. При выборе первичного меню вторичное меню перемещается вниз до тех пор, пока верхний край вторичного меню не совпадает нижним краем первичного меню. Используется линейная анимация
3. При выборе самого себя или другого первичного меню выполняются противоположные действия
```4. Маска используется с анимацией ease-in/ease-out
Шаг 1: Изменение стилей, установка свойства top
Шаг 2: Объявление анимации
Основной код:```python
animation: function(index) {
// Определение анимации
var animation = wx.createAnimation({
duration: 400,
timingFunction: 'linear',
})
// Отображение или скрытие
var flag = this.data.subMenuDisplay[index] === 'show' ? 1 : -1;
// flag = 1;
console.log(flag)
// Движение вдоль оси Y
animation.translateY(flag * (initSubMenuHighLight[index].length * 34) + 8).step();
// Экспортирование данных для привязки к свойству view
this.setData({
animationData: animation.export()
});
}
```
После завершения анимации необходимо один раз вызвать `step()`, независимо от того, является ли это одной группой или несколькими.
Шаг 3: Объявление массива data и связывание с wxml
```
animationData: {}
```
в wxml:
```
<dd animation="{{animationData}}">
```
Проблема z-index может закрывать первичное меню, установите значение равным `-999`, чтобы поместить его ниже уровня первого меню.
Используйте `bottom: 0;` для начального положения вровень с нижней границей первого меню.
Установите `dl` как `position: relative;` для соответствия вторичному меню, которое имеет позицию `absolute`.
Шаг 4: При клике на первичное меню вызывается анимация
```
// Установка анимации
this.animation(index);
```
Шаг 5: При клике на вторичное меню вызывается анимация
```
// Установка анимации
this.animation(indexArray[0]);
```Шаг 6: Атрибут `display` следует заменить на `visibility`.
```markdown
/* Отображение и скрытие */
.show {
/*display: block;*/
visibility: visible;
}
.hidden {
/*display: none;*/
visibility: hidden;
}
```
> Сохраните место, ширину и высоту, иначе при отсутствии анимационного эффекта после клика.
Скачать исходный код: подписаться на следующий официальный аккаунт -> ответить цифрой 1006
Друзьям, интересующимся разработкой мини-приложений, рекомендую подписаться на официальный аккаунт: `huangxiujie85`, QQ группа: `575136499`, WeChat: `small_application`, мы будем продолжать выпускать больше работ.

Вы можете оставить комментарий после Вход в систему
Неприемлемый контент может быть отображен здесь и не будет показан на странице. Вы можете проверить и изменить его с помощью соответствующей функции редактирования.
Если вы подтверждаете, что содержание не содержит непристойной лексики/перенаправления на рекламу/насилия/вульгарной порнографии/нарушений/пиратства/ложного/незначительного или незаконного контента, связанного с национальными законами и предписаниями, вы можете нажать «Отправить» для подачи апелляции, и мы обработаем ее как можно скорее.
Комментарии ( 0 )