page.vue 3.06 KB
<template>
  <view ref="page" :class="['page', `page-${name}`]"
    :style="{ paddingTop: `${headerH}px`, paddingBottom: `${footerH}px` }">
    <view v-if="$slots.header" id="header" :class="['page__header', `page-${name}__header`]">
      <slot name="header"></slot>
    </view>
    <view v-if="$slots.content" :class="['page__content', `page-${name}__content`, flank ? 'flank' : '']"
      :style="{ minHeight: `calc(100vh - ${headerH}px - ${footerH}px)` }">
      <slot name="content"></slot>
    </view>
    <view v-if="$slots.footer" id="footer" :class="['page__footer', `page-${name}__footer`]">
      <slot name="footer"></slot>
    </view>
    <slot></slot>
  </view>
</template>

<script>
import { mapState } from 'vuex';

export default {
  props: {
    name: {
      type: String,
      required: true,
    },
    flank: Boolean,
  },
  computed: {
    ...mapState({
      authed: state => state.authed,
    }),
  },
  data() {
    return {
      headerH: 0,
      footerH: 0,
    };
  },
  beforeCreate() {
    if (this.$root.$options.onAuthed) {
      if (this.authed) {
        this.$root.$options.onAuthed.bind(this.$root)(true);
      } else {
        uni.$on('authed', authed => {
          if (authed) {
            this.$root.$options.onAuthed.bind(this.$root)(authed);
          }
        });
      }
    }
    if (this.$root.$options.onAuth) {
      uni.$on('authed', authed => {
        if (authed) {
          this.$root.$options.onAuth.bind(this.$root)(authed);
        }
      });
    }
  },
  created() {
    if (this.$root.$options.onAuthed) {
      if (this.authed) {
        this.$root.$options.onAuthed.bind(this.$root)(true);
      }
    }
  },
  mounted() {
    this.fit();
  },
  methods: {
    fit() {
      uni.createSelectorQuery().in(this).select('#header').fields({
        size: true,
        scrollOffset: true,
        rect: true
      }, data => {
        if (data) this.headerH = data.height;
      }).exec();
      uni.createSelectorQuery().in(this).select('#footer').fields({
        size: true,
        scrollOffset: true,
        rect: true
      }, data => {
        if (data) this.footerH = data.height;
      }).exec();
    }
  }
};
</script>

<style lang="scss">
  .page {
    box-sizing: border-box;
    min-height: 100vh;
    width: 100vw;
    overflow-x: hidden;
    background-color: $color-bg-base;

    &__header {
      position: fixed;
      top: 0;
      left: 0;
      width: 100%;
      z-index: 10;
      box-sizing: border-box;
      padding: $padding-md;
      background-color: $color-white;
    }

    &__content {
      box-sizing: border-box;
      padding-top: $padding-md;
      padding-bottom: $padding-md;

      &.flank {
        padding-left: $padding-md;
        padding-right: $padding-md;
      }
    }

    &__footer {
      box-sizing: border-box;
      position: fixed;
      bottom: 0;
      left: 0;
      width: 100%;
      z-index: 10;
      padding: $padding-sm;
      padding-bottom: 60upx !important;
      button {
        border-radius: 14rpx;
        font-size: 15px;
        font-weight: 500;
        min-height: 80rpx;
      }
    }
  }
</style>