[SOLVED] Vue+Panel динамичное содержимое

Добрый день Владимир!
Есть два вопроса по боковому правому панели.

  1. Как сделать, чтобы у каждой страницы динамично менять содержимое правой панели? Хочу контролировать через v-model данные внутри панели.
  2. B как сделать так, если у страницы есть содержимое в правой панели, автоматически активировалась параметр swipe=‘both’ ?
    Страниц очень много в данный момент около 72, 30 из них имеет боковую панель, дальше будет больше. Есть простой способ, одним малой кровью сделать это, в предыдущей версии F7/1.6 делал, через атрибут

<div class=“page” data-page=“task-list” data-swipepanel=“both”>?

и потом глобально проверял через событие

myApp.onPageAfterAnimation( ‘*’ , function (page) {
var swipePanel = $$(page.container).data(‘swipePanel’);
//проверял и переназначал
myApp.params.swipePanel = ‘both’;
}

Есть какое то облегченное решение в рамках Vue+F7?

Спасибо!

Облегченного решения тут нет)) По поводу второго пункта можно в принципе сделать тоже самое, только вызвать:

app.panel.enableSwipe('left');
app.panel.enableSwipe('right');

вместо myApp.params.swipePanel = ‘both’;

А по поводу первого пункта хотелось бы более конкретный пример кода

Добрый день Владимир! По первому вопросу. У меня много страниц, где есть список/реестр каких то объектов. При нажатии иконки фильтра или swipe открывается содержимое правой панели, где указаны параметры для фильтрации. Некоторые простые, некоторые наборы фильтров содержат выпадающие списки, и при выборе список(в mainView) должен реагировать на изменение фильтра.


В первой версии F7 я пользовался, тем что заменял внутренность правой панели через, примерно так:
$$('#panelRight').html(content)
внутри контента было много onclick/onchange событий.

Сейчас использую Vue и хотелось, чтобы содержимое правой панели контролировать через один и тот же компонент, или же пробрасывать данные через v-model.

Чтобы это делать так сказать во vue-way, можно передавать туда динамический компонент, например создав такую структуру:

// главный скрипт приложения app.js
new Vue({
  data() {
    return {
      ...
      rightPanelComponent: null,
    }
  }
});
<!-- главный компонент приложения app.vue -->
<f7-panel right>
  <component v-if="$root.rightPanelComponent" :is="$root.rightPanelComponent"></component>
</f7-panel>
// страница в которой нужна своя панель
import pagePanelComponent from './somewhere/some-page-panel.vue';

export default {
  ...
  mounted() {
    // устанавливаем компонент в панель
    this.$root.rightPanelComponent = pagePanelComponent;
  },
  beforeDestroy() {
    // убираем компонент из панели
    this.$root.rightPanelComponent = null;
  },
}

Получилось, в файле(содержимой правой панели)
'./somewhere/some-page-panel.vue'
вызываю нужный метод через
this.$f7.views.main.router.currentRoute.route.component.methods.RequiredMethod(Params)

поторопился, для теста написал метод с выводом в консоль, при использовании Vue теряется this контекст. Те же самые грабли как раньше писал та же самая проблема. Изменения буду отлавливать через EventBus.

Так нельзя, ибо this.$f7.views.main.router.currentRoute.route.component это всего лишь объект с параметрами, а не инициализированный Vue компонент, поэтому никакого контекста там и не будет.

Можно тогда генерировать компонент динамически вроде:

// страница в которой нужна своя панель
export default {
  // ...
  mounted() {
    // контекст данной траницы
    const self = this;
    // устанавливаем компонент в панель
    const rightPanelComponent = {
      template: `
        <f7-page>...</f7-page>
      `,
      methods: {
        someMethod() {
          this // -> контекст компонента правой панели
          self // -> конекст этой страницы
        }
      }
    };
    self.$root.rightPanelComponent = rightPanelComponent;
  },
  beforeDestroy() {
    
    // убираем компонент из панели
    this.$root.rightPanelComponent = null;
  },
}

Хотя тоже немного колхозно

Решил, таким путем. Решил данные и методы пробросить через v-model в $root.

// главный скрипт приложения app.js
new Vue({
data() {
return {

rightPanelComponent: null,
rightPanelInfo: null,
}
}
});

//главный компонент приложения app.vue, добавил v-model, который ссылается на rightPanelInfo
f7-panel right
component v-if="$root.rightPanelComponent" :is="$root.rightPanelInfo" v-model="$root.rightPanelInfo" /component
/f7-panel

//some-page-panel.vue внутри в props ссылаюсь на value,
export default {
name: ‘some-page-panel’,
props: [‘value’],
methods: {
clicked() {
this.value.MyRequiredMethod();
//this.value.$data //данные откуда вызываются.
}
},
}

// страница в которой нужна своя панель
import pagePanelComponent from ‘./somewhere/some-page-panel.vue’;
export default {

mounted() {
// устанавливаем компонент в панель
this.$root.rightPanelComponent = pagePanelComponent;
this.$root.rightPanelInfo = this;
},
beforeDestroy() {
// убираем компонент из панели
this.$root.rightPanelComponent = null;
this.$root.rightPanelInfo = null;
},
}

А как такой метод?

Как вариант тоже неплохо передавать отдельно контекст

внутри ./somewhere/some-page-panel.vue использую Smart Select компонент в консоли выдает ошибку.

[Vue warn]: Error in mounted hook: “Error: Smart Select requires initialized View” …

Пробовал инициализировать через

<f7-view :init=“true”>

не помогает. Документации написано, smart select works only in initialized Views, но так и не разобрался, как и где что делать.

Если у SS параметр openIn: 'page' (по умлочанию) то чтобы был родительский View (f7-view). Если openIn не page, то можно просто передать парметром главный view:

:smart-select-params="{ view: 'view-main' }"

Проблему решил, через setTimeout или setImmediate если использовать hook created. В f7-list поставил проверку на v-if=“show”, потом в hook created, выставляю this.show=true. Или в hook mounted this.show=true.

<template>
    <f7-panel right reveal>
        <f7-view id="right">
            <!--<component v-if="$root.rightPanelComponent" :is="$root.rightPanelComponent" v-model="$root.rightPanelInfo"/>-->
            <f7-page>
                <!--<component v-if="$root.rightPanelComponent" :is="$root.rightPanelComponent" v-model="$root.rightPanelInfo"/>-->

                <f7-list v-if="show">
                    <!-- With back on select -->
                    <f7-list-item smart-select :smart-select-params="{ closeOnSelect: true }" title="Mac or Windows">
                        <select name="mac-windows">
                            <option value="mac">Mac</option>
                            <option value="windows">Windows</option>
                        </select>
                    </f7-list-item>
                </f7-list>

            </f7-page>
        </f7-view>
    </f7-panel>
</template>

<script>
    export default {
        components: {},
        name: 'panel-right',
        data() {
            return {
                show: false
            }
        },
        created: function () {
            setImmediate(() => {
                this.show = true;
            });
        }
    }
</script>

p.s. И еще заметил, что компоненты f7-view и f7-page нельзя использовать раздельно в разных компонентах. Должны всегда следовать друг за другом.
1 Like

Есть такая проблема, должна быть решена в v3, там другой более независимый от Vue логики роутер