H5移动端实现自定义分类选择树





<template>
  <div class="pos-content content">
    <div class="group-section">
      <div class="group-item">
        <div class="group-info">人员选择</div>
      </div>
      <div class="pb10">
        <van-search
          class="search"
          v-model="searchValue"
          @input="onSearch"
          placeholder="输入姓名"
        />
      </div>
    </div>
    <div class="blackbox"/>
    <div class="botton-box">
      <ul>
        <li v-for="province in cityData" :key="province.id" class="province-item">
          <span @click="toggle(province)">
            <span class="triangle" :class="{ 'open': province.isOpen }"></span>
            <img src="../../assets/images/box.png" alt="" class="link-icon">
            {{ province.name }}
          </span>
          <ul v-if="province.children && province.isOpen">
            <li v-for="city in province.children" :key="city.id" class="city-item">
              <span @click="toggle(city)">
                <span class="triangle" :class="{ 'open': city.isOpen }"></span>
                <img src="../../assets/images/box.png" alt="" class="link-icon">
                {{ city.name }}
              </span>
              <ul v-if="city.children && city.isOpen">
                <li v-for="district in city.children" :key="district.id" class="district-item">
                  <span class="district-name">{{ district.name }}</span>
                  <label class="radio-label">
                    <input
                      type="radio"
                      :name="city.name"
                      :value="district.id"
                      v-model="selectedDistrict"
                      @change="handleSelection(district)"
                    />
                    <span class="radio-custom"></span>
                  </label>
                </li>
              </ul>
            </li>
          </ul>
        </li>
      </ul>
    </div>
    <div class="buttons">
      <div class="no-data">{{ showName }}</div>
      <button class="cancel-button" @click="onCancel">取消</button>
      <button class="confirm-button" @click="onConfirm">确定</button>
    </div>
  </div>
</template>

<script>
export default {
  data() {
    return {
      showName: "暂无人员选择",
      selectedDistrict: null,
      searchValue: null,
      cityData: [
        {
          id: 1,
          name: '省份A',
          isOpen: false,
          children: [
            {
              id: 2,
              name: '城市A1',
              isOpen: false,
              children: [
                { id: 3, name: '区A1-1' },
                { id: 4, name: '区A1-2' }
              ]
            },
            {
              id: 5,
              name: '城市A2',
              isOpen: false,
              children: [
                { id: 6, name: '区A2-1' },
                { id: 7, name: '区A2-2' }
              ]
            }
          ]
        },
        {
          id: 8,
          name: '省份B',
          isOpen: false,
          children: [
            {
              id: 9,
              name: '城市B1',
              isOpen: false,
              children: [
                { id: 10, name: '区B1-1' },
                { id: 11, name: '区B1-2' }
              ]
            }
          ]
        }
      ]
    };
  },
  methods: {
    onConfirm() {
      alert('Confirm button clicked');
    },
    onSearch() {
      if (this.searchValue) {
        this.autoSelectDistrict(this.cityData, this.searchValue);
      } else {
        this.selectedDistrict = null;
        this.showName = "暂无人员选择";
      }
    },
    onCancel() {
      this.$router.go(-1);
    },
    toggle(item) {
      item.isOpen = !item.isOpen;
    },
    handleSelection(district) {
      this.showName = district.name;
      console.log('选中的区域:', district);
      this.selectedDistrict = district.id;
    },
    autoSelectDistrict(data, keyword) {
      let found = false;
      data.forEach(province => {
        if (province.children) {
          this.toggle(province)
          province.children.forEach(city => {
            if (city.children) {
              this.toggle(city)
              const district = city.children.find(district => district.name.includes(keyword));
              if (district) {
                this.selectedDistrict = district.id;
                this.showName = district.name;
                found = true;
              }
            }
          });
        }
      });
      if (!found) {
        this.selectedDistrict = null;
        this.showName = "暂无人员选择";
      }
    }
  }
};
</script>


<style scoped>

h2 {
  margin-bottom: 1rem;
}

ul {
  list-style-type: none;
  padding-left: 20px;
}

span {
  cursor: pointer;
  font-weight: 400;
  font-size: 0.28rem;
  color: #4E4E4E;
  line-height: 0px;
  text-align: left;
  font-style: normal;
  text-transform: none;
}

.pos-content {
  background: #fff;
}
.blackbox{
  width: 100%;
  height: 0.2rem;
  background: #F5F5F5;

}
.botton-box {
  margin-top: 0.2rem;
  background: #fff;
}

.group-section {
  padding: 0;
  background: #fff;

  .group-item {
    display: flex;
    height: 100%;
    font-size: 0.28rem;
    color: #646464;
    padding: 0.48rem 0.32rem 0.22rem 0.28rem;
    align-items: center;
    justify-content: space-between;


    .group-info {
      line-height: 0.38rem;
      font-size: 0.26rem;
      color: #B2B2B2;
      display: flex;
      align-items: center;
      word-break: break-all;
      text-align: right;
    }
  }
}

.province-item,
.city-item {
  margin-top: 0.34rem; /* 省份和城市之间的间隔 */

  //margin-bottom: 0.4rem; /* 省份和城市之间的间隔 */
}

.district-item {
  display: flex; /* 使用 flexbox 布局 */
  justify-content: space-between; /* 使内容分散对齐 */
  align-items: center; /* 垂直居中 */
  padding-top: 0.34rem; /* 上下内边距 */
}

.district-name,
.radio-label {
  font-weight: 400; /* 字体粗细 */
  font-size: 0.28rem; /* 字体大小,使用 rem 作为单位 */
  color: #4E4E4E; /* 字体颜色 */
  line-height: .32rem; /* 行高 */
  text-align: left; /* 文本对齐方式 */
  font-style: normal; /* 字体样式 */
  text-transform: none; /* 文本转换 */
}

.radio-label {
  display: flex; /* 使标签也成为 flex 容器 */
  align-items: center; /* 垂直居中 */
}

.radio-label input {
  width: 0.32rem; /* 强制宽度 */
  height: 0.32rem; /* 强制高度 */
  margin-right: 0.2rem; /* 单选框左边距 */
}

/* 实心三角符号样式 */
.triangle {
  display: inline-block;
  width: 0;
  height: 0;
  //margin-right: 0.1rem;
  border-left: 0.12rem solid transparent;
  border-right: 0.12rem solid transparent;
  border-top: 0.12rem solid #D1D1D1; /* 实心向上的三角形 */
  transition: transform 0.2s ease; /* 添加过渡效果 */
  transform: rotate(270deg); /* 旋转90度表示展开 */
}

.triangle.open {
  transform: rotate(0deg); /* 旋转90度表示展开 */
}

.link-icon {
  //margin-left: 8px; /* 图标左边距 */
  width: 0.24rem;
  height: 0.24rem;
  vertical-align: middle; /* 图标与文字对齐 */
}
.search{
  margin-bottom: 0.24rem;
}
>>> .van-search{
  margin-bottom: 0.24rem;

  padding: 0;
}
>>> .van-search__content{
  padding-right: 0.28rem;

  background-color: #FFFFFF; /* 修改背景颜色 */
  //border-radius: 18px; /* 添加边框圆角 */
  //border: 1px solid #F5F5F5;
}
>>> .van-field__control{
  color: #C6C6C6;
  font-size: 0.26rem;
  line-height: 0.38rem;
  //height: 0.7rem;
  margin-top: 0.2rem;
  border:0px;
}
>>> .van-field__left-icon .van-icon{
  margin-top: 0.1rem;
}
>>> .van-search .van-cell{
  border-radius: 0.7rem; /* 添加边框圆角 */
  border: 0.02rem solid #F5F5F5 ;
}
>>> .van-field__left-icon .van-icon, .van-field__right-icon .van-icon{
  padding-left: 0.28rem;
}
>>> .van-cell {
  line-height: 0.48rem;
}
.pb10{
  padding-bottom: 0.1rem;
}

.buttons {
  position: fixed;
  bottom: 0;
  left: 0;
  width: 100%;
  display: flex;
  align-items: center; /* 垂直居中对齐 */
  padding: 10px;
  background-color: #FFFFFF; /* 按钮区域的背景颜色 */
  //box-shadow: 0 -2px 4px rgba(0, 0, 0, 0.1); /* 添加阴影 */
  border-top: 0.04rem solid #F5F5F5; /* 替换阴影为颜色为 #F5F5F5 的线 */

}

.no-data {
  margin-right: auto; /* 将暂无数据推到最左侧 */
  color: #B5B5B5; /* 暂无数据字体颜色 */
  font-size: 0.32rem; /* 字体大小 */
}

.cancel-button, .confirm-button {
  width: 52px; /* 按钮宽度 */
  height: 38px; /* 按钮高度 */
  border: none;
  border-radius: 5px;
  cursor: pointer;
  font-size: 0.32rem; /* 字体大小 */
  margin-right: 0.24rem; /* 右侧边距 */
}

.cancel-button {
  background-color: transparent; /* 取消按钮的背景颜色 */
  color: #B5B5B5; /* 取消按钮的字体颜色 */
  border: 1px solid #D5D5D5; /* 取消按钮的边框颜色 */
}

.confirm-button {
  background-color: #3B70FF; /* 确定按钮的背景颜色 */
  color: #F5F5F5; /* 确定按钮的字体颜色 */
}
</style>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值