Vue 利用slot封装一个自定义程度高的 Dropdown 组件

         有一个页面用到了几种样式不同的Dropdown按钮,想将每个dropdown按钮的开关状态分组件管理,但是封装了组件之后按钮又难以自定义,所以想出这样一个 使用slot传出值方式来将封装在组件内部的方法和状态绑定到组件外自定义的按钮上 的方法。

 Dropdown组件:

 因为要兼容ie9,没有使用 他处点击指令(关键api contains 在ie10才受到支持)

<template>
  <div class="dropdown-box">
    <!-- 下拉框打开时的遮罩层 -->
    <div class="backdrop" v-show="dropdownShow" @click="toggleDropdown"></div>

    <!-- 关键代码 -->
    <!-- 将value传出组件。将按钮的点击事件传出组件 -->
    <slot :label="getDropdownValue(FilterOptions, value)" :click="toggleDropdown"/>
    
    <!-- 此处也可使用slot自定义:将click事件、dropdownShow传出组件,在组件外绑定到元素上 -->
    <ul class="select" v-show="dropdownShow">
      <li class="option"
        v-for="item in FilterOptions"
        :key="item.value"
        @click="$emit('change', item.value)"
      >
        <a>{{item.label}}</a>
      </li>
    </ul>

  </div>
</template>

<script>
export default {
  props: {
    FilterOptions: Array, // 接收dropdown的枚举值
    value: Number, // v-model绑定的当前选择的value
  },
  data() {
    return {
      dropdownShow: false, // 是否展示下拉框
    }
  },
  // 自定义组件的v-model
  model: {
    prop: 'value',
    event: 'change'
  },
  methods: {
    // 打开、关闭下拉框,回调函数
    toggleDropdown() {
      this.dropdownShow = !this.dropdownShow;
      if(this.dropdownShow) {
        this.$emit('open');
      } else {
        this.$emit('close');
      }
    },

    // 获取dropdown的label值展示在按钮上
    getDropdownValue(filterOptions, val) {
      return filterOptions.find(item => item.value === val)?.label;
    },
  }
}
</script>

<style lang="less" scoped>
.backdrop{
  position: fixed;
  top: 0;
  bottom: 0;
  left: 0;
  right: 0;
  margin: auto;
  z-index: 50;
}
.dropdown-box{
  position: relative;
  display: inline-block;
  vertical-align: middle;
  border: none;
  .select{
    position: absolute;
    width: 100%;
    top: 100%;
    margin-top: 6px;
    padding: 6px 0;
    left: 0;
    background: #f9f4e9;
    box-shadow: 4px 4px 8px rgba(105, 105, 105, 0.2);
    border: 1px solid #AE9672;
    border-radius: 4px;
    z-index: 51;
    font-size: 12px;
    text-align: center;
    .option{
      padding: 4px 3px;
      &:hover{
        text-decoration: underline;
      }
    }
  }
}
</style>

使用: 

<template>
  <!-- 传入下拉框的枚举值,绑定v-model -->
  <Dropdown :filter-options="filterOptions" v-model="form.filter1">
    
    <!-- 给自定义的dropdown按钮添加Dropdown组件传出的click方法和label值 -->
    <button class="dropdown" slot-scope="scope" @click="scope.click">
      <span>{{scope.label}}</span>
      <img src="@/assets/img/drop.png">
    </button>
  </Dropdown>
</template>

<script>
import Dropdown from "./Dropdown";

export default {
  components: { Dropdown },
  data() {
    return {
      filterOptions: [{ // Dropdown下拉框的枚举值格式
        value: 0,
        label: "全部",
      }, {
        value: 1,
        label: "经部",
      }, {
        value: 2,
        label: "史部",
      }, {
        value: 3,
        label: "子部",
      }, {
        value: 4,
        label: "集部",
      }],
      form: {
        filter1: 0, // Dropdown的v-model
      },
    }
  },

}
</script>

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值