经验 - 组件实现思路在实战中的应用:collapse 折叠面板的手风琴效果

16 篇文章 2 订阅
6 篇文章 1 订阅

1,需求

  1. 遍历展示银行列表,每个银行还有子项-分期列表,
  2. 点击银行,会打开对应分期列表,再次点击会关闭。点击另一个银行,会关闭前一个分期列表。
  3. 点击分期列表,会选中分期数,同时展示当前分期相关内容。
  4. 首次进入页面,会默认打开第1个可用银行(item.enabled === true)的分期列表,并选中最高期
  5. 最终获取的数据:当前银行编码+当前分期数。

银行列表数据:

const data = [
  {
    id: 1,
    bankName: "中国银行",
    bankCode: "BKC",
    enabled: true,
    periodNum: 12,
    periods: [
      { periodNum: 3, eachAmount: 400, interest: "4%" },
      { periodNum: 6, eachAmount: 300, interest: "3%" },
      { periodNum: 9, eachAmount: 200, interest: "2%" },
      { periodNum: 12, eachAmount: 100, interest: "1%" },
    ],
  },
  {
    id: 2,
    bankName: "招商银行",
    bankCode: "CMB",
    enabled: true,
    periodNum: 24,
    periods: [
      { periodNum: 3, eachAmount: 400, interest: "4%" },
      { periodNum: 6, eachAmount: 300, interest: "3%" },
      { periodNum: 12, eachAmount: 200, interest: "2%" },
      { periodNum: 24, eachAmount: 50, interest: "1%" },
    ],
  },
];

效果展示
在这里插入图片描述

2,难点

  1. 不能通过 ref 获取分期组件period.vue的实例,再获取选中的期数。
    因为通过遍历list产生的 ref 列表无法保证顺序,所以不能正确获取指定的分期组件实例。
  2. 需求2 不推荐用 item.isActive = !item.isActive + 遍历list关闭打开的分期列表。
    因为不用遍历整个list。只需要关注哪个item的分期列表需要展开即可。

3,思路

  1. 在分期组件period.vue中判断是否打开分期列表:visible = props.item.bankCode === props.currentBank.bankCode
  2. 监听 visible === true 时,赋值当前选中期数:currentPeriod = props.item.periods.find(f => f.periodNum === props.item.periodNum)
  3. 选择期数时,修改父组件的参数 props.currentBank.period

4,实现

index.vue

其中,collapse-transition.vue 是高度折叠动画组件。

<template>
  <ul>
    <li v-for="item in list" @click="handleClick(item)">
      <span>{{ item.bankName }}</span>
      <CollapseTransition>
        <Period :item="item" />
      </CollapseTransition>
    </li>
  </ul>
  <div style="margin-top: 15px">银行编码:{{ currentBank.bankCode }}; 分期数 {{ currentBank.periodNum }}</div>
</template>

<script setup>
import { onBeforeMount, ref, provide } from "vue";
import Period from "./period.vue";
import CollapseTransition from "./collapse-transition.vue";

// 前面有,这里省略。
const data = [];

onBeforeMount(() => {
  usePayList();
});

const list = ref([]);
const usePayList = async () => {
  setTimeout(() => {
    list.value = data;
    initOpenItem();
  }, 1000);
};

// 当前选中银行
const currentBank = ref({});
const updateCurrentBank = (bank) => {
  currentBank.value = bank;
};

provide("bankSymbol", {
  currentBank,
  updateCurrentBank,
});

const handleClick = (item) => {
  if (!item.enabled) {
    return;
  }
  const { bankCode, periodNum } = item;
  // 重复点击关闭
  if (bankCode === currentBank.value.bankCode) {
    updateCurrentBank({});
  } else {
    updateCurrentBank({
      bankCode,
      periodNum,
    });
  }
};

// 初始化默认选中
const initOpenItem = () => {
  let item = list.value.find((f) => f.enabled);
  if (item) {
    const { bankCode, periodNum } = item;
    updateCurrentBank({
      bankCode,
      periodNum,
    });
  }
};

const handleComfirm = () => {
  console.log(currentBank.value);
};
</script>

period.vue

<template>
  <!-- 分期数 -->
  <div v-if="visible && item.periods.length">
    <p>分{{ currentPeriod.periodNum }}期</p>
    <ul>
      <li v-for="p in item.periods" :class="{ active: currentBank.periodNum === p.periodNum }" @click.stop="choosePeriod(p)">
        <span>¥{{ p.eachAmount }}x{{ p.periodNum }}期</span>
        <span>利息¥{{ p.interest }}/期</span>
      </li>
    </ul>
  </div>
</template>

<script setup>
import { ref, computed, watch, inject } from "vue";

const props = defineProps(["item"]);
const { currentBank, updateCurrentBank } = inject("bankSymbol");

// 当前分期
const currentPeriod = ref({});
const choosePeriod = (p) => {
  currentPeriod.value = p;
  updateCurrentBank({
    ...currentBank.value,
    periodNum: p.periodNum,
  });
};

const visible = computed(() => {
  return currentBank.value.bankCode === props.item.bankCode;
});

watch(
  visible,
  (nv) => {
    if (nv) {
      currentPeriod.value = props.item.periods.find((f) => f.periodNum === props.item.periodNum);
    }
  },
  { immediate: true }
);
</script>

以上。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

下雪天的夏风

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值