最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

vue用復選框實現組件且支持單選和多選操作方式

 更新時間:2024年04月26日 08:57:36   作者:球球和皮皮  
這篇文章主要介紹了vue用復選框實現組件且支持單選和多選操作方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教

前言

最近開發(fā)一個選擇電器的功能,電器分很多大類,而每一類又區(qū)分單選和多選。

我想只通過一個組件實現這個功能,于是使用了vant框架中的van-checkbox組件。

另外,每一種類的電器都支持可折疊,方便查看。

當然其他框架的復選框組件實現也類似。

一、實現效果

二、實現步驟

注意:后臺給我的數據是沒有分類的,但是每一條數據都有type屬性,前端根據這個參數判斷類型。

1、代碼實現

<template>
	<van-collapse class="layout-collapse" v-model="activeNames">
	   <van-checkbox-group class="layout-checkbox-group" :max="singleCheck(item.value)" v-model="ElectricalChecked[item.value]" v-for="item in ElectricalRequireList" :key="item.value" @change="changeUserCheckedElectrical(ElectricalChecked)">
	     <van-collapse-item :title="singleCheckTitle(item)" :name="item.value">
	       <van-checkbox
	         shape="square"
	         v-for="subItem in item.children"
	         :key="subItem.value"
	         :name="subItem.id"
	          @click="changeSingleCheck(item, subItem)"
	       >
	         <template>
	           <van-image fit="cover" :src="subItem.url" />
	           <span class="name">{{ subItem.name }}</span>
	         </template>
	       </van-checkbox>
	     </van-collapse-item>
	   </van-checkbox-group>
	 </van-collapse>
 <template>
data() {
    return {
      activeNames: [],
      ElectricalRequireList: [],
    }
},
computed: {
	singleCheck: () => {
        return (value) => ((value === 'shuicao' || value === 'cooking' || value === 'yanji') ? 1 : 0);
    },
},
methods: {
	getAllAppliances() {
		request("getAllAppliances").then((res) => {
		  if (res && res.code === 0) {
		  	// 獲取電器數據列表
		    const allArr = res.data
		    // 預定義電器種類
		    let typeList = []
		    // 預定義最終數據格式
		    let resultArray = []
		    allArr.map(item => {
		      // 定義處理后的數據格式:電器類型的key/value,和該類數據集合
		      const typeObj = {
		        name: item.typeName,
		        value: item.typeCode,
		        children: [],
		      };
		      // 遍歷數據,把所有電器類型篩選出來,對應類型的數據放進children
		      if (!typeList.includes(item.typeCode)) {
		        typeList.push(item.typeCode)
		        // 提前定義好v-modle中的數據類型,存放選中的電器集合
		        this.$set(this.ElectricalChecked, item.typeCode, [])
		        typeObj.children.push(item)
		        return resultArray.push(typeObj)
		      } else {
		        resultArray.forEach((subItem) => {
		          if (subItem.value === item.typeCode) {
		            subItem.children.push(item);
		          }
		        });
		        return;
		      }
		    });
		    // 定義初始展開的折疊區(qū)域,這里存入所有類型,默認全部展開
		    this.activeNames = this.activeNames.concat(typeList);
		    // 獲得最終的數據,雙向綁定到組件中
		    this.ElectricalRequireList = resultArray;
		  }
		});
	},
	changeSingleCheck (item, subItem) {
      // 判斷是否是單選項
      let singleFlag = 0
      if (item.value === 'shuicao' || item.value === 'cooking' || item.value === 'yanji') {
        singleFlag = 1
      }
      if (singleFlag === 1) {
        // 單選項中如果有其他項,取消其他項,改為當前項
        if (this.ElectricalChecked[item.value].length && !this.ElectricalChecked[item.value].includes(subItem.id)) {
          this.ElectricalChecked[item.value] = [subItem.id]
        }
      }
    }
}

2、代碼解析

只能說這里沒有一條代碼是多余的,而且都是經過踩坑之后,解決了所有bug之后的。

(1)、<van-checkbox-group>

<van-checkbox-group class="layout-checkbox-group" :max="singleCheck(item.value)" v-model="ElectricalChecked[item.value]" v-for="item in ElectricalRequireList" :key="item.value">
  • 這段代碼是這個組件的核心,把復選框組作為循環(huán);
  • 每個復選框組到底是單選,還是多選,這是根據max屬性來做判斷。
  • max使用計算屬性來判斷,這里需要給計算屬性傳參數,涉及到一個閉包的問題。
  • v-model綁定的值是一個對象,對象包含多個屬性,每個屬性對應每一個復選框組的值。注意:復選框組的值是一個數組,所以v-model是一個包含多個數組的對象。
  • ElectricalRequireList是所有數據的集合,是一個數組,每一項的數據都是{name: '煙機', value: 'yanji', children: []}。

(2)、<van-collapse-item>

這個沒啥可說的,就是加個折疊的功能,像我這種展示圖片的,高度會占用很大空間,有必要加個折疊。

(3)、<van-checkbox>

<van-checkbox shape="square"
	v-for="subItem in item.children"
	:key="subItem.value"
	:name="subItem.id"
	@click="changeSingleCheck(item, subItem)">

這地方說一下click事件的意義吧。

  • 如果不加click事件,用復選框實現單選功能會有一個問題:只有取消上一次選中的才能再選。
  • 這個函數不難理解:判斷是否為單選的組,把選中的值改為最新值就可以了。

三、增加【更多】功能

客戶增加需求,每個種類后,根據后臺返回的數據,判斷是否有更多的電器,如圖:

請?zhí)砑訄D片描述

1、代碼實現

<van-collapse class="layout-collapse" v-model="activeNames">
   <van-checkbox-group class="layout-checkbox-group" :max="singleCheck(item.value)" v-model="ElectricalChecked[item.value]" v-for="item in ElectricalRequireList" :key="item.value" @change="handleUserCheckedElectrical(ElectricalChecked)">
     <van-collapse-item :title="singleCheckTitle(item)" :name="item.value">
       <div class="van-collapse-item">
         <div class="van-collapse-item__title">
           {{singleCheckTitle(item)}}
           <div class="layout-button-more" v-if="item.showMore">
             <span class="layout-button-more-text" @click="handleMore(item)">更多 > </span>
           </div>
         </div>
         <div class="van-collapse-item__wrapper">
           <van-checkbox
             v-for="subItem in item.children"
             :key="subItem.id"
             :name="subItem.id"
             @click="changeSingleCheck(item, subItem, mutexValue)"
             :disabled="mutexValue[item.value].includes(subItem.id)"
           >
             <template>
               <van-image fit="cover" :src="subItem.url" />
               <span class="name">{{ subItem.name }}</span>
             </template>
           </van-checkbox>
         </div>
       </div>
     </van-collapse-item>
   </van-checkbox-group>
 </van-collapse>
 <!-- 更多需求 -->
 <van-popup v-model="moreRequirementShow" position="bottom" :lazy-render="false" round style="height: 80%">
   <div class="more-require-wrapper">
     <div class="more-require-title">
       <div class="more-require-title-line"></div>
     </div>
     <div class="more-require-content">
       <div class="more-require-panel">
         <van-collapse class="layout-collapse" v-model="activeMoreNames">
           <van-checkbox-group class="layout-checkbox-group" :max="moreSingleCheck(item.value)" v-model="moreElectricalChecked[item.value]" v-for="item in caseList" :key="item.value" @change="handleUserCheckedMore(moreElectricalChecked)">
             <van-collapse-item :title="moreSingleCheckTitle(item)" :name="item.value">
               <div class="van-collapse-item">
                 <div class="van-collapse-item__title">
                   {{singleCheckTitle(item)}}
                 </div>
                 <div class="van-collapse-item__wrapper">
                   <van-checkbox v-for="subItem in item.children" :key="subItem.id" :name="subItem.id"
                     :disabled="mutexValueMore[item.value].includes(subItem.id)">
                     <template>
                         <van-image fit="cover" :src="subItem.url"/>
                         <span class="name">{{subItem.name}}</span>
                     </template>
                   </van-checkbox>
                 </div>
               </div>
             </van-collapse-item>
           </van-checkbox-group>
         </van-collapse>
       </div>
     </div>
     <div class="more-require-button">
       <van-button round type="primary" @click="confirmMore"
         >確定</van-button
       >
     </div>
   </div>
 </van-popup>
data() {
    return {
      activeNames: [],
      ElectricalRequireList: [],
      ElectricalChecked: {},
      moreRequirementShow: false,
      mutexValue: {},
    }
},
computed: {
	singleCheck: () => {
        return (value) => ((value === 'shuicao' || value === 'cooking' || value === 'yanji') ? 1 : 0);
    },
    singleCheckTitle: () => {
        return (item) => ((item.value === 'shuicao' || item.value === 'cooking' || item.value === 'yanji') ? item.name + "(單選)" : item.name);
    },
},
watch: {
    ElectricalChecked: {
      handler (val) {
        // 處理互斥操作
        this.handleMutexValue()
      },
      deep: true
    },
}
methods: {
	getAllAppliances() {
      request("getAllAppliances").then((res) => {
        if (res && res.code === 0) {
          const allArr = res.data.filter(
            (col) => col.isMain === 0
          );
          this.ElectricalRequireBaseList = res.data
          // 獲取【更多】中的數據,用來判讀是否顯示每個類型下的【更多】按鈕
          let allMoreArr = res.data.filter(
            (col) => col.isMain === 1
          );
          this.moreElectricalRequireBaseList = allMoreArr
          let typeMoreList = allMoreArr.map(item => {
            return item.typeCode
          })

          let typeList = []
          let resultArray = []
          allArr.map(item => {
            let typeObj = {
              name: item.typeName,
              value: item.typeCode,
              showMore: false,
              children: [],
            };
            // 如果【更多】中有該類型的數據,則顯示【更多】按鈕
            if(typeMoreList.includes(typeObj.value)) {
              typeObj.showMore = true
            }
            if (!typeList.includes(item.typeCode)) {
              typeList.push(item.typeCode)
              this.$set(this.ElectricalChecked, item.typeCode, [])
              this.$set(this.moreElectricalChecked, item.typeCode, [])
              this.$set(this.mutexValue, item.typeCode, [])
              this.$set(this.mutexValueMore, item.typeCode, [])
              typeObj.children.push(item)
              return resultArray.push(typeObj)
            } else {
              resultArray.forEach((subItem) => {
                if (subItem.value === item.typeCode) {
                  subItem.children.push(item);
                }
              });
              return;
            }
          });
          this.activeNames = this.activeNames.concat(typeList);
          this.ElectricalRequireList = resultArray;
        }
      });
    },
	changeSingleCheck (item, subItem, mutexValue) {
      // 判斷是否是單選項
      let singleFlag = 0
      if (item.value === 'shuicao' || item.value === 'cooking' || item.value === 'yanji') {
        singleFlag = 1
      }
      if (singleFlag === 1 && !mutexValue[item.value].includes(subItem.id)) {
        // 單選項中如果有其他項,取消其他項,改為當前項
        if (this.ElectricalChecked[item.value].length && !this.ElectricalChecked[item.value].includes(subItem.id)) {
          this.ElectricalChecked[item.value] = [subItem.id]
        }
      }
    },
   // 監(jiān)聽外部選中的物品,同步【更多】中的選中狀態(tài)
   handleUserCheckedElectrical(ElectricalChecked) {
     this.changeUserCheckedElectrical(ElectricalChecked)
     Object.keys(ElectricalChecked).forEach((key) => {
       Object.keys(this.moreElectricalChecked).forEach((allKey) => {
         if (key == allKey) {
           // 如果里邊存在,外部不存在,則刪除內部的數據
           this.moreElectricalChecked[allKey].forEach(newValItem => {
             if(!ElectricalChecked[key].includes(newValItem)) {
               let index = this.moreElectricalChecked[allKey].indexOf(newValItem)
               this.moreElectricalChecked[allKey].splice(index, 1)
             }
           })
         }
       })
     })
   },
   handleMore() {
     this.moreRequirementShow = true;
   },
   // 處理互斥操作
   handleMutexValue() {
     // 處理選擇電器時的互斥項
     const allSelectId = []
     Object.keys(this.mutexValue).forEach(key => {
       this.mutexValue[key] = []
       this.mutexValueMore[key] = []
     })
     Object.keys(this.ElectricalChecked).forEach(key => {
       allSelectId.push(...this.ElectricalChecked[key])
     })
     Object.keys(this.moreElectricalChecked).forEach(key => {
       allSelectId.push(...this.moreElectricalChecked[key])
     })
     // 根據所有選中的電器,獲取互斥的所有電器
     allSelectId.forEach(item => {
       this.ElectricalRequireBaseList.forEach(subItem => {
         if(item == subItem.id && subItem.mutualExclusion) {
           const mutualExclusionList = subItem.mutualExclusion.split(",").map(item => { return Number(item)})
           Object.keys(this.mutexValue).forEach(key => {
             this.mutexValue[key].push(...mutualExclusionList)
             this.mutexValueMore[key].push(...mutualExclusionList)
             this.mutexValue[subItem.typeCode] = []
           })
         }
       })
     })
   },
   confirmMore() {
     this.moreRequirementShow = false;
   },
   // 獲取【更多】頁面中顯示的數據
   getCaseList() {
     request("getAllAppliances").then((res) => {
       if (res && res.code === 0) {
         let allMoreArr = res.data.filter((col) => col.isMain === 1);
         this.moreElectricalRequireBaseList = allMoreArr
         let typeMoreList = []
         let resultMoreArray = []

         allMoreArr.map(item => {
           const typeObj = {
             name: item.typeName,
             value: item.typeCode,
             children: []
           }
           if (!typeMoreList.includes(item.typeCode)) {
             typeMoreList.push(item.typeCode)
             typeObj.children.push(item)
             return resultMoreArray.push(typeObj)
           } else {
              resultMoreArray.forEach(subItem => {
               if (subItem.value === item.typeCode) {
                 subItem.children.push(item)
               }
              })
             return
           }
         })
         this.activeMoreNames = this.activeMoreNames.concat(typeMoreList)
         this.caseList = resultMoreArray
         // 判斷模板案例中是否有【更多】中的電器
         this.handleSetMoreCheck()
       }
     });
   },
   // 獲取案例詳細信息
   getCaseById(caseId) {
     request("getCaseById", { id: caseId }).then((res) => {
       if (res && res.code === 0) {
         this.caseLabelAppliances = res.data.label.appliances.data;
         // 調用遍歷數據的方法,傳遞三個參數:當前案例中的需求,全部需求,需要選中的需求
         this.handleCheck(
           this.caseLabelAppliances,
           this.ElectricalRequireBaseList,
           this.ElectricalChecked
         );
         // 從vuex判斷有沒有用戶之前勾選的數據
         Object.keys(this.userCheckedElectrical).forEach(key => {
           this.ElectricalChecked[key] = this.userCheckedElectrical[key];
         })
         // 判斷模板案例中是否有【更多】中的電器
         this.handleSetMoreCheck()
       }
     });
   },
   handleCheck(part, all, checked) {
     // 遍歷電器列表
     part.forEach((item) => {
       all.forEach((allItem) => {
         if (allItem.typeCode == item.code) {
           // 具體類別下的已選電器
           const caseElecs = item.data;
           caseElecs.forEach((subItem) => {
             if (subItem.id == allItem.id) {
               checked[allItem.typeCode].push(subItem.id);
             }
           });
         }
       });
     });
   },
   // 判斷模板案例中是否有【更多】中的電器
   handleSetMoreCheck() {
     this.handleCheck(
       this.caseLabelAppliances,
       this.moreElectricalRequireBaseList,
       this.moreElectricalChecked
     );
     // 從vuex判斷有沒有用戶之前勾選的數據
     Object.keys(this.userCheckedMore).forEach(key => {
       this.moreElectricalChecked[key] = this.userCheckedMore[key];
     })
     // 初始狀態(tài)判斷【更多】中是否有選中的數據,有則展示到外部
     this.setMoreSelectToAll()
   },
   // 初始狀態(tài)判斷【更多】中是否有選中的數據,有則展示到外部
   setMoreSelectToAll() {
     this.oldMoreElectricalChecked = JSON.parse(JSON.stringify(this.moreElectricalChecked))
     Object.keys(this.moreElectricalChecked).forEach((key) => {
       Object.keys(this.ElectricalChecked).forEach((allKey) => {
         if (key == allKey && this.moreElectricalChecked[key].length) {
           let selectKey = []
           this.caseList.forEach(item => {
             if (item.value == key) {
               selectKey = item.children.filter(itemValue => this.moreElectricalChecked[key].includes(itemValue.id) )
             }
           })
           this.ElectricalRequireList.forEach(item => {
             if (item.value == key) {
               item.children = item.children.concat(selectKey)
               const map = new Map()
               item.children = item.children.filter(itemKey => !map.has(itemKey.id) && map.set(itemKey.id, 1))
             }
           })
           this.ElectricalChecked[allKey] = Object.assign(this.ElectricalChecked[allKey], this.moreElectricalChecked[key])
         }
       })
     })
   },
}
mounted() {
   this.$nextTick(()=>{
     this.getCaseById(curCaseId);
   })
},
created() {
  this.getAllAppliances();
  this.getCaseList();
},
filters: {
  ellipsis(value) {
    if (!value) return "";
    if (value.length > 8) {
      return value.slice(0, 8) + "...";
    }
    return value;
  },
},

2、代碼解析

新增的代碼中多了很多邏輯:

(1)、初始進入頁面,會調用兩個接口:一個是獲取主頁面的電器,另一個是獲取【更多】中的電器。

(2)、進入頁面后,會自動勾選一些項,這是根據接口返回的數據勾選的。

this.$nextTick(()=>{
  this.getCaseById(curCaseId);
})

這里要在頁面渲染完畢后,再勾選。

(3)、在【更多】里勾選的電器,要同步更新到主頁面。這需要把【更多】里選中的電器的數據增加到主頁面數據上,還要把勾選的值添加到主頁面已選項中。

// 監(jiān)聽【更多】中選中的物品,同步到外部展示
handleUserCheckedMore (moreElectricalChecked) {
  this.changeUserCheckedMore(moreElectricalChecked)
  Object.keys(moreElectricalChecked).forEach((key) => {
    Object.keys(this.oldMoreElectricalChecked).forEach((allKey) => {
      if (key == allKey) {
        // 如果newVal存在,oldVal不存在,則是新增的電器
        moreElectricalChecked[key].forEach(newValItem => {
          if(!this.oldMoreElectricalChecked[key].includes(newValItem)) {
            let selectKey = []
            this.caseList.forEach(item => {
              if (item.value == key) {
                selectKey = item.children.filter(itemValue => itemValue.id == newValItem )
              }
            })
            this.ElectricalRequireList.forEach(item => {
              if (item.value == key) {
                // item.children = item.children ? item.children : []
                item.children = item.children.concat(selectKey)
              }
            })
            this.ElectricalChecked[allKey].push(newValItem)
          }
        })
        // 如果newVal不存在,oldVal存在,則是減少的電器
        this.oldMoreElectricalChecked[key].forEach(oldValItem => {
          if(!moreElectricalChecked[key].includes(oldValItem)) {
            this.ElectricalRequireList.forEach(item => {
              if (item.value == key) {
                item.children.forEach((ele, index) => {
                  if (ele.id == oldValItem) {
                    item.children.splice(index, 1)
                  }
                })
              }
            })
          }
        })
      }
    })
  })
  this.oldMoreElectricalChecked = JSON.parse(JSON.stringify(this.moreElectricalChecked))
},

(4)、當取消選中的電器時,如果取消的是當時從【更多】選過來的電器,則把該電器從主頁面刪除,同時刪除【更多】里的選中狀態(tài)

// 監(jiān)聽外部選中的物品,同步【更多】中的選中狀態(tài)
handleUserCheckedElectrical(ElectricalChecked) {
  this.changeUserCheckedElectrical(ElectricalChecked)
  Object.keys(ElectricalChecked).forEach((key) => {
    Object.keys(this.moreElectricalChecked).forEach((allKey) => {
      if (key == allKey) {
        // 如果里邊存在,外部不存在,則刪除內部的數據
        this.moreElectricalChecked[allKey].forEach(newValItem => {
          if(!ElectricalChecked[key].includes(newValItem)) {
            let index = this.moreElectricalChecked[allKey].indexOf(newValItem)
            this.moreElectricalChecked[allKey].splice(index, 1)
          }
        })
      }
    })
  })
}

總結

以上為個人經驗,希望能給大家一個參考,也希望大家多多支持腳本之家。

相關文章

  • vue實現實時搜索顯示功能

    vue實現實時搜索顯示功能

    這篇文章主要為大家詳細介紹了vue實現實時搜索顯示功能,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-04-04
  • vue計算屬性無法監(jiān)聽到數組內部變化的解決方案

    vue計算屬性無法監(jiān)聽到數組內部變化的解決方案

    今天小編就為大家分享一篇vue計算屬性無法監(jiān)聽到數組內部變化的解決方案,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2019-11-11
  • Vue實現移除數組中特定元素的方法小結

    Vue實現移除數組中特定元素的方法小結

    這篇文章主要介紹了Vue如何優(yōu)雅地移除數組中的特定元素,文中介紹了單個去除和批量去除的操作方法,并通過代碼示例講解的非常詳細,具有一定的參考價值,需要的朋友可以參考下
    2024-03-03
  • Vue3異步組件Suspense的使用方法詳解

    Vue3異步組件Suspense的使用方法詳解

    這篇文章主要介紹了Vue3異步組件Suspense的使用方法詳解,需要的朋友可以參考下
    2023-01-01
  • Vue3格式化Volar報錯的原因分析與解決

    Vue3格式化Volar報錯的原因分析與解決

    Volar 與vetur相同,volar是一個針對vue的vscode插件,下面這篇文章主要給大家介紹了關于Vue3格式化Volar報錯的原因分析與解決方法,文中通過圖文介紹的非常詳細,需要的朋友可以參考下
    2022-06-06
  • 詳細分析vue響應式原理

    詳細分析vue響應式原理

    這篇文章主要介紹了vue響應式原理的的相關資料,文中講解非常細致,代碼幫助大家更好的理解和學習,感興趣的朋友可以了解下
    2020-06-06
  • vue如何修改data中數據問題

    vue如何修改data中數據問題

    這篇文章主要介紹了vue如何修改data中數據問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-09-09
  • Vue3項目中優(yōu)雅實現微信授權登錄的方法

    Vue3項目中優(yōu)雅實現微信授權登錄的方法

    用戶在微信端中訪問第三方網頁,可以通過微信網頁授權機制獲取用戶的基本信息,進而實現所需要的業(yè)務邏輯,這篇文章主要給大家介紹了關于Vue3項目中優(yōu)雅實現微信授權登錄的相關資料,需要的朋友可以參考下
    2021-09-09
  • Vue3使用md-editor-v3的實例解讀markdown文本

    Vue3使用md-editor-v3的實例解讀markdown文本

    本文介紹了如何在Vue3項目中使用md-editor-v3實現Markdown編輯器,包括基礎實現、工具欄自定義、預覽功能以及擴展功能
    2026-01-01
  • Vue計算屬性中reduce方法實現遍歷方式

    Vue計算屬性中reduce方法實現遍歷方式

    這篇文章主要介紹了Vue計算屬性中reduce方法實現遍歷方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-03-03

最新評論

宁强县| 达尔| 陵川县| 南安市| 嵊泗县| 老河口市| 大丰市| 颍上县| 金寨县| 灌南县| 蓬莱市| 闵行区| 阿巴嘎旗| 汤原县| 保靖县| 临清市| 平遥县| 随州市| 万全县| 夹江县| 南汇区| 萝北县| 郸城县| 武陟县| 沙湾县| 澄城县| 泽州县| 乌鲁木齐市| 岳阳市| 金昌市| 驻马店市| 昔阳县| 东乡| 濮阳县| 建德市| 宣化县| 满城县| 广丰县| 乐清市| 霸州市| 青铜峡市|