Впервые опубликовано в моем блоге:dunizb.comОригинальная ссылка:блог. Прочитайте свой Prep.com/2017/11/18/…
Статью рекомендуется читать на компьютере, полный адрес источника указан в конце статьи.
Обновление 2017.11.30: Этот случай имеет более элегантную и простую реализацию.Вы можете сравнить две реализации.Подробности см. в файле checklist2.0.vue в исходном коде в конце статьи.
2017.11.25 Обновить Глава: 0.3 API планирования
В этой статье вы узнаете, как написать мобильный компонент Checklist, который разработан в виде одного файла на vue, который подходит для новичков в Vue.js. В то же время, эта статья очень длинная, лучше всего следовать шагам статьи при чтении и написании. Что эта статья говорит, или что вы можете получить? .
- Напишите компонент контрольного списка ритмично, начиная с 0, шаг за шагом
- Функциональный анализ при кодировании
- Включает некоторые проблемы с адаптацией мобильного терминала
- Некоторое знание компонентов Vue.js
содержание
Предварительное знание
Что такое контрольный список
Шаг 0: Анализ и подготовка
- [0.1 Бизнес-требования и функциональный анализ] (#0.1 Бизнес-требования и функциональный анализ)
- [0.2 API планирования] (#0.2 API планирования)
- [0.3 Элемент инициализации] (#0.3 Элемент инициализации)
Шаг 1: Реализуйте скелет компонента и инфраструктуру
- [1.1 Реализация базового скелета] (#1.1 Реализация базового скелета)
- [1.2 Внедрить верхнюю панель] (#1.2 Внедрить верхнюю панель)
- [1.3 Панель подсказок по работе агрегата] (#1.3 Панель подсказок по работе агрегата)
Шаг 2: Реализуйте структуру списка списка
- [2.1 Реализовать базовый скелет] (#2.1 Реализовать базовый скелет)
- [2.2 Реализовать выбор флажка] (#2.2 Реализовать выбор флажка)
- [2.3 Маленький значок перед информацией об адресе] (#2.3 Маленький значок перед информацией об адресе)
- [2.4 Граница 1 пиксель для мобильных устройств] (#2.4 Граница 1 пиксель для мобильных устройств)
- [2.5 Прокрутка списка] (#2.5 Прокрутка списка)
Шаг 3: Реализуйте интерактивную функцию выбора CheckBox
- [3.1 Принцип реализации и v-модель] (#3.1 Принцип реализации и v-модель)
- [3.2 Добавить выбранный стиль](#3.2 Добавить выбранный стиль)
- [3.3 Можно выбрать до нескольких элементов] (#3.3 Можно выбрать до нескольких элементов)
- [3.3.1 Использование реквизита для передачи данных](#3.3.1 Использование реквизита для передачи данных)
- [3.3.2 Параметры просмотра,
использование ссылок)
Шаг 4. Отображение и скрытие компонентов
- [4.1 Компоненты дисплея] (#4.1 Компоненты дисплея)
- [4.2 Скрыть компонент] (#4.2 Скрыть компонент)
- [4.3 Добавить маску] (#4.3 Добавить маску)
- [4.4 Мобильное поле ввода предотвращает появление виртуальной клавиатуры мобильного телефона] (#4.4 Мобильное поле ввода предотвращает появление виртуальной клавиатуры мобильного телефона)
Шаг 5: Рендеринг данных и передача событий в родительский компонент
- [5.1 Визуализация данных] (#5.1 Визуализация данных)
- [5.2 Компонентная связь и пользовательские события] (#5.2 Компонентная связь и пользовательские события)
Предварительное знание
Прежде чем читать эту статью, вы должны иметь базовые знания о следующем:
- для Vue.js
.vueБазовое понимание работы с отдельными файлами и знание компонентов Vue.js - Знание верстки CSS Flexbox.
Что такое контрольный список
Что такое компонент контрольного списка? Давайте сначала посмотрим, как выглядит контрольный список UI-фреймворков, уже представленных на рынке.
| weui | Mint UI |
|---|---|
Типичным сценарием этого компонента является список корзины покупок на мобильном терминале.Откройте корзины покупок Jingdong и Taobao, чтобы увидеть, очень ли похожи функции?
О каком компоненте контрольного списка написано в этой статье? Этот компонент взят из реального проекта нашей компании.Вначале я также использовал для этого Mint-UI.Потом изменить Mint-UI под требования бизнес-апгрейда было нецелесообразно,поэтому я сделал его сам,и специально скомпилировал этой статье, и мы пытаемся сделать его универсальным и гибким. Наш контрольный список выглядит следующим образом:
| наш | Список корзины покупок JD.com |
|---|---|
Шаг 0: Анализ и подготовка
0.1 Бизнес-требования и функциональный анализ
Прежде чем начать код, давайте тщательно проанализируем бизнес-требования и функциональные точки.Этот компонент должен отображать тестовую комнату и адрес тестовой комнаты.Если адрес тестовой комнаты не отображается, он не будет отображаться.Вы можете выберите до трех.Данные получаются динамически в соответствии с испытуемыми и городом, в котором они находятся.Когда данных в списке много, мы должны придать ему максимальную высоту, чтобы список можно было прокручивать, и т.д. Из рисунка получаются следующие функциональные точки:
- Показать анимацию скрытия и перехода
- Адресная строка списка не является обязательной, а высота строки адаптивной.
- Проверено и отключено
- Выделенный и максимум выделенный текст подсказки (назовем егоПанель оперативных подсказокНу для удобства он будет называться позже), ради универсальности в качестве настраиваемых опций надо выбрать максимум несколько
- Список можно прокручивать, а максимальную высоту списка максимальную высоту также можно сделать настраиваемым элементом.
- Заголовок, заголовок, отмена, подтверждение также должны быть необязательными, их можно превратить в настраиваемые элементы.
- Значение выбранного элемента должно быть массивом
- После выбора нажатие кнопки «Готово» должно отправить выбранное значение родительскому компоненту.
- Флажок может быть слева или справа
и т.д....
0.2 API планирования
API компонента Vue состоит только из реквизита, событий и слотов. Определите имена и правила этих трех частей. Даже если остальная логика не реализована в первой версии, в будущем ее можно многократно улучшить. Однако, если API плохо спроектирован, последующие изменения будут дорого стоить пользователям.
Согласно приведенному выше функциональному анализу, некоторые API можно изначально получить следующим образом: мы можем сначала записать каждый API в компонент (эта часть контента является новой, в этой статье API сначала не прописывается в компонент, реквизитыmaxHeightВ этой статье это тоже не реализовано, вы можете самостоятельно реализовать следующее)
Props
| Имя свойства | инструкция | тип | Это необходимо | По умолчанию |
|---|---|---|---|---|
| max | Выберите не более нескольких | Number | да | 0 |
| dataList | данные | Array | да | [] |
| maxHeight | контролировать максимальную высоту | Number | нет | 300(px) |
| checkboxLeft | Находится ли бегунок слева | Boolean | нет | false |
Events
| название события | инструкция | параметры/возвращаемые значения |
|---|---|---|
| on-change | Событие срабатывает после нажатия OK | Object |
Methods
| имя метода | инструкция |
|---|---|
| show | компоненты дисплея |
| hide | скрытые компоненты |
0.3 Инициализировать проект
Давайте проанализируем, как разделить структуру DOM, что способствует общему представлению о кодировании.
Рисунок немного некрасивый, и под рукой нет простого в использовании инструмента для аннотирования изображений, я использую родной инструмент для аннотирования Mac.
После вышеописанного анализа мы знаем, что делать с этим компонентом, а затем приступаем к кодированию.Сначала делаем базовый вид и полку компонента.
Сначала мы создаем новый файл checklist.vue:
<template>
<div class="cl-checklist">
checklist
</div>
</template>
<script>
</script>
<style scoped>
</style>
Чтобы облегчить тестирование и наблюдение во время разработки, мы также должны создать файл demo.vue и добавить наш компонент checklist.vue в demo.vue:
<template>
<div class="cl-div">
<div class="center">checklist demo</div>
<div>
<input type="text" placeholder="请选择考场">
</div>
<checklist></checklist>
</div>
</template>
<script>
import checklist from '@components/checklist/checklist'
export default {
components: {
checklist
}
}
</script>
<style scoped>
.center{
text-align: center;
font-size: 18px;
}
</style>
Шаг 1: Реализуйте скелет компонента и инфраструктуру
1.1 Реализовать базовый скелет
Напишем сначала базовые модули, различаем их по цвету фона, а потом убираем цвет фона после написания.Так я пишу страницы каждый день, чтобы четко видеть, где проходят границы модулей. контрольный список.vue
<template>
<div class="cl-checklist">
<div class="topbar"></div>
<div class="desc">您已选中0个,最多可选3个</div>
<div class="list">
</div>
</div>
</template>
<script>
</script>
<style scoped>
.topbar{
height: 30px;
background-color: #d0000e;
}
.desc{
padding: 10px 15px 0 0;
font-size: 14px;
text-align: right;
color: #fff;
background-color: #0d2e44;
}
.list{
height: 300px;
background-color: #00b4ff;
}
</style>
Эффект следующий:
1.2 Реализовать верхнюю панель
Верхняя панель состоит из трех элементов, как выбрать метод компоновки? Видно, что кнопки отмены и завершения выровнены слева и справа, а средний заголовок выровнен по центру. Мы можем выбрать традиционный плавающий макет, используя три элемента div, например:
<div class="cancel">取消</div>
<div class="title">选择考场</div>
<div class="confirm">确定</div>
Таким образом, вам нужно указать ширину div, отменить, определить выравнивание по левому и правому краю и центрировать заголовок.НЕТ! НЕТ! НЕТ!Слишком много проблем! Мы используемFlexboxМакет, позже я буду использовать макет Flexbox. Давайте посмотрим, как Flexbox может легко решить этот макет.
HTML:
<div class="topbar">
<span class="cancel">取消</span>
<span class="title">选择考场</span>
<span class="confirm">完成</span>
</div>
CSS:
.topbar{
display: -webkit-flex;
display: flex;
justify-content: space-between;
align-items: center;
height: 45px;
font-size: 16px;
padding: 0 13px;
border-bottom: 1px solid rgb(217,217,217);
}
.topbar .cancel{
color: rgb(159,159,159);
}
.topbar .confirm{
color: rgb(46,166,242);
}
Мы используемjustify-content: space-betweenВыровняйте их по горизонтали, затемalign-items: centerВыровняйте вертикально по центру, а затем дайте слева и справаpaddingВот и все. Эффект следующий:
Я использую в проектеdisplay:inline-blockВёрстка не так хороша, как сейчас, такого рода просмотр и вывод в виде статей постфактум может помочь мне яснее понять, как лучше организовать код, поэтому я настаиваю на выводе.
1.3 Реализовать панель оперативных подсказок
Это относительно просто, давайте просто попробуем в этой части. HTML
<template>
<div class="cl-checklist">
<div class="topbar">
<span class="cancel">取消</span>
<span class="title">选择考场</span>
<span class="confirm">完成</span>
</div>
<div class="desc">您已选中0个,最多可选3个</div>
<div class="list">
</div>
</div>
</template>
CSS
.desc{
height: 30px;
line-height: 30px;
padding-right: 10px;
font-size: 14px;
text-align: right;
color: rgb(159,159,159);
}
Эффект следующий:
Шаг 2: Реализуйте структуру списка списка
2.1 Реализовать базовый скелет
Давайте сначала рассмотрим следующий анализ нулевой структуры мульти-DOM:
Видно, что мы делим DOM-структуру на левую и правую структуру, а затем левую часть делим на верхнюю и нижнюю структуру, а левый флажок центрируем по горизонтали и вертикали.
Давайте сначала наметим основную структуру HTML:
<-- 省略上面的代码 -->
<div class="list">
<div class="line">
<div class="l">
<div class="title">科目二第07考点马路</div>
<div class="address">上海市宝山区保安公路2009号</div>
</div>
<div class="r"></div>
</div>
</div>
<-- 省略下面的代码 -->
CSS:
.list{
height: 300px;
font-size: 14px;
padding: 10px 13px;
background-color: #00b4ff;
}
.list .line {
display: -webkit-flex;
display: flex;
justify-content: center;
align-items: center;
height: 50px;
background-color: #4caf50;
}
.list .line .l{
display: -webkit-flex;
display: flex;
flex-direction: column;
justify-content: center;
align-items: flex-start;
width: 90%;
background-color: #d0000e;
}
.list .line .r{
width: 20px;
height: 20px;
background-color: #0d2e44;
}
Эффект следующий:
Следующим шагом будет совершенство, и кружок флажка справа.Уведомление, мы не можем дать.lineУстановите мертвую высоту, эта высота должна поддерживаться контентом, потому что мы должны учитывать отображение, когда нет информации об адресе.
2.2 Реализовать выбор флажка
Для того, чтобы облегчить отображение выбранного состояния, копируем строку.line, установите это поведение в выбранное состояние, то есть добавьте.selectedкласс, то у нас есть.selectedНапишите стиль выбранного состояния
<div class="list">
<div class="line">
<div class="l">
<div class="title">科目二第07考点马路</div>
<div class="address">上海市宝山区保安公路2009号</div>
</div>
<div class="r"></div>
</div>
<div class="line selected">
<div class="l">
<div class="title">科目二第07考点马路</div>
<div class="address">上海市宝山区保安公路2009号</div>
</div>
<div class="r"></div>
</div>
</div>
Продолжаем с CSS:
.list .line .r{
width: 20px;
height: 20px;
margin: 0 5px;
-webkit-border-radius: 50%;
border-radius: 50%;
border:1px solid #9e9e9e;
background-color: #fff;
position: relative;
z-index: 0;
}
.list .line.selected .l .title{
color: #1799fa;
}
.list .line.selected .r{
border: 1px solid #1799fa;
background-color: #1799fa;
}
.list .line.selected .r::before{
content: ' ';
position: absolute;
top: 4px;
left: 4px;
width: 12px;
height: 12px;
background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABUAAAAPCAYAAAALWoRrAAAA90lEQVQ4ja3TMSuFURgH8GeQRGIwy6BkUbIYlHwBu0Umi8VkMVlMJoMvIcNdDAYlJuULWCSESBSLwc9we/P2eu715t6nznKe//Or0zknEF1YS3jAHRa7Aa7iy0/ddAquVUC47ARcT8APLPwX3PC73jGPCPRiGSvoqwFuJuAb5opMoFFqnmCwDbiVgK+YLecCn5XQGYYScDsBXzBTzQb2k/A5hkvBnSTzhOnsRIEBHCdDFxjBbtJ7xFQGFmigH0fJ8HOyd4/JVmAZDc2bP0yQct1ioh1YRYvn1cg0XGP8LzBDC/igAl5hrA7YCg30YE/zl5xitC6I+AYJmBaJbbKurAAAAABJRU5ErkJggg==");
background-repeat: no-repeat;
background-size: contain;
background-position: center center;
z-index: 1;
}
Здесь, чтобы не полагаться на картинки, кодируем отмеченные галочкой картинки в формат base64, и при этом сначала убираем фон, эффект такой:
2.3 Маленькие значки перед информацией об адресе
Эту маленькую иконку лучше всего реализовать с помощью псевдоэлементов.
.list .line .l .address{
color: rgb(159,159,159);
position: relative;
padding-left: 15px;
}
.list .line .l .address::before{
content: ' ';
display: inline-block;
position: absolute;
width: 15px;
height: 15px;
top: 2px;
left: 0;
background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAbCAYAAAB836/YAAABu0lEQVRIiaXUzU8TQRjH8U9fpAkXIZqItHghxEgietuD/gP84R420QSDcCDxIq6KaCoJYCuaeJhdu93OlILfpEnnmWd++7zMM63d3V0RuljHQ9xFr7SP8QNfUOBPlmUzB5tsYBtLkb0eHpS/JzjEcd2hs7W1Vf1v4TkeoxMLu0EHa0VRLBdFcTIYDEC75vCsjO6mbGCnWlSCg1uKVTzK83xAqGFHqFmMX3iP7+X6HjbF67ud5/nnLvomXaxziVcY1WxDfMQLLDf8e+i3sZaIbq8hVjHC28SZtTZWIhs/TdKM8S3xsZW2eLrjOWIVMcFeO2Ik1Kc1R6xltoYI1+Y8Yl8Sxi7Funinz9s4SRzaEa/vKp4mzpx0hSHfjGzewUt8EpoA98voUuUoujgT7tdqxKEl3NN+QqDOMMuys6opRwscuI4jJrP8VYjytgxLjanX5uA/BA+qh7YuOBQadFOKLMv+Zde82Ae4uoHYlUZmTcGx8KwvymGWZVNjGhu9DzhdQOy09J0iNct75qd+VfrMkBIcYX+O4L74a5MUJHT8OGI/Nuc2zBOEd7iorS9KW5LrBH/jjZDeCK9LW5K/QatiGcsSFOsAAAAASUVORK5CYII=");
background-repeat: no-repeat;
background-size: contain;
background-position: 0;
}
2.4 Адаптация к 1-пиксельной границе мобильного терминала
Для достижения границы в 1 пиксель, адаптированной к мобильному терминалу, граница в основном масштабируется в соответствии с dpr устройства.CSS написан следующим образом:
.border-1px{
position: relative;
}
.border-1px::after{
display: block;
position: absolute;
left: 0;
bottom: 0;
width: 100%;
border-bottom: 1px solid rgb(217,217,217);
content: ' ';
}
@media (-webkit-min-device-pixel-ratio: 1.5), (min-device-pixel-ratio: 1.5) {
.border-1px::after {
-webkit-transform: scaleY(0.7);
transform: scaleY(0.7);
}
}
@media (-webkit-min-device-pixel-ratio: 2), (min-device-pixel-ratio: 2) {
.border-1px::after {
-webkit-transform: scaleY(0.5);
transform: scaleY(0.5);
}
}
Затем устанавливаем, где нужно.border-1pxстиль
<div class="list">
<div class="line border-1px">
<div class="l">
<div class="title">科目二第07考点马路</div>
<div class="address">上海市宝山区保安公路2009号</div>
</div>
<div class="r"></div>
</div>
<div class="line border-1px selected">
<div class="l">
<div class="title">科目二第07考点马路</div>
<div class="address">上海市宝山区保安公路2009号</div>
</div>
<div class="r"></div>
</div>
</div>
у нас в каждой строке.lineдобавить элементborder-1px, эффект следующий:
Дополнительные сведения о проблемах с рамкой в 1 пиксель для мобильных устройств см.«Проблема с границей 1 пикселя для мобильных устройств»
2.5 Прокрутка списка
Реализовать прокрутку очень просто, достаточно указать родительский элемент, который есть в нашем коде.listЭлемент задает высоту, где наши данные не обязательно сколько, поэтому нам лучше установить только максимальную высотуmax-heightТо есть одновременно нужно отдать самый внешний DIV, который.cl-checklistнастраиватьoverflow:hidden. Давайте сначала скопируем много строк для тестирования.
CSS:
.cl-checklist{
overflow: hidden;
}
.list{
/*height: 300px;*/
max-height: 300px;
font-size: 14px;
padding: 10px 13px;
overflow-y: auto;
-webkit-overflow-scrolling: touch;
overflow-scrolling: touch;
/*background-color: #00A2E6;*/
}
Уведомлениеoverflow-scrolling: touch;Свойство настроено на адаптацию к проблеме неравномерной прокрутки на мобильном терминале. Текущий эффект выглядит следующим образом:
Шаг 3: Реализуйте интерактивную функцию выбора CheckBox
3.1 Принцип реализации и v-модель
Этот шаг является сердцевиной и сложным моментом всего компонента, если этот шаг будет написан хорошо и грамотно, то он значительно упростит последующее логическое взаимодействие. Мы используем встроенные функции HTML для достижения:
<label for="xxx"><input id="xxx" type="checkbox" value=""></label>
На эту комбинацию тегов можно нажать<label>Спусковойigger, когда пакет обернутаcheckbox, по этому принципу мы трансформируем HTML-код
<div class="desc">您已选中 <span>{{checkboxValue.length}}</span> 个,最多可选<span>3</span>个</div>
<div class="list">
<div class="line-wrapper">
<label for="1" class="line border-1px">
<div class="l">
<div class="title">科目二第07考点马路</div>
<div class="address">上海市宝山区保安公路2009号</div>
</div>
<div class="r"></div>
</label>
<input type="checkbox" id="1" v-model="checkboxValue" style="display:none" value="1">
</div>
<div class="line-wrapper">
<label for="2" class="line border-1px">
<div class="l">
<div class="title">科目二第07考点马路</div>
<div class="address">上海市宝山区保安公路2009号</div>
</div>
<div class="r"></div>
</label>
<input type="checkbox" id="2" v-model="checkboxValue" style="display:none" value="2">
</div>
<div class="line-wrapper">
<label for="3" class="line border-1px">
<div class="l">
<div class="title">科目二第07考点马路</div>
<div class="address">上海市宝山区保安公路2009号</div>
</div>
<div class="r"></div>
</label>
<input type="checkbox" id="3" v-model="checkboxValue" style="display:none" value="3">
</div>
</div>
в основном дляdiv.lineэлемент становится<label>элемент, затем оберните другой снаружиdiv.line-wrapper,существует<label>Добавьте тег флажка после него. В то же время, чтобы сделать флажок невидимым, мы можем установить флажокdisplay:noneили на перифериюdiv.line-wrapperнастраиватьoverflow:hiddenможет быть, здесь я используюdisplay:none.
Vue.js предоставляет директиву v-model для двусторонней привязки данных к элементам формы.Например, при использовании в поле ввода входное содержимое будет сопоставлено с привязанными данными в режиме реального времени. Радиокнопке не нужна v-модель, когда она используется отдельно, и напрямую использует v-bind для привязки логического значения. Если это правда, она выбрана, а если нет, она не выбрана. Если она используется в комбинация для достижения взаимного исключения, требуется v. -model используется со значением.
Здесь флажок связан с инструкцией v-modelcheckboxValue, это значение должно быть массивом, тогда Vue.js поможет нам каждый раз автоматически изменять массив:
export default {
data () {
return {
checkboxValue: []
}
}
}
На панели подсказок операции мы выбрали несколько настроек для текущего выбора, какcheckboxValueДлина , так что давайте попробуем позже, мы можем обнаружить, что каждый раз, когда он выбран, он будет помещен в массив один раз, а если щелкнуть его снова, он будет удален из массива. Эффект следующий:
3.2 Добавить выбранный стиль
Теперь его можно выбрать, а вот как добавить выбранный CSS к выделенному элементу — тоже хлопотно подумать, но это надо реализовать с помощью JS.
Привязываем событие к тегу флажкаselectedItem:
<div class="line-wrapper">
<label for="1" class="line border-1px">
<div class="l">
<div class="title">科目二第07考点马路</div>
<div class="address">上海市宝山区保安公路2009号</div>
</div>
<div class="r"></div>
</label>
<input type="checkbox" id="1" @click="selectedItem($event)" v-model="checkboxValue" style="display:none" value="1">
</div>
methods: {
selectedItem (event) {
const labelNode = event.target.previousElementSibling
const classList = labelNode.classList
classList.contains('selected') ? classList.remove('selected') : classList.add('selected')
}
}
Получите объект события Event при нажатии, а затем передайтеpreviousElementSiblingНайдите предыдущий родственный узел и привяжите его к нему..selectedкласс может
3.3 Можно выбрать до нескольких вариантов
3.3.1 Передача данных с помощью реквизита
Пользователи могут настроить выбор нескольких элементов, поэтому функция Props Vue.js пригодится. В компоненте Vue.js опция Props используется для объявления данных, которые необходимо получить от родителя.Значение props может быть двух видов, одно — строка, другое — объект, здесь мы используем объект , аNumberобъект.
Сначала определите реквизит
props: {
max: {
type: Number,
default: 0
}
}
Мы определяем максимальное свойство, тип которогоNumberТип, значение по умолчанию 0 . Затем мы кладемmaxдобавить в советы по действию
<div class="desc">您已选中 <span>{{checkboxValue.length}}</span> 个,最多可选<span>{{max}}</span>个</div>
Затем мы можем передать его компонентуmaxproperties, теперь перейдите к файлу demo.vue:
<template>
<div class="cl-div">
<div class="center">checklist demo</div>
<div>
<input type="text" placeholder="请选择考场">
</div>
<checklist :max="2"></checklist>
</div>
</template>
мы даемmaxУстановите на 2, то есть выберите не более 2.
3.3.2 Опция Watch, использование $refs
Когда мы выбираем два, другие параметры должны быть выделены серым цветом (отключены), тогда нам нужно отслеживать параметр данных вcheckboxValueВ настоящее время нам нужно использовать параметр наблюдения Vue.js, часы — это объект, ключ — это выражение, которое нужно наблюдать, а значение — это соответствующая функция обратного вызова. Значение также может быть именем метода или объектом, содержащим параметры. Экземпляр Vue будет вызываться при создании экземпляра$watch(), выполняет итерацию по каждому свойству объекта наблюдения.
Уведомление, вы не должны использовать стрелочные функции для определения функций-наблюдателей (например,
searchQuery: newValue => this.updateAutocomplete(newValue)). Причина в том, что функция стрелки привязана к контексту родительской области, поэтому она не будет указывать на экземпляр Vue, как ожидалось,this.updateAutocompleteбудетundefined.
Мы делаем это, прослушивая опцию данных вcheckboxValue, чтобы судить о его длине, если его длина точно такая же, как множествоmaxЕсли атрибуты равны, добавьте их к другим.disabledЭтот класс, коллеги даютinput checkboxДобавить кdisabledАтрибуты.
watch: {
checkboxValue (val) {
const listDom = this.$refs['list']
const lines = listDom.querySelectorAll('line-wrapper')
if (val.length === this.max) {
let item = null
for (let i = 0; i < lines.length; i++) {
item =lines[i]
if (val.indexOf(lines[i].dataset.val) === -1) {
item.children[0].classList.add('disabled')
item.querySelector('input[type="checkbox"]').setAttribute('disabled', 'disabled')
}
}
} else {
let item = null
for (let i = 0; i <lines.length; i++) {
item =lines[i]
if (item.children[0].classList.contains('disabled')) {
item.children[0].classList.remove('disabled')
item.querySelector('input[type="checkbox"]').removeAttribute('disabled')
}
}
}
}
}
Это должно работать с Vue.js$refsсделать, в HTML.listустановить на узелref = 'list', то есть для удобства выбора этого DOM-узла вы, конечно же, используете традиционныйdocument.querySelectorвыбирать.listУзлы тоже в порядке.
<div class="list" ref="list">
Строка 9 приведенного выше кода, чтобы определить, находится ли текущий DOM в выбранном массиве,checkboxValueЭлементы массива сравниваются со значением пользовательского свойства, называемогоdata-val, его значение равноinput checkboxЗначение value остается прежним, этоvalПользовательские свойства задаются в.list-wrapperУзел предназначен для облегчения поиска DOM и уменьшения количества слоев поиска DOM, в противном случае его необходимо получить.input checkboxзначение для сравнения.
настраивать.disabledCSS выглядит следующим образом:
.list .line.disabled .l .title{
color: #9e9e9e;
}
.list .line.disabled .r{
border: 1px solid #9e9e9e;
background-color: #9e9e9e;
}
Шаг 4. Отображение и скрытие компонентов
4.1 Компоненты дисплея
transformсвойства могут быть достигнуты.
.cl-checklist{
overflow: hidden;
position: fixed;
bottom: 0;
left: 0;
width: 100%;
-webkit-transition: all .5s;
transition: all .5s;
-webkit-transform: translateY(100%);
transform: translateY(100%);
}
.cl-checklist.show{
-webkit-transform: translateY(0%);
transform: translateY(0%);
}
Мы также должны получить свойство отображения и скрытия для компонента.isOpen, По умолчаниюfalseНе отображать, используйте для управления динамическим добавлением отображаемых и скрытых компонентов к компоненту.cl-checklist.showсвоего рода.
<div class="cl-checklist" :class="{'show': isOpen}">
Как вызвать это свойство в demo.vue? В настоящее время мы должны рассмотреть возможность предоставления методов внешнему миру.Мы можем определить метод отображения и скрытия для вызова пользователями.
methods: {
show () {
this.isOpen = true
},
hide () {
this.isOpen = false
}
}
В demo.vue добавьте событие для поля ввода, а затем вызовите метод show компонента.
<template>
<div class="cl-div">
<div class="center">checklist demo</div>
<div>
<input type="text" @focus="openChecklist" placeholder="请选择考场">
</div>
<checklist ref="checklist" :max="2"></checklist>
</div>
</template>
<script>
import checklist from '@components/checklist/checklist'
export default {
methods: {
openChecklist () {
this.$refs['checklist'].show()
}
},
components: { checklist }
}
</script>
Теперь эффект следующий:
4.2 Скрытые компоненты
Показать и скрыть очень просто. Нажмите, чтобы показать компонент, и анимация вернется к тому же пути. Вам нужно только установить его для отмены.isOpen = falseили позвоните по телефонуhideметод.
<div class="topbar">
<span class="cancel" @click="hide">取消</span>
<span class="title">选择考场</span>
<span class="confirm">完成</span>
</div>
Сейчас эффект такой
4.3 Добавить маску
Чтобы маска покрывала всю страницу, необходимо внести некоторые коррективы в структуру DOM.
<div class="cl-checklist">
<div class="checklist" :class="{'show': isOpen}">
... ...
</div>
<!--蒙层-->
<div class="checklist-overlay" v-if="isOpen"></div>
</div>
.checklist-overlayCSS выглядит следующим образом
.checklist-overlay{
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
z-index: 1000;
background: rgba(0, 0, 0, .5);
transition: all .5s;
}
Соответственно, после настройки DOM-структуры следует изменить и самый внешний стиль.
.cl-checklist{
overflow: hidden;
}
.checklist{
position: fixed;
bottom: 0;
left: 0;
z-index: 2000;
width: 100%;
background-color: #fff;
-webkit-transition: all .5s;
transition: all .5s;
-webkit-transform: translateY(100%);
transform: translateY(100%);
}
Обратите особое внимание на.checklistДобавлен белый фон иz-index:2000, теперь эффект такой
Конечно, вы также можете скрыть компонент при нажатии на маску и напрямую привязать событие клика к маске.@click = "hide"Вот и все.
4.4 Мобильное поле ввода предотвращает всплывающую виртуальную клавиатуру
На мобильном терминале ввод вызовет виртуальную клавиатуру мобильного телефона по умолчанию Как предотвратить всплывающую виртуальную клавиатуру мобильного телефона? В настоящее время я пробовал два решения, одно из которых - добавить к входуreadonlyатрибут, другой — добавить предложение перед обработчиком события ввода.document.activeElement.blur(). Более подробно по этому вопросу вы можете прочитать в другом моем блоге"Советы | H5 запрещает всплывающее окно виртуальной клавиатуры мобильного телефона"
methods: {
show () {
document.activeElement.blur()
this.isOpen = true
}
}
Шаг 5: Рендеринг данных и передача событий в родительский компонент
В этой статье дочерний компонент — checklist.vue, а родительский компонент — demo.vue.
5.1 Отображение данных
Раньше наши данные записывались насмерть, теперь будем рендерить данные динамически, то есть зацикливать данные. Чтобы передать данные из родительского компонента и получить их в дочернем компоненте, вы должны использовать Props. Мы определилиmaxАтрибут, используемый для управления выбором до нескольких элементов, мы добавляем еще один атрибут Props с именемdataList, который является типом массива и требуется
props: {
max: {
type: Number,
default: 0
},
dataList: {
type: Array,
require: true
}
}
Для передачи этого реквизита в компонент требуетсяУведомлениеДело в том, что, поскольку функции HTML не чувствительны к регистру, при использовании шаблонов DOM имена реквизитов в верблюжьем регистре должны быть преобразованы в имена, разделенные тире. не можетdataListДефис должен использоваться в компоненте, который становитсяdata-listформа.
<checklist ref="checklist" :data-list="data" :max="2"></checklist>
определениеdataДанные, данные здесь должны поступать из внутреннего интерфейса, здесь я смоделирую данные
data () {
return {
data: [{
label: '科目二第07考点马路',
value: '101',
address: '上海市宝山区宝安公路2009号'
},{
label: '科目二第08考点沪松公路',
value: '102',
address: '上海市闵行区沪松公路565弄128号'
},{
label: '科目二第09考点七宝',
value: '103',
address: '上海市闵行区沪松公路200号'
},{
label: '科目二第09考点世纪公园世纪公园',
value: '104',
address: ''
},{
label: '科目二第09考点世纪公园',
value: '105',
address: '上海市浦东新区世纪大道200号'
},{
label: '科目二第09考点哈哈哈哈',
value: '107'
},{
label: '科目二第09考点合川路地铁站',
value: '106',
address: '上海市合川路地铁站2号出口'
}]
}
}
Наконец, это рендеринг, вернитесь к checklist.vue, поместитеv-forПросто помирись
<div class="list" ref="list">
<div v-for="(item, index) in dataList" class="line-wrapper" :data-val="item.value">
<label :for="index" class="line border-1px">
<div class="l">
<div class="title">{{item.label}}</div>
<div class="address" v-if="item.address">{{item.address}}</div>
</div>
<div class="r"></div>
</label>
<input type="checkbox" :id="index" @click="selectedItem($event)"
v-model="checkboxValue" style="display:none" :value="item.value">
</div>
</div>
Следует отметить, чтострока 3истрока 10,forстоимость иidЗначение должно быть согласованным, лучше всего использоватьv-forизindex, конечно, вы также можете использоватьitem.labelилиitem.value, но это не рекомендуется.
5.2 Связь между компонентами и пользовательские события
Наконец, пришло время передать выбранное значение на родительскую страницу после нажатия «Готово». Мы уже знаем, что для связи от родительского компонента к дочернему достаточно передать данные через пропсы.Когда дочернему компоненту нужно передать данные родительскому компоненту, нам нужно использовать пользовательские события. В дополнение к прослушиванию событий DOM директива v-on также может использоваться для пользовательских событий между компонентами.
Использование подкомпонентов в Vue.js$emit()Для запуска события родительский компонент использует$on()для прослушивания событий дочернего компонента. Родительский компонент также может использовать v-on непосредственно в пользовательском теге дочернего компонента для прослушивания пользовательских событий, запускаемых дочерним компонентом.
мы даем обязательно использовать@clickКнопка привязана к методу, называемомуonConfirm
<div class="topbar">
<span class="cancel" @click="hide">取消</span>
<span class="title">选择考场</span>
<span class="confirm" @click="onConfirm">完成</span>
</div>
Что нам нужно передать родительскому компоненту? Выбранное значение, это значение должно содержать значение экзаменационной комнаты (то есть идентификатор экзаменационной комнаты), название выбранной экзаменационной комнаты и, возможно, адрес экзаменационной комнаты.Мы можем использовать эти значения|Символически свяжите эти значения вместе и поместите их в значение переключателя
<div class="list" ref="list">
<div v-for="(item, index) in dataList" class="line-wrapper" :data-val="item.label + '|' + item.value">
<label :for="index" class="line border-1px">
<div class="l">
<div class="title">{{item.label}}</div>
<div class="address" v-if="item.address">{{item.address}}</div>
</div>
<div class="r"></div>
</label>
<input type="checkbox" :id="index" @click="selectedItem($event)"
v-model="checkboxValue" style="display:none" :value="item.label + '|' + item.value">
</div>
</div>
**Примечание.** Значение data-val в строке 2 должно соответствовать значению переключателя, поскольку следующая логика JS должна использовать его для сравнения со значением переключателя. Давайте реализуем метод onConfirm().
onConfirm () {
this.isOpen = false
const checkboxValue = this.checkboxValue
const res = []
for (let i = 0; i < checkboxValue.length; i++) {
const resObj = {}
const item = checkboxValue[i].split('|')
resObj.label = item[0]
resObj.value = item[1]
res.push(resObj)
}
this.$emit('on-change', res)
}
В способе предпочтительно получатьcheckboxValueЗначение , а затем извлеките три части значения, метки и адреса в объект resObj, а затем поместите его в массив res и, наконец, используйте этот объект массива в качестве параметра возвращаемого значения события при изменении.
В теге дочернего компонента родительского компонента мы используем@on-changeполучить
<checklist ref="checklist"
:data-list="data"
:max="2" @on-change="changeKaochangValue"></checklist>
В варианте данных родительского компонента определяютkaochangValатрибут для получения, а затем распечатать название выбранной экзаменационной комнаты
<p v-for="(item, index) in kaochangVal">{{item.label}}</p>
метод changeKaochangValue
changeKaochangValue (val) {
this.kaochangVal = val
}
Теперь эффект следующий:
На этом компонент контрольного списка завершен.
Шаг 6: Расширение и уточнение
Установите флажок слева
Учитывая универсальность, что, если требование требует, чтобы поле CheckBox было слева? Эту проблему на самом деле легко решить, потому что мы используем макет Flexbox, который естественно поддерживается, и нужно только добавить дополнительный стиль. Эта функция должна устанавливаться пользователем, то есть она должна поддерживаться свойством props.
props : {
checkboxLeft: {
type: Booolean,
default: false
}
}
Определите свойство checkboxLeft, значение по умолчанию — false, то есть флажок по умолчанию находится справа, а флажок — только слева, когда пользователь показывает, что значение истинно.
Как упоминалось ранее, вам нужно только добавить стиль, чтобы сделать флажок слева, для.lineЭлемент устанавливает класс стиля, а затем динамически привязывает класс через реквизиты checkboxLeft.
.list .line.checkbox-left{
flex-direction: row-reverse;
}
...
<label :for="index" class="line border-1px" :class="{'checkbox-left': checkboxLeft}">
...
Студенты, знакомые с Flexbox, должны знать,flex-directionнаправление раскладки элементов управления,row-reverseИмеется в виду обратный порядок, получился 12-й ряд, а после реверса рядов он становится 21-м.
Установить на компонент (demo.vue)
<checklist ref="checklist"
:data-list="data"
:max="2"
:checkbox-left="true"
@on-change="changeKaochangValue"></checklist>
показать набор реквизитcheckboxLeftправда
Что еще можно сделать?
Вы можете расширить...