Фреймы
Введение
Приложение apx не основывается на клиенском роутинге, как многие. Нет, как таковой,
роутинг присутствует, но не является основным и обязательным механизмом взимодействия с
различными частями приложения.
Вместо клиентского роутинга используются "фреймы".
Представим себе такое стандартное расположение основных элементов страницы:
В областях "header" и "menu" - управляющие элементы. В области "main" - контент, который меняется, в зависимости от того, что выбрано в "header" или "main", например щелчек по какой-то кнопке.
Фрейм как раз и предназначен для того, что бы отображать информацию в "main".
А теперь представим себе диалог. Такую панель, которая содержит что-то, имеет кнопки "ок" , "отмена". При показе может быть модальным. И т.д.
Фрейм предназначен еще и для того, что бы отображать информацию в диалогах.
Фрейм - это vue-компонент
Фрейм - это vue-компонент, который должен быть унаследован от apx.JcFrame.
Пример простейшего фрейма:
<template>
<div>
Страница
</div>
</template>
<script>
import {apx} from './vendor'
export default {
extends: apx.JcFrame,
}
</script>Декораторы фрейма
Фрейм должен отрисовывать себя сам полностью. Ему предоставляется некоторая область экрана (в примере выше это "main") и он ее полностью отрисовывает, включая все оформление, например заголовки.
Если фрейм используется как диалог, то он должен отрисовать диалог полностью, включая все кнопки диалога, его заголовок и т.д.
Естественно повторять оформление от фрейма к фрейму мало кому хочется. Поэтому для фрейма используются декораторы.
Декоратор фрейма - это vue-компонент, который используется в качестве корневого компонента в шаблоне фрейма.
Пример фрейма с декоратором:
<template>
<decor-page>
<template #toolbar>
<jc-action icon="mail"/>
<jc-action icon="calendar"/>
</template>
Страница
</decor-page>
</template>
<script>
import {apx} from './vendor'
export default {
extends: apx.JcFrame,
created() {
this.title = 'Простая страница'
this.title2 = 'Есть мелкий заголовок'
this.icon = 'frame'
},
}
</script>Компонент decor-page является декоратором фрейма.
По умолчанию для фрейма зарегистрированы следующие декораторы:
decor-page- для фреймов-страниц в "main". Компонент-декоратор:apxUi.JcDecorFramePagedecor-dialog- для фреймов-диалогов. Компонент-декоратор:apxUi.JcDecorFrameDialog
Собственные декораторы
Никто не мешает Вам разработать собственные декотораторы и использовать их. В качестве стартовых примеров можно взять существующие декортаторы.
Правила их написания просты:
- нужно унаследовать компонент от
apx.JcDecorFrame - у вас есть ссылка на оформляемый фрейм в свойстве
own. Его свойства можно использовать при оформлении. Например - заголовок фрейма.
Показ фрейма
Функция apx.showFrame показывает фрейм как страницу в "main".
apx.showFrame({
frame: FRAME,
props: {PROPS},
})
Параметры:
frame- какой фрейм нужно показать. Может быть компонентом vue, import()-модуля, путем в роутингеprops- свойства компонента-фрейма.
Функция apx.showFrame асинхронная. Она возвращает Promise, который ресолвится
экземпляром фрейма после показа.
frameInit
Фрейм может иметь опцию-функцию frameInit. Функция может быть асинхронной. Эта функция
вызывается перед тем, как фрейм будет показан. В качестве параметра в функцию передается
экземпляр класса apx.FrameWrapper.
Цель этой функции - загрузить данные в свойство FrameWrapper.frameData, которые затем
можно использовать как данные в работе компонента-фрейма.
В момент вызова функции frameInit компонент-фрейм еще не существует. Поэтому this
внутри тела функции не определен.
Пример:
<template>
<decor-page>
<div class="q-gutter-md">
<div>users: {{ users }}</div>
<div>dummyList: {{ frameData.dummyList }}</div>
<div>post: {{ frameData.post }}</div>
</div>
</decor-page>
</template>
<script>
import {apx} from '../vendor'
export default {
extends: apx.JcFrame,
// свойства фрейма
props: {
// количество генерируемых строк
cnt: {}
},
// метод будет вызван перед монтированием и показом
// fw это экземпляр apx.FrameWrapper
// функция может быть асинхронной
async frameInit(fw) {
// данные, которые необходимо заполнить
let frameData = fw.frameData
// свойства, которые были переданы фрейму при вызове showFrame
let props = fw.props
// берем значение свойств
let cnt = apx.jcBase.toInt(props.cnt, 5)
// проверяем их
if (cnt > 10) {
throw new Error('Слишком много строк заказано')
}
// используем свойства для формирования данных
frameData.dummyList = []
for (let i = 1; i <= cnt; i++) {
frameData.dummyList.push({id: i, text: 'text-' + i})
}
// можно выполнять запросы
let users = await apx.jcBase.ajax.request({
method: 'get',
url: 'https://jsonplaceholder.typicode.com/users'
})
frameData.users = users.data
// даже несколько запросов
let post = await apx.jcBase.ajax.request({
method: 'get',
url: 'https://jsonplaceholder.typicode.com/posts/1'
})
frameData.post = post.data
// в консоле печатается frameWrapper, можно посмотреть что загрузилось
},
created() {
this.title = 'FrameInit demo'
// frameData доступно как свойство компонента
let frameData = this.frameData
// можно использовать
for (let user of frameData.users) {
this.users.push(user.username)
}
// frameData можно напрямую использовать в шаблоне
},
data() {
return {
users: [],
}
},
}
</script>frameInit не наследуется
frameInit не наследуется при наследовании компонентов! В каждом фрейме должен быть
собственный frameInit.
Пример:
import FrameInit from './FrameInit'
export default {
// наследуем существующий фрейм
extends: FrameInit,
// frameInit не наследуется!
async frameInit(fw) {
// вызываем унаследованный
await FrameInit.frameInit(fw)
}
}