Vue.js でカスタムドロワーコンポーネントを作成する

Element UI フレームワークにはドロワーコンポーネントが用意されていないため、ここではカスタムドロワーコンポーネントの実装方法について解説します。

以下に、ドロワーコンポーネントのソースコードを示します。

<template>
  <div class="custom-drawer">
    <div :class="maskClasses" @click="handleMaskClick"></div>
    <div :class="drawerClasses" :style="drawerStyles">
      <div class="drawer-header">
        <span>{{ title }}</span>
        <span v-if="closable" class="close-button" @click="closeDrawer">×</span>
      </div>
      <div class="drawer-content">
        <slot />
      </div>
    </div>
  </div>
</template>

<script>
export default {
  props: {
    isOpen: {
      type: Boolean,
      required: true
    },
    title: {
      type: String,
      default: 'ドロワータイトル'
    },
    closable: {
      type: Boolean,
      default: true
    },
    showMask: {
      type: Boolean,
      default: true
    },
    maskClosable: {
      type: Boolean,
      default: true
    },
    width: {
      type: String,
      default: '300px'
    },
    isInner: {
      type: Boolean,
      default: false
    }
  },
  computed: {
    maskClasses() {
      return {
        'drawer-mask': true,
        'mask-visible': this.showMask && this.isOpen,
        'mask-hidden': !(this.showMask && this.isOpen),
        'inner-mask': this.isInner
      };
    },
    drawerClasses() {
      return {
        'drawer-panel': true,
        'panel-visible': this.isOpen,
        'panel-hidden': !this.isOpen,
        'inner-panel': this.isInner
      };
    },
    drawerStyles() {
      const styles = {
        width: this.width,
        right: this.isOpen ? '0' : `-${this.width}`,
      };
      if (!this.showMask) {
        styles.borderLeft = '1px solid #eee';
      }
      return styles;
    }
  },
  mounted() {
    if (this.isInner) {
      const parentElement = this.$el.parentNode;
      parentElement.style.position = 'relative';
    }
  },
  methods: {
    handleMaskClick() {
      if (this.maskClosable) {
        this.$emit('update:isOpen', false);
      }
    },
    closeDrawer() {
      this.$emit('update:isOpen', false);
    }
  }
};
</script>

<style lang="scss" scoped>
.custom-drawer {
  .drawer-mask {
    position: fixed;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    z-index: 1000;
    background-color: rgba(0, 0, 0, 0.5);
    opacity: 1;
    transition: opacity 0.5s ease;

    &.mask-hidden {
      opacity: 0;
    }
    &.inner-mask {
      position: absolute;
    }
  }

  .drawer-panel {
    position: fixed;
    z-index: 1001;
    top: 0;
    height: 100%;
    background-color: #fff;
    transition: transform 0.5s ease, opacity 0.5s ease;
    box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);

    &.panel-visible {
      opacity: 1;
    }
    &.panel-hidden {
      opacity: 0;
    }
    &.inner-panel {
      position: absolute;
    }
  }

  .drawer-header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    height: 50px;
    padding: 0 20px;
    border-bottom: 1px solid #e0e0e0;
    font-size: 16px;
    font-weight: bold;

    .close-button {
      cursor: pointer;
      font-size: 18px;
      padding: 5px;
    }
  }

  .drawer-content {
    padding: 20px;
  }
}
</style>

このコンポーネントの使用例を以下に示します。

<template>
  <div class="usage-example">
    <el-button type="primary" @click="drawerVisible = true">ドロワーを開く</el-button>
    
    <custom-drawer 
      title="詳細情報" 
      :isOpen.sync="drawerVisible" 
      :isInner="true" 
      :width="'450px'" 
      :showMask="false">
      <p>これはドロワー内のコンテンツです。</p>
      <p>追加情報はこちらに記載します。</p>
    </custom-drawer>
  </div>
</template>

<script>
import CustomDrawer from '@/components/CustomDrawer.vue';

export default {
  components: {
    CustomDrawer
  },
  data() {
    return {
      drawerVisible: false
    };
  }
};
</script>

タグ: vue.js コンポーネント カスタムコンポーネント ドロワー UI

5月25日 17:36 投稿