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

目录

  • 1,需求
  • 2,难点
  • 3,思路
  • 4,实现
    • index.vue
    • period.vue

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%" },
    ],
  },
];

效果展示
经验 - 组件实现思路在实战中的应用:collapse 折叠面板的手风琴效果_第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>

以上。

你可能感兴趣的:(问题解决,element-plus,vue3,前端,vue.js,elementui,vue,javascript)