vue3+无聊的三级联动---头条投放

4 篇文章 0 订阅

在这里插入图片描述
需求是选了省份就显示省份,下面的耳机城市没有选择那么省份也不显示就显示已选城市,跟头条的投放一样的逻辑

<template>
  <div class="cascader-input" v-if="input">
    <el-input
      placeholder="请输入内容"
      v-model="searchInfo"
      class="input-with-select search-input"
    >
      <template #append>
        <el-button type="primary" @click="handleClickSearch">搜索</el-button>
      </template>
    </el-input>
  </div>
  <div class="cascader-box flex city-box">
    <div class="select-cascader city">
      <div class="cascader-title" style="padding-left: 10px;">
        <el-switch v-model="allParent" active-color="#4371FF" inactive-color="#F5F6FA" @change="handleClickAllparent"></el-switch> {{parentList[0].parentType}}
      </div>
      <div class="select-cascader-box">
        <div v-for="(item,i) in parentList" :key="i" class="flex city-icon">
          <div><el-switch v-model="item.checked" active-color="#4371FF" inactive-color="#F5F6FA" @change="handleChangeParent($event, item.id)"></el-switch> {{item.name}}</div>
          <span class="el-icon-arrow-right city-icon" v-if="item.children.length" @click="handleClickIcon(i)"></span>
        </div>
      </div>
    </div>
    <div class="select-cascader city" v-if="index > -1 && parentList[index].children.length">
      <div class="cascader-title" style="padding-left: 10px;">
        <el-switch v-model="allChild" active-color="#4371FF" inactive-color="#F5F6FA" @change="handleClickAllChild"></el-switch> {{parentList[index].children[0].childType}}
      </div>
      <div class="select-cascader-box">
        <div v-for="(item,i) in parentList[index].children" :key="i">
          <el-switch v-model="item.checked" active-color="#4371FF" inactive-color="#F5F6FA" @change="handleClickChild($event, parentList[index])"></el-switch> {{item.name}}
        </div>
      </div>
    </div>
    <div class="selectd-cascader">
      <div class="cascader-title cascader-title-flex"><span>已选</span><span style="color:#4371FF;cursor: pointer;" @click="deleteAll">清空全部</span></div>
      <div class="selectd-cascader-box">
        <div v-for="(item,i) in selectList" :key="i" class="selectd-cascader-item">
          <div>{{item.name}}</div>
          <div class="selectd-close" @click="deleteItem(item.id)">X</div>
        </div>
      </div>
    </div>
  </div>
</template>
<script>
import { defineComponent, onBeforeMount, reactive, ref, computed } from 'vue'

export default defineComponent({
  setup(props) {
    let list = reactive(props.list)
    let selectList = reactive([])
    let searchInfo = ref('')
    let index = ref(-1)
    let allParent = computed(() => parentList.findIndex(item => item.checked === false) === -1)
    let allChild = computed(() => parentList[index.value].children.findIndex(item => item.checked === false) === -1)

    let parentList = reactive([])

	// 这里是根据传过来的list做了一个初始化,结构不同的话就改这里
    function init () {
      list.forEach(item => {
        if (item.parentid == 1) {
          parentList.push({
            ...item,
            children: []
          })
        } else {
          parentList.forEach(child => {
            if (child.id === item.parentid) {
              child.children.push(item)
            }
          })
        }
      })
      parentList.splice()
    }
    // 全选省份
    function handleClickAllparent (val) {
      if (!val) {
        index.value = -1
      } 
      changeEleChecked(parentList, val)
      setSelectList()
    }

    function handleClickAllChild (val) {
      parentList[index.value].children.forEach(item => item.checked = val)
      parentList[index.value].checked = val
      setSelectList()
    }

    function handleChangeParent (val, id) {
      // 判断是否是选中状态
      let i;   // 定义当前选中的省份索引
      parentList.forEach((item,index) => {
        if (item.id == id) {
          i = index
          // 改变该省份下所有城市的选中状态
          item.children.forEach(child => {
            child.checked = val
          })
        }
      })
      console.log('1',i);
      index.value = i
      setSelectList()
    }

    function handleClickSearch () {
      parentList.forEach((item,i) => {
        if (item.name === searchInfo.value) {
          item.checked = true
          item.children.forEach(child => {
            child.checked = true
          })
        } else {
          item.children.forEach(child => {
            if (child.name === searchInfo.value) {
              child.checked = true
              index.value = i
            }
          })
        }
      })

      setSelectList()
    }

    function handleClickChild (val, parent) {
      // 点击选择省份时是选中状态,判断选中后的城市和总城市是否相同
      let arr = parent.children.filter(child => child.checked)
      if (arr.length == parent.children.length) {
        // 相同要把全选城市和省份的选中状态改变
        parent.checked = true
      } else {
        parent.checked = false
      }
      setSelectList()
    }

    function handleClickIcon (i) {
      index.value = i
    }

    function deleteItem (id) {
      for (let i = 0;i < parentList.length;i++) {
        let item = parentList[i]
        if (item.id === id) {
          item.checked = false
          item.children.forEach(child => {
            child.checked = false
          })
          index.value = i
        } else {
          item.children.forEach(child => {
            if (child.id === id) {
              child.checked = false
              item.checked = false
              index.value = i
            }
          })
        }
      }
      setSelectList()
    }

    function deleteAll () {
      changeEleChecked(parentList, false)
      setSelectList()
    }

    // 数组元素全部需要改变时
    function changeEleChecked (list, parentStatus, childStatus) {
      let arg = arguments.length
      list.forEach(item => {
        item.checked = parentStatus
        if (item.children) {
          item.children.forEach(child => {
            child.checked = arg > 2 ? childStatus : parentStatus
          })
        }
      })
    }

    // 列表选中了逻辑
    function setSelectList () {
      parentList.forEach(item => {
        // 父元素被选中,已选列表添加父元素,子元素删除
        if (item.checked) {
          // 判断是否存在,如果不存在就push
          if (isHaveEle(item, 'id') == -1) {
            selectList.push(item)
          } 
          // 父元素被选中删掉子元素
          item.children.length ? item.children.forEach(child => {
            if (isHaveEle(child, 'id') > -1) {
              selectList.splice(isHaveEle(child, 'id'), 1)
            }
          }) : ''
        } else if (!item.checked) {
          // 如果没有被选中父元素,删掉父元素
          if (isHaveEle(item, 'id') > -1) {
            selectList.splice(isHaveEle(item, 'id'), 1)
          }
          item.children.length ? item.children.forEach(child => {
            // 如果子元素被选中,判断列表中是否存在,不存在就push
            if (child.checked) {
              if (isHaveEle(child, 'id') == -1) {
                selectList.push(child)
              } 
            } else {
              // 子元素没有被选中,判断是否列表中存在,存在就删掉
              if (isHaveEle(child, 'id') > -1) {
                selectList.splice(isHaveEle(child, 'id'), 1)
              }
            }
          }) : ''
        }
      })
    }

    // 判断数组中是否已经存在某元素
    function isHaveEle (ele, attr = 'id') {
      return selectList.findIndex(item => item[attr] === ele[attr])
    }

    onBeforeMount(() => {
      init()
    })

    return {
      index,
      searchInfo,
      list,
      selectList,
      parentList,
      allChild,
      allParent,
      handleClickAllparent,
      handleClickAllChild,
      handleChangeParent,
      init,
      handleClickSearch,
      handleClickChild,
      handleClickIcon,
      deleteItem,
      deleteAll,
      setSelectList,
      changeEleChecked
    }
  },
  props: {
    list: Object,
    input: {
      type: Boolean,
      default: true
    }
  }
})
</script>

<style scoped lang="scss">
.cascader-input ::v-deep{
  margin-left: 96px;
  margin-top: 20px;
  .el-input__inner {
    width: 288px;
  }
  .el-input {
    width: 288px;
  }

  .el-input-group__append, .el-input-group__prepend {
    width: 76px;
    height: 28px;
    background: #4371FF;
    border-radius: 0px 2px 2px 0px;
    color: #fff;
    border: none;
  }

  .el-button {
    width: 76px;
  }
}

.cascader-box {
  margin-top: 12px;
  margin-left: 96px;
  .cascader-title {
    background-color: #F5F6FA;
    height: 26px;
    line-height: 26px;
    border-bottom: 1px solid #D3D5E0;
  }
  .select-cascader{
    width: 352px;
    height: 240px;
    border-radius: 3px;
    border: 1px solid #D3D5E0;
  }
  .city  {
    width: 183px;
    &:nth-child(2) {
      border-left: 0;
    }
  }
  .selectd-cascader {
    height: 240px;
    width: 176px;
    background: #F5F6FA;
    padding: 0 10px;
    border-radius: 3px;
    overflow: hidden;
    padding-bottom: 8px;
    margin-left: 12px;
  }
  .cascader-title-flex {
    display: flex;
    justify-content: space-between;
    margin-bottom: 8px;
    font-size: 12px;
  }

  .select-cascader-box {
    padding: 0 10px;
    height: 213px;
    overflow: auto;
  }

  .selectd-cascader-box {
    height: 213px;
    overflow: auto;
  }

  .selectd-cascader-item {
    width: 156px;
    height: 24px;
    background: #DCE5FF;
    border-radius: 3px;
    color: #4371FF;
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 0 8px;
    margin-bottom: 8px;
  }
  .selectd-close {
    cursor: pointer;
  }

  .city-icon {
    justify-content: space-between;
  }
}

.city-box {
  margin-top: 8px;
}
</style>
// 这是父组件传的list
list: [{
  name: '北京',
  id: 1,
  checked: false,
  parentid: 1,
  parentType: '省份'
},{
  name: '山西',
  id: 2,
  checked: false,
  parentid: 1,
  parentType: '省份'
},{
  name: '太原',
  parentid: 2,
  id: 3,
  checked: false,
  childType: '城市'
},{
  name: '大兴',
  id: 4,
  parentid: 2,
  checked: false,
  childType: '城市'
},{
  name: '内蒙',
  id: 5,
  checked: false,
  parentid: 1,
  parentType: '省份'
},{
  name: '呼市',
  parentid: 5,
  id: 6,
  checked: false,
  childType: '城市'
},{
  name: '赤峰',
  id: 7,
  parentid: 5,
  checked: false,
  childType: '城市'
}],

一开始写的比较乱后来改良了一下,所以可能也有冗余的地方,可以指出来共同进步

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值