<span id="mktg5"></span>

<i id="mktg5"><meter id="mktg5"></meter></i>

        <label id="mktg5"><meter id="mktg5"></meter></label>
        最新文章專題視頻專題問答1問答10問答100問答1000問答2000關鍵字專題1關鍵字專題50關鍵字專題500關鍵字專題1500TAG最新視頻文章推薦1 推薦3 推薦5 推薦7 推薦9 推薦11 推薦13 推薦15 推薦17 推薦19 推薦21 推薦23 推薦25 推薦27 推薦29 推薦31 推薦33 推薦35 推薦37視頻文章20視頻文章30視頻文章40視頻文章50視頻文章60 視頻文章70視頻文章80視頻文章90視頻文章100視頻文章120視頻文章140 視頻2關鍵字專題關鍵字專題tag2tag3文章專題文章專題2文章索引1文章索引2文章索引3文章索引4文章索引5123456789101112131415文章專題3
        問答文章1 問答文章501 問答文章1001 問答文章1501 問答文章2001 問答文章2501 問答文章3001 問答文章3501 問答文章4001 問答文章4501 問答文章5001 問答文章5501 問答文章6001 問答文章6501 問答文章7001 問答文章7501 問答文章8001 問答文章8501 問答文章9001 問答文章9501
        當前位置: 首頁 - 科技 - 知識百科 - 正文

        Vue編寫多地區選擇組件

        來源:懂視網 責編:小采 時間:2020-11-27 22:32:07
        文檔

        Vue編寫多地區選擇組件

        Vue編寫多地區選擇組件:看看效果圖: 效果圖 功能點: 支持不限城市,不限地區(這個東西的實現..真心死磕了挺久) – 左右兩邊數據的同步 地區一次性多選,若是選擇了所有地區會自動轉為不限地區 數據遷移箭頭的判斷..選中數據才會有對應的按鈕可以點擊 已選位置的數據同步響應調用的
        推薦度:
        導讀Vue編寫多地區選擇組件:看看效果圖: 效果圖 功能點: 支持不限城市,不限地區(這個東西的實現..真心死磕了挺久) – 左右兩邊數據的同步 地區一次性多選,若是選擇了所有地區會自動轉為不限地區 數據遷移箭頭的判斷..選中數據才會有對應的按鈕可以點擊 已選位置的數據同步響應調用的

        看看效果圖:

        效果圖

        這里寫圖片描述

        功能點:

      1. 支持不限城市,不限地區(這個東西的實現..真心死磕了挺久) – 左右兩邊數據的同步
      2. 地區一次性多選,若是選擇了所有地區會自動轉為不限地區
      3. 數據遷移箭頭的判斷..選中數據才會有對應的按鈕可以點擊
      4. 已選位置的數據同步響應調用的地方,當然也可以外部傳入…(新增傳出,編輯依賴傳入再組合)
      5. 箭頭是iconfont,支持外部傳入,默認是我這邊的cdn的啦….
      6. !!!這是一個獨立的組件,css預處理是用的scss;

        寫的過程遇到的問題:

        因為這個功能會多次需要切換省份城市這些,所以我一次性拉取所有數據存儲到localstorage,不然請求接口次數太多了

        一開始的不限城市和不限地區我想并入JSON(重組JSON),但是發現雖然能降低處理麻煩,但是數據更亂了…非常不好維護,也有其他組件調用這個JSON的地方(比如其他組件有個地址的三級聯動也是依賴這個JSON)

                 *還有一個就是要考慮兩邊有不限制這東東的時候,要剔除不能存在的數據,比如你不限制城市,那所有該省份的城市都要干掉,不限制地區也是類似

        寫左右兩邊數據的對比是最惡心的,為什么這么說呢?

              *左邊三級聯動的,每個子項都有自己的id和name, 而選擇的是組合成的(看GIF圖),中間是中劃線隔開,這對于推入和推出就帶來一堆遍歷和比較

              *我們這邊的后端大佬說不限制的id均為0(城市或者地區),所以這個需要自行組合,最后就是動態圖那格式的ID就是后臺接受的,,多地區再拼接成字符串….'3-13-2,2-44-3,4-0-0'這種提交到后臺..

        聯動JSON數據格式

        regionName: 項的名稱
        regionId: 項的ID
        child: 是否包含有子項

        本來想寫個props映射下regionName,regionId,child; 但是感覺作用不大,就沒寫了,(一般公司的地區JSON格式定下來了之后變動的可能性太低)

        你能學到什么?

        1: 數組的比對,數組的遍歷,數組的組合及響應判斷
        2: vue一些內置指令的使用
        3: 組件功能細節的考慮,不限制地區,全部這些按鈕在什么情況下能點擊
        4: 清空數據之后各個狀態的恢復和重置等等

        代碼

        manyAreaSelect.vue

        <template>
         <div class="manyAreaSelect">
         <div class="item">
         <div class="item-title">
         <span> 選擇省</span>
         </div>
         <div class="item-content">
         <ul>
         <li v-for="(item,index) in chinaArea" :class="item.selected?'active':''" :key="index" @click="getCityList(item)">{{item.regionName}}</li>
         </ul>
         </div>
         <div class="item-footer"></div>
         </div>
         <div class="item">
         <div class="item-title">
         <span>選擇市</span>
         </div>
         <div class="item-content">
         <ul v-show="cityList.length===0">
         <li>
         <<請選擇省份</li>
         </ul>
         <ul v-show="!notLimitButton.notLimitCity &&cityList.length!==0">
         <li v-for="(item,index) in cityList" :class="item.selected ? 'active':''" :key="index" @click="getDistricList(item)">{{item.regionName}}</li>
         </ul>
         </div>
         <div class="item-footer">
         <button class="button" :class="notLimitButton.notLimitCity?'success':''" @click="cityNotLitmit({regionName:'不限',regionId:'0'})" size="mini" :disabled="!selectItem.province.regionName">不限城市</button>
         </div>
         </div>
         <div class="item">
         <div class="item-title">
         <span>選擇地區</span>
         </div>
         <div class="item-content">
         <ul v-show="districList.length===0">
         <li>
         <<請選擇城市</li>
         </ul>
         <ul v-show="!notLimitButton.notLimitCity && !notLimitButton.notLimitDistrict && districList.length!==0">
         <li v-for="(item,index) in districList" :class="item.selected?'active':''" :key="index" @click="getAreaCombineID(item)">{{item.regionName}}</li>
         </ul>
         </div>
         <div class="item-footer">
         <button class="button" :class="notLimitButton.notLimitDistrict ?'success':''" @click="districNotLitmit({regionName:'不限',regionId:'0'})" :disabled="!selectItem.city.regionName ||!selectItem.province.regionName || notLimitButton.notLimitCity ">不限地區</button>
         </div>
         </div>
         <div class="trangle">
         <div class="trangle-wrap">
         <div class="left">
         <button class="button" @click="transferToRight" :disabled="direactionStatusToRight">
         <i :class="this.iconDirection.right"></i>
         </button>
         </div>
         <div class="right">
         <button class="button" @click="transferToLeft" :disabled="direactionStatusToLeft">
         <i :class="this.iconDirection.left"></i>
         </button>
         </div>
         </div>
         </div>
         <div class=" item ">
         <div class="item-title ">
         <span>已選位置</span>
         </div>
         <div class="item-content ">
         <ul class="selectedContent">
         <li v-for="(item,index) in selectedList" :class="item.selected?'active':''" :key="index" @click="selectedAreaSingle(item)">{{item.regionName}}</li>
         </ul>
         </div>
         <div class="item-footer">
         <button class="button" @click="selectedAllArea()" :disabled="rightDataList.length=== 0" :class="selectedAllButtonStatus?'success':''">{{selectedAllButtonStatus?'反選':'全部'}}</button>
         </div>
         </div>
         </div>
        </template>
        
        <script>
         import _ from 'lodash';
         export default {
         name: 'manyAreaSelect',
         data: function () {
         return {
         chinaArea: JSON.parse(window.localStorage.getItem('chinaArea')) || [], // 這是地區聯動的JSON
         notLimitButton: {
         notLimitCity: false, // 城市不限
         notLimitDistrict: false, // 地區不限
         },
         selectedAllButtonStatus: false, // 已選位置列表全部按鈕的狀態
         selectItem: {
         province: {},
         city: {},
         distric: {}
         },
         cityList: [], // 城市列表
         districList: [], // 區域列表
         rightDataList: [], // 選中項目組合成的渲染列表
         rightData: [], // 選中需要移除的
         leftData: [], // 左邊選中的轉發
         }
         },
         props: {
         selectedData: {
         type: [String, Object, Array]
         },
         iconDirection: {
         type: Object,
         default: function () { // 箭頭圖標
         return {
         left: 'fzicon fz-ad-you',
         right: 'fzicon fz-ad-right'
         }
         }
         }
         },
         computed: {
         selectedList () { // 已選中列表
         if (this.selectedData && this.selectedData !== '') {
         this.rightDataList = this.selectedData;
         return this.rightDataList;
         } else {
         return this.rightDataList;
         }
        
         },
         direactionStatusToRight () { // 控制可以轉移的箭頭狀態
         if (this.notLimitButton.notLimitCity || this.notLimitButton.notLimitDistrict) {
         if (this.notLimitButton.notLimitCity) {
         this.removeAllSelected(this.cityList);
         this.removeAllSelected(this.districList);
         return false;
         } else {
         if (this.notLimitButton.notLimitDistrict) {
         this.removeAllSelected(this.districList);
         return false;
         }
         }
         return false;
         } else {
         if (this.selectItem.distric.regionName) {
         return false;
         }
         return true;
         }
         },
         direactionStatusToLeft () { // 控制可以轉移的箭頭狀態
         if (this.rightData.length === 0) {
         return true
         } else {
         return false
         }
         }
         },
         methods: {
         mapSelect (list, value, type) { // 高亮選中
         if (type) {
         return list.map(pitem => {
         if (pitem.regionId === value.regionId) {
         if (value.selected && value.selected === true) {
         this.$delete(pitem, 'selected');
         } else {
         this.$set(pitem, 'selected', true)
         }
         }
         })
         } else {
         return list.map(pitem => {
         if (pitem.regionId === value.regionId) {
         if (value.selected && value.selected === true) {
         this.$delete(pitem, 'selected');
         } else {
         this.$set(pitem, 'selected', true)
         }
         } else {
         this.$delete(pitem, 'selected');
         }
         })
         }
         },
         resetToDefault () {
         this.leftData = []; // 清空需要轉移的數組
         this.notLimitButton = { // 重置按鈕狀態
         notLimitCity: false, // 城市不限
         notLimitDistrict: false, // 地區不限
         };
         this.selectItem.city = {};
         this.selectItem.distric = {}
         this.removeAllSelected(this.cityList); // 清除選中狀態
         this.removeAllSelected(this.districList); // 清除選中狀態
         this.cityList = [];
         this.districList = [];
         },
         getCityList (item) {
         this.resetToDefault();
         if (item) {
         this.cityList = item.child; // 獲取城市列表
         this.selectItem.province = item; // 保存省份對象
         this.mapSelect(this.chinaArea, item); // 高亮選擇,單選
         }
         },
         getDistricList (item) {
         this.leftData = []; // 清空需要轉移的數組
         this.notLimitButton.notLimitDistrict = false; // 重置按鈕狀態
         this.removeAllSelected(this.districList); // 清除選中狀態
         this.selectItem.distric = {};
         this.districList = [];
         if (item) {
         this.districList = item.child; // 獲取區域列表
         this.selectItem.city = item; // 保存省份對象
         this.mapSelect(this.cityList, item); // 高亮選擇,單選
         }
        
         },
         getAreaCombineID (item) { // 獲取組合ID
         if (item) {
         this.selectItem.distric = item;
         this.mapSelect(this.districList, item, 'manySelect'); // 區域高亮選擇,多選
        
         this.leftData.push({
         regionName: this.selectItem.province.regionName + '-' + this.selectItem.city.regionName + '-' + item.regionName,
         regionId: this.selectItem.province.regionId + '-' + this.selectItem.city.regionId + '-' + item.regionId
         })
         this.leftData = _.uniqBy(this.leftData, 'regionId');
         if (this.leftData.length === this.districList.length) {
         this.leftData = [];
         this.notLimitButton.notLimitDistrict = true; // 轉為不限制地區
         this.leftData.push({
         regionName: this.selectItem.province.regionName + '-' + this.selectItem.city.regionName + '-不限',
         regionId: this.selectItem.province.regionId + '-' + this.selectItem.city.regionId + '-0'
         })
         }
         }
        
         },
         cityNotLitmit (item) { // 城市不限
         this.leftData = []; // 請空數組
         this.notLimitButton.notLimitCity = !this.notLimitButton.notLimitCity; // 不限按鈕狀態
         this.leftData.push({
         regionName: this.selectItem.province.regionName + '-不限-不限',
         regionId: this.selectItem.province.regionId + '-0-0'
         })
         },
         districNotLitmit (item) { // 區域不限
         this.leftData = []; // 請空數組
         this.notLimitButton.notLimitDistrict = !this.notLimitButton.notLimitDistrict; // 不限按鈕狀態
         this.leftData.push({
         regionName: this.selectItem.province.regionName + '-' + this.selectItem.city.regionName + '-不限',
         regionId: this.selectItem.province.regionId + '-' + this.selectItem.city.regionId + '-0'
         })
         },
         transferToRight () { // 選中推入到已選中列表區域
         if (this.leftData && this.leftData.length !== 0) {
         if (this.leftData.length === 1) { // 長度只有1,那就只有不限城市或者地區了
         let limitId = this.leftData[0].regionId.split('-'); // 比對比對,切割成數組
         this.rightDataList.map(item => {
         let id = item.regionId.split('-');
         if (limitId[0] === id[0]) {
         if (limitId[1] === '0') { // 不限城市
         this.rightDataList = this.rightDataList.filter(ritem => {
         let rid = ritem.regionId.split('-');
         if (limitId[0] !== rid[0]) {
         return ritem;
         }
         })
         } else {
         if (limitId[2] === '0') { // 不限地區
         this.rightDataList = this.rightDataList.filter(ritem => {
         let rid = ritem.regionId.split('-');
         if ((limitId[0] === rid[0] && limitId[1] === rid[1])) {
         if (ritem[2] === '0') {
         return ritem;
         }
         } else {
         if (limitId[0] !== rid[0] || limitId[1] !== rid[1]) {
         return ritem;
         }
         }
         })
         } else {
         this.rightDataList = this.rightDataList.filter(ritem => {
         let rid = ritem.regionId.split('-');
         if (limitId[0] === rid[0]) {
         if (limitId[1] === rid[1]) {
         if (!(rid[2] === '0')) {
         return ritem;
         }
         } else {
         if (!(rid[1] === '0')) {
         return ritem
         }
         }
         } else {
         return ritem
         }
         })
         }
         }
        
         }
         })
         } else {
         let limitId = this.leftData[0].regionId.split('-'); // 比對比對,切割成數組
         this.rightDataList = this.rightDataList.filter(ritem => {
         let rid = ritem.regionId.split('-');
         if (limitId[0] === rid[0]) {
         if (limitId[1] === rid[1]) {
         if (!(rid[2] === '0')) {
         return ritem;
         }
         } else {
         if (!(rid[1] === '0')) {
         return ritem
         }
         }
         } else {
         return ritem
         }
         })
         }
         this.leftData.map(item => {
         this.rightDataList.push(item);
         })
         this.rightDataList = _.uniqBy(this.rightDataList, 'regionId');
         this.resetToDefault();
         }
        
        
         },
         selectedAreaSingle (item) { // 已選擇區域單個選擇
         if (item) {
         this.rightData = [];
         this.mapSelect(this.rightDataList, item, 'manySelect'); // 區域高亮選擇,多選
         this.rightDataList.map(item => {
         if (item.selected) {
         this.rightData.push(item)
         }
         })
         }
        
         },
         selectedAllArea () { // 已選中區域全選反選
         if (this.selectedAllButtonStatus) {
         this.removeAllSelected(this.rightDataList);
         this.rightData = [];
         } else {
         this.rightDataList.map(item => this.$set(item, 'selected', true));
         this.rightData = this.rightDataList;
         }
         this.selectedAllButtonStatus = !this.selectedAllButtonStatus;
         },
         transferToLeft () { // 從已選中列表區域退回待轉發區域
         if (this.rightData && this.rightData.length !== 0) {
         this.rightDataList = this.rightDataList.filter(item => {
         if (!item.selected) {
         return item;
         }
         })
         this.rightData = [];
         }
         },
         removeAllSelected (list) { // 清空選中狀態
         list.map(item => this.$delete(item, 'selected'));
         }
         },
         watch: {
         'rightDataList' (newValue, oldValue) { // 選擇列表的值變動響應外部值的變動
         if (newValue.length !== this.rightData.length) {
         this.selectedAllButtonStatus = false;
         } else {
         if (newValue.length === 0) {
         this.selectedAllButtonStatus = false;
         } else {
         this.selectedAllButtonStatus = true;
         }
         }
         this.$emit('update:selectedData', newValue);
         }
         }
         }
        </script>
        
        <style scoped lang="scss">
         ul {
         padding: 0;
         margin: 0;
         max-height: 100%;
         overflow-y: auto;
         li {
         cursor: pointer;
         text-align: center;
         padding: 5px;
         &.active,
         &:hover {
         background: #e4e8f1;
         color: #48576a;
         }
         }
         }
        
         .manyAreaSelect {
         position: relative;
         z-index: 2005;
         .item {
         border: 1px solid #d1dbe5;
         background: #fff;
         box-shadow: 0 2px 4px rgba(0, 0, 0, .12), 0 0 6px rgba(0, 0, 0, .04);
         display: inline-block;
         vertical-align: middle;
         min-width: 180px;
         box-sizing: border-box;
         position: relative;
         height: 100%;
         min-height: 260px;
         }
         .item-title {
         height: 36px;
         line-height: 36px;
         background: #fbfdff;
         margin: 0;
         border-bottom: 1px solid #d1dbe5;
         box-sizing: border-box;
         color: #1f2d3d;
         text-align: center;
         }
         .trangle {
         background: transparent;
         display: inline-block;
         vertical-align: middle;
         width: 40px;
         box-sizing: border-box;
         height: 100%;
         position: relative;
         .trangle-wrap {
         position: absolute;
         top: 50%;
         left: 50%;
         transform: translate(-50%, -50%);
         }
         .left,
         .right {
         margin: 10px 5px;
         }
         ;
         }
        
         .item-content {
         font-size: 13px;
         height: 190px;
         padding: 8px 2px;
         }
         .item-footer {
         padding: 5px 0;
         height: 40px;
         text-align: center;
         }
         }
        
         .selectedContent {
         li {
         text-align: left;
         padding-left: 25px;
         }
         }
        
        
        
         .button {
         display: inline-block;
         line-height: 1;
         white-space: nowrap;
         cursor: pointer;
         background: #fff;
         border: 1px solid #c4c4c4;
         color: #1f2d3d;
         margin: 0;
         border-radius: 4px;
         padding: 4px;
         font-size: 12px;
         border-radius: 4px;
         -webkit-appearance: button;
         outline: none;
         &.success {
         background: #42d885;
         border-color: #42d885;
         color: #fff;
         }
        
         &:disabled {
         color: #bfcbd9;
         cursor: not-allowed;
         background-image: none;
         background-color: #eef1f6;
         border-color: #d1dbe5;
         }
         }
        </style>
        

        用法

        <!--selectedData就是響應的數據.sync是2.3回歸的語法糖-->
        <!--可以綁定iconDirection傳入箭頭的iconfont,Object-->
        
        <many-area-select :selectedData.sync="manyAreaValue"></many-area-select>
        

        總結

        這個組件的出爐,折騰了很久..

        寫的過程推倒了三版(三天三個版本),都是思路沒想對和理清..寫著寫著就寫不下去了…

        這個組件目前的功能是滿足我這邊的需求的,若是有更好的實現方式可以留言。

        聲明:本網頁內容旨在傳播知識,若有侵權等問題請及時與本網聯系,我們將在第一時間刪除處理。TEL:177 7030 7066 E-MAIL:11247931@qq.com

        文檔

        Vue編寫多地區選擇組件

        Vue編寫多地區選擇組件:看看效果圖: 效果圖 功能點: 支持不限城市,不限地區(這個東西的實現..真心死磕了挺久) – 左右兩邊數據的同步 地區一次性多選,若是選擇了所有地區會自動轉為不限地區 數據遷移箭頭的判斷..選中數據才會有對應的按鈕可以點擊 已選位置的數據同步響應調用的
        推薦度:
        標簽: VUE 地區 選擇
        • 熱門焦點

        最新推薦

        猜你喜歡

        熱門推薦

        專題
        Top
        主站蜘蛛池模板: 毛片a级毛片免费播放100| 91在线视频免费观看| 国产麻豆视频免费观看| 久久亚洲一区二区| 在线播放免费人成毛片乱码| 久久精品亚洲男人的天堂| 韩日电影在线播放免费版| 国产精品亚洲精品日韩已满| 大地资源中文在线观看免费版| 亚洲日韩欧洲乱码AV夜夜摸| 国产婷婷成人久久Av免费高清| 国内精品99亚洲免费高清| 久久成人免费大片| 亚洲美女视频网址| 中文字幕影片免费在线观看 | 亚洲国产成人五月综合网 | 亚洲欧洲日产国码无码网站| 最近更新免费中文字幕大全| 亚洲AV午夜成人片| av无码免费一区二区三区| 亚洲深深色噜噜狠狠网站| 四虎影视永久免费观看地址 | 国产在线观看免费视频软件 | 一区二区三区免费视频网站| 久久久久亚洲AV无码专区桃色| 少妇性饥渴无码A区免费| 亚洲日本乱码一区二区在线二产线| 无码人妻一区二区三区免费| 亚洲综合欧美色五月俺也去| 免费一区二区三区四区五区 | 波多野结衣中文字幕免费视频 | 亚洲成a人片77777群色| 欧美大尺寸SUV免费| 农村寡妇一级毛片免费看视频| 亚洲精品午夜无码电影网| 日本h在线精品免费观看| 欧洲亚洲国产精华液| 国产AV无码专区亚洲AV男同| 亚洲福利精品一区二区三区 | 亚洲精品国产专区91在线| 成年性午夜免费视频网站不卡|