Этот учебник будет разбит на несколько историй; каждый из них исследует отдельную концепцию, так что вы можете читать только интересные части, а не все. Это пятая история в серии о создании диалогов и связанных с ними концепциях. Ссылки на рассказы:
- Часть 1: предыстория и целевое приложение
- Часть 2: сервер golang
- Часть 3: интеграция golang и javascript
- Часть 4: SPA с Vue.js
- Часть 5: диалоги
- Часть 6: нотная составляющая
исходный код @ здесь:
Https://github.com/quoeamaster/golang_blogs/tree/master/2020-03-gui-task-app
добавление верхней строки меню
Обычный компонент пользовательского интерфейса - это строка меню верхнего уровня. Menubar выполняет несколько функций, включая место для отображения заголовка приложения, предоставление популярных опций меню, таких как «добавить», «сохранить», «загрузить» и т. Д. На данный момент мы просто добавим заголовок приложения плюс «добавить примечание »в строке меню.
HTML-код строки меню выглядит следующим образом:
... <!-- splash --> <splash-screen></splash-screen> <div style="height: 30px; box-shadow: 0 4px 5px #aaa; line-height: 30px; vertical-align: middle; padding-left: 4px; padding-right: 4px;"> <div class="float-left" style="font-family: 'Comic Sans MS'; font-size: 0.8em;"> daily task app </div> <div class="float-right" style="font-size: 1.1em; margin-top: 4px;"> <i class="far fa-sticky-note" style="cursor: pointer;"></i> </div> </div> {{msg}} <button class="btn btn-primary">bootstrap buttons</button> ...
PS. чтобы проиллюстрировать, какие стили CSS были применены к строке меню; теперь все стили встроены. Если возникнут проблемы с обслуживанием, со временем следует переместить все стили CSS обратно в таблицы стилей.
Единственная деталь, на которую следует обратить внимание, - это «значок»; здесь мы используем иконки с потрясающим шрифтом ‹i class =« far fa-sticky-note »›. Мы можем просто рассматривать каждый значок здесь как символ символа (ресурс шрифта), поэтому он намного эффективнее по сравнению с реальным фоторесурсом.
После того, как мы закончили отображение пользовательского интерфейса, пришло время подключить значок к обработчику событий.
обновите следующее:
<div class="float-right" style="font-size: 1.1em; margin-top: 4px;"> <i class="far fa-sticky-note" style="cursor: pointer;" v-on:click="onAddNoteClick"></i> </div>
Мы добавили v-on: click = «functionName», что означает, что теперь мы привязываем событие onClick этого значка к вызову функции. Соответственно, в app.js нам нужно будет снова добавить функцию с именем «onAddNoteClick»:
... data: function () { return { msg: 'vue app created', }; }, methods: { onAddNoteClick: function () { alert('time to add a note'); } } ...
А пока мы просто показываем окно с предупреждением, но вскоре заменим этот код, чтобы отобразить диалоговое окно создания заметки. Повторно соберите приложение и запустите его, в результате получится следующее:
Мягкое напоминание о процессе сборки (объяснения доступны в Части 4 серии):
go run generateAssets.go mv generateAssets.go generateAssets.go.disable go build -o taskApp mv generateAssets.go.disable generateAssets.go ./taskApp
создание диалога
Javascript предоставляет диалоговые окна по умолчанию, такие как окно подтверждения и окно предупреждения, но оно может быть не таким красивым и красивым, поэтому мы могли бы создать свои собственные диалоговые окна. Давайте создадим новый файл js - createNoteDlg.js
Исходный код будет следующим:
Vue.component('create-note-dlg', { template: ` <div style="width: 600px; height: 300px; margin: auto; border: 1px solid #ddd; border-radius: 4px; z-index: 20;" class="core-display-block"> <div style="text-align: center; font-size: 1.1em; margin-top: 4px; margin-bottom: 12px;"> create a note~ </div> <div style="padding-left: 12px; padding-right: 12px;"> <input class="form-control" style="margin-bottom: 4px;" placeholder="position: x coordinate"> <input class="form-control" style="margin-bottom: 4px;" placeholder="position: y coordinate"> <textarea class="form-control" rows="5" style="margin-bottom: 4px;" placeholder="content of the note"></textarea> </div> </div> ` });
Затем нам нужно будет снова добавить компонент в index.html:
... <div id="app"> <!-- splash --> <splash-screen></splash-screen> <!-- the menubar --> ... <!-- create note dlg --> <create-note-dlg></create-note-dlg> </div> <!-- load back all vue related components; app.js MUST be the last one --> <script src="./component/demo/splash.js"></script> <script src="./component/demo/createNoteDlg.js"></script> <script src="./component/demo/app.js"></script> ...
который дает:
Хорошо, внешний вид диалога готов ... но не должен отображаться, пока не будет нажата иконка «добавить заметку»! Измените класс компонента диалога с core-display-block на core-display-none (сделайте его невидимый). Обновите функцию onAddNoteClick, расположенную в app.js.
new Vue({ el: '#app', data: function () { return { displayDlg: false }; }, methods: { // * ------------------ * // * event handlers * // * ------------------ * onAddNoteClick: function () { this.displayDlg = true; } } });
Давайте посмотрим на 2 строки обновленного кода в app.js:
- добавить новый логический член данных (локальное состояние) - displayDlg. Это локальное состояние определяет, должен ли отображаться диалог.
- в соответствующей функции onAddNoteClick; обновить локальное состояние «displayDlg» до true
Затем нам нужно будет также изменить index.html:
... <!-- create note dlg --> <create-note-dlg v-bind:show="displayDlg"></create-note-dlg> ...
Обратите внимание на атрибут v-bind: show = «displayDlg», мы передаем значение локального состояния - displayDlg в «диалог создания заметки». Переданное значение указывает, должен ли диалог быть видимым или нет. Давайте посмотрим на соответствующее изменение кода на createNoteDlg.js:
Vue.component('create-note-dlg', { props: ['show'], methods: { getDlgCss: function () { let c = {}; console.log(this.show); if (this.show === true) { c['core-display-block'] = true; c['core-display-none'] = false; } else { c['core-display-block'] = false; c['core-display-none'] = true; } return c; } }, template: ` <div style="width: 600px; height: 380px; margin: auto; border: 1px solid #ddd; border-radius: 4px; z-index: 20; overflow: auto;" class="core-display-block" v-bind:class="getDlgCss()"> ... </div> ` });
Важные изменения кода:
- верните настройку «props» - мы ясно видим, что доступен элемент с именем «show». Параметр props соответствует тому, какие значения можно ПОЛУЧИТЬ от его родительского компонента (в нашем случае компонент app).
- добавлен новый метод «getDlgCss». Вернуть объект классов css, соответствующий значению полученного значения «show»
- наконец, добавьте v-bind: class = «getDlgCss ()» в элемент div верхнего уровня; так что теперь мы можем контролировать, должен ли отображаться диалог или нет
Повторная сборка приложения и запуск даст:
Приятно ~ Выглядит пока неплохо; так как мы могли скрыть диалог позже? Давайте добавим несколько кнопок и предположим, что нажатие кнопки «отмена» закроет диалог:
Vue.component('create-note-dlg', { ... template: ` <div style="width: 100%; height: 100%; position: absolute; top: 0; left: 0; z-index: 10; padding-top: 40px; background-color: rgba(230,230,230,0.8);" v-bind:class="getDlgCss()"> <div style="width: 600px; height: 380px; margin: auto; border: 1px solid #ddd; border-radius: 4px; z-index: 20; overflow: auto; background-color: white;"> <div style="text-align: center; font-size: 1.1em; margin-top: 4px; margin-bottom: 12px;"> create a note~ </div> <div style="padding-left: 12px; padding-right: 12px;"> <input class="form-control" style="margin-bottom: 4px;" placeholder="position: x coordinate"> <input class="form-control" style="margin-bottom: 4px;" placeholder="position: y coordinate"> <textarea class="form-control" rows="5" style="margin-bottom: 4px;" placeholder="content of the note"></textarea> </div> <div class="float-right"> <button class="btn btn-primary">save</button> <button class="btn btn-secondary" v-on:click="onCancel">cancel</button> </div> </div> </div> ` });
Мы видим, что добавлены 2 кнопки, кнопка «Отмена» прикреплена к обработчику события с именем «onCancel».
PS. Фон (элемент div) также добавляется для обтекания содержимого диалога; в основном просто для лучшего визуального эффекта :)
... methods: { getDlgCss: function () { ... }, onCancel: function () { this.$emit('on-display-dlg-update', false); } }, ...
Функция onCancel имеет только 1 строку кода = ›отправку события своему родительскому компоненту - компоненту приложения. Здесь вступает в действие еще одна важная концепция - дочерние компоненты НИКОГДА не могут изменять состояния родительских компонентов; следовательно, вместо того, чтобы напрямую изменять родительские состояния, мы могли бы создать событие и позволить родителю выполнить обновление.
Теперь измените index.html следующим образом:
... <!-- create note dlg --> <create-note-dlg v-on:on-display-dlg-update="onDisplayDlgUpdate" v-bind:show="displayDlg"></create-note-dlg> ...
PS. соответствующее переданное событие ДОЛЖНО быть объявлено в дочернем компоненте, как указано выше.
Обновите наш файл app.js:
new Vue({ el: '#app', data: function () { return { displayDlg: false }; }, methods: { ... onDisplayDlgUpdate: function (data) { this.displayDlg = false; } } });
Вот так просто ... обновите член данных displayDlg обратно на false, и все готово! Повторная сборка приложения и запуск даст:
модель данных в Vue.js
Теперь у нас уже есть рабочий диалог графического интерфейса для ввода данных новой заметки / задачи. Следующее, как записать эти значения для дальнейшей обработки?
В Vue.js есть синтаксис v-model для захвата входных данных из элементов html. Давайте посмотрим, как это работает:
Vue.component('create-note-dlg', { props: ['show'], data: function() { return { x: "", y: "", content: "" }; }, methods: { ... onSave: function () { alert(this.x+','+this.y+','+this.content); } }, template: ` <div style="width: 100%; height: 100%; position: absolute; top: 0; left: 0; z-index: 10; padding-top: 40px; background-color: rgba(230,230,230,0.8);" v-bind:class="getDlgCss()"> ... <input v-model="x" class="form-control" style="margin-bottom: 4px;" placeholder="position: x coordinate"> <input v-model="y" class="form-control" style="margin-bottom: 4px;" placeholder="position: y coordinate"> <textarea v-model="content" class="form-control" rows="5" style="margin-bottom: 4px;" placeholder="content of the note"></textarea> ... </div> </div> ` });
Во-первых, мы снова добавляем параметр «данные» в компонент. Если вы все еще помните, «данные» содержат объявления локальных состояний этого компонента - в этом сценарии:
- Координата x ноты
- Координата Y ноты
- содержание заметки (например, бег трусцой в течение 30 минут, купить Лилиан подарок на день рождения)
Затем необходимо привязать входные значения (из текстовой области HTML и текстового ввода) к локальным состояниям; это достигается с помощью синтаксиса v-model = «local_state_name».
Повторная сборка и запуск приложения даст:
Мы сделали это, теперь содержание этого диалога передается в местные государства. Может быть, вы спросите, что нам нужно для использования локальных состояний вместо прямого запуска jQuery, чтобы вернуть эти значения ???
Смысл в том, чтобы избежать прямого доступа к значению HTML-элементов; в старые добрые времена jQuery - лучший, а также ЕДИНСТВЕННЫЙ фреймворк, который мы могли использовать для доступа к значению HTML-элементов ПЛЮС… для их ИЗМЕНЕНИЯ. Если мы просто намерены выполнять доступ ТОЛЬКО ДЛЯ ЧТЕНИЯ к значениям, это совершенно нормально; однако, когда нам также необходимо изменить значения - это то, что мы знали как повреждение данных. Возможность прямого изменения значений может вызвать следующие проблемы:
- без общего места для управления изменением значений - например, проверка новых значений может выполняться перед принятием изменения. Таким образом, прямой доступ означает, что эта логика проверки может быть забыта ИЛИ разбросана повсюду.
- если вы были единственным разработчиком компонента, то все равно можно было бы поддерживать подход прямого доступа к коду; однако… если бы команда разработчиков работала над одним и тем же компонентом, то очень скоро это могло бы войти в хаос, поскольку мы не знаем, когда и почему разработчики напрямую обращаются к некоторым атрибутам / значениям HTML-элементов и изменяют их. Ремонтопригодность вызывает сомнение
Двигаемся дальше…
В этом уроке / рассказе; мы рассмотрели следующее:
- использование font-awesome для создания интерактивных иконок; помните, что font-awesome - это глифы, а не ресурсы изображения, поэтому они более эффективны.
- научились прикреплять обработчики событий к HTML-компонентам (например, значку)
- создали наш первый модальный диалог; снова благодаря силе css :)
- узнал, как родительский компонент (например, компонент приложения) может передавать свои локальные состояния дочернему компоненту (например, диалогу) с помощью синтаксиса v-bind
- узнал, как дочерний компонент может получать информацию о состоянии родителя с помощью параметра «props».
- использовать значение местного состояния и контролировать внешний вид диалога с помощью выбора класса css (например, чтобы показать или скрыть диалог)
- научились обновлять информацию о местном штате родителей с помощью событий. Помните, что дочерние компоненты НИКОГДА не могут изменять информацию о состоянии родителей (ТОЛЬКО ДЛЯ ЧТЕНИЯ). Ключ должен запустить «this. $ Emit (‘ event-name ’, {{payload / data}});»
- узнал, как родительский компонент может быть подтвержден по запросу на изменение состояния. Секрет заключается в следующем: «v-on: {{event-name}} =‘ event-handler-function ’»
- наконец, как Vue.js реагирует на обработку данных уровня формы - синтаксис v-model.
Это довольно много ~ Наш следующий урок / рассказ будет посвящен тому, как создать компонент Note на основе информации, полученной компонентом диалога. Будьте на связи. :)))