Vue với Element UI: Tạo hiệu ứng co giãn hai bên sử dụng el-drawer hoặc CSS

Một yêu cầu phổ biến trong giao diện quản trị là cho phép người dùng thu gọn/mở rộng thanh bên trái để tối ưu không gian hiển thị nội dung chính. Bài viết này trình bày cách thực hiện chức năng này trong Vue.js sử dụng thư viện Element UI, với hai phương án: dùng el-drawer tùy chỉnh và dùng CSS thuần.

Phương án 1: Sử dụng el-drawer tùy chỉnh hướng mở

Tận dụng component el-drawer của Element UI, ta có thể tạo hiệu ứng trượt từ trái sang phải bằng cách thiết lập thuộc tính direction="ltr". Để drawer không che toàn màn hình mà chỉ chiếm vùng bố cục nhất định, cần điều chỉnh một số thuộc tính.

<template>
  <el-row :gutter="20" style="margin-top: 1%">
    <!-- Vùng bên trái -->
    <el-col :span="leftSpan" class="position-relative">
      <div class="drawer-wrapper">
        <el-drawer
          class="custom-drawer"
          :visible.sync="isDrawerOpen"
          direction="ltr"
          :modal="false"
          :show-close="false"
          :append-to-body="false"
          :wrapperClosable="false"
          size="100%"
        >
          <el-card class="side-card">
            <div slot="header">Nội dung bên trái</div>
            <div>Danh sách tùy chọn...</div>
          </el-card>
        </el-drawer>

        <!-- Nút toggle -->
        <div class="toggle-btn" :class="{ 'expanded': isDrawerOpen }" @click="toggleDrawer">
          <img
            v-if="!isDrawerOpen"
            :src="require('@/assets/image/zhankai.png')"
            alt="Mở rộng"
            width="25"
            height="40"
          />
          <img
            v-else
            :src="require('@/assets/image/shousuo.png')"
            alt="Thu gọn"
            width="25"
            height="40"
          />
        </div>
      </div>
    </el-col>

    <!-- Vùng bên phải -->
    <el-col :span="rightSpan" class="main-content">
      <el-card>
        <div>Nội dung chính - Bảng dữ liệu người dùng</div>
      </el-card>
    </el-col>
  </el-row>
</template>

Giải thích cấu hình drawer:

  • :append-to-body="false": Drawer được render trong phần tử cha thay vì chèn vào body.
  • :modal="false": Tắt lớp phủ mờ (overlay).
  • :show-close="false": Ẩn nút đóng mặc định.
  • :wrapperClosable="false": Không cho phép đóng khi click ra ngoài.
  • direction="ltr": Mở từ trái sang phải.

Logic xử lý trong Vue instance:

export default {
  data() {
    return {
      isDrawerOpen: true,
      leftSpan: 8,
      rightSpan: 15
    };
  },
  methods: {
    toggleDrawer() {
      this.isDrawerOpen = !this.isDrawerOpen;
      if (this.isDrawerOpen) {
        this.leftSpan = 8;
        this.rightSpan = 15;
      } else {
        this.leftSpan = 1;
        this.rightSpan = 23;
      }
    }
  }
};

CSS kèm hiệu ứng chuyển tiếp:

<style lang="scss" scoped>
.position-relative {
  position: relative;
  transition: all 0.3s ease;
}

.drawer-wrapper {
  position: relative;
  height: 350px;
}

.toggle-btn {
  position: absolute;
  top: 30%;
  z-index: 1000;
  background: #fff;
  border-radius: 0 4px 4px 0;
  transition: all 0.3s;
  &.expanded { right: 0; background: #f5f5f5; }
  &:not(.expanded) { left: 0; }
}

.custom-drawer ::v-deep .el-drawer__header {
  display: none;
}

.main-content, .side-card {
  transition: all 0.3s ease;
}
</style>

Phương án 2: Dùng CSS linh hoạt (khuyến nghị)

Nếu chỉ cần hiệu ứng co giãn đơn giản, không cần các tính năng phức tạp của drawer, nên dùng CSS kết hợp Flexbox để tối ưu hiệu suất và dễ kiểm soát hơn.

<template>
  <el-row style="margin-top: 1%">
    <div class="flex-layout">
      <div class="sidebar" :class="{ 'collapsed': !isExpanded }">
        <el-card>
          <div>Nội dung bên trái</div>
        </el-card>
      </div>

      <div class="toggle-trigger" @click="toggleExpand">
        <img
          :src="isExpanded ? require('@/assets/image/shousuo.png') : require('@/assets/image/zhankai.png')"
          :alt="isExpanded ? 'Thu gọn' : 'Mở rộng'"
          width="25"
          height="40"
        />
      </div>

      <div class="main-area" :class="{ 'expanded': isExpanded }">
        <el-card>
          <div>Nội dung chính</div>
        </el-card>
      </div>
    </div>
  </el-row>
</template>
export default {
  data() {
    return {
      isExpanded: true
    };
  },
  methods: {
    toggleExpand() {
      this.isExpanded = !this.isExpanded;
    }
  }
};
<style lang="scss" scoped>
.flex-layout {
  display: flex;
  align-items: stretch;
  width: 100%;
}

.sidebar {
  width: 35%;
  transition: width 0.3s ease;
  &.collapsed { width: 0; min-width: 0; overflow: hidden; }
}

.main-area {
  flex: 1;
  transition: flex 0.3s ease;
  &.expanded { flex: 0.65; }
  &:not(.expanded) { flex: 0.95; }
}

.toggle-trigger {
  cursor: pointer;
  display: flex;
  align-items: center;
  padding: 0 10px;
  background: #f9f9f9;
}

.el-card {
  height: 350px;
}
</style>

Phương án thứ hai giúp giảm sự phụ thuộc vào component UI, tăng tính linh hoạt và hiệu năng. Tuy nhiên, nếu cần animation phức tạp hay tích hợp thêm hành vi modal, el-drawer vẫn là lựa chọn phù hợp.

Thẻ: Vue.js Element UI el-drawer CSS Transitions flexbox

Đăng vào ngày 9 tháng 9 lúc 07:51