使用v-model實(shí)現(xiàn)select下拉框組件

一、組件使用場(chǎng)景及需求分析

  • 表單多個(gè)固定單值的情況乌助,我們不用再去input框輸入值,直接在固定的值里面去選擇

  • 選擇以后父組件綁定的值對(duì)應(yīng)改變陌知,使得不需要發(fā)送表單前再進(jìn)行賦值

  • 選擇前后他托,列表都是不可見(jiàn)的

二、開(kāi)始我們的codeing

  • 首先我們需要的是一個(gè)有所有單值選項(xiàng)的list展示

  • 然后是一個(gè)展示當(dāng)前選擇的文字框

像這樣的:

01.png

這一步我們只需要父組件傳遞單值代碼仆葡,然后當(dāng)前選中的一個(gè)值赏参,沒(méi)有的話就默認(rèn)為空。

vue:

<div class="fd-select-box">
   <p v-text="scoped.selected&&scoped.selected.name?scoped.selected.name:'請(qǐng)選擇'"></p>
   <span :class="fd-arrow icon iconfont">&#xe6a4;</span>
   <ul class="fd-select-list">
     <li v-for="(item,index) in list"
     :key="index+'select'"
     :class="{'active':scoped.selected&&item.code===scoped.selected.code}">
     {{item.name}}</li>
   </ul>
 </div>

JS:

 props: {
   list: {
   type: Array,
   required: true,
   },
   selected: Object,
 },
 data() {
   return {
     scoped: {
     // 當(dāng)前選中的
     selected: this.selected,
     },
   };
 },

CSS:

.fd-select-box {
   position: relative;
   width: 200px;
   padding-right: 40px;
   padding-left: 10px;
   height: 36px;
   margin: 30px auto;
   line-height: 36px;
   border: 1px solid #41b883;
   border-radius: 4px;
   color: #000;
   font-size: 14px;
   text-align: left;
   cursor: pointer;
   box-sizing: border-box;
?
   .fd-arrow {
     position: absolute;
     top: 0;
     right: 0;
     font-size: 30px;
     transition: all 200ms;
?
       &.fd-down {
         transform: rotate(180deg);
         }
     }
?
 .fd-select-list {
   position: absolute;
   width: 100%;
   max-height: 200px;
   overflow: auto;
   list-style: none;
   top: 36px;
   left: 0;
   background: #fff;
   box-shadow: 0 0 5px rgba(0,0,0,0.2);
   z-index: 9;
?
     li {
       padding-left: 12px;
       line-height: 30px;
       cursor: pointer;
?
     &:hover {
       background: rgba(65, 191, 138, 0.2);
     }
?
     &.active {
       background: rgba(65, 191, 138, 0.9);
       color: #fff;
     }
 }
 }
 }

這樣浙芙,我們已經(jīng)把外層框架搭建好了登刺。

接下來(lái),解決子組件改變嗡呼,父組件對(duì)應(yīng)的值發(fā)生改變纸俭。

一般情況我們會(huì)想到子組件把當(dāng)前選中的值通過(guò)this.$emit傳給父組件,然后父組件再在對(duì)應(yīng)方法里面給對(duì)應(yīng)的值賦值南窗。今天我們用另外一種方法來(lái)解決這個(gè)問(wèn)題揍很,那就是v-model,相信我,用了它你會(huì)愛(ài)上它万伤。

好了窒悔,我們看看官方文檔怎么說(shuō)的:

一個(gè)組件上的 v-model 默認(rèn)會(huì)利用名為 value 的 prop 和名為 input 的事件,但是像單選框敌买、復(fù)選框等類型的輸入控件可能會(huì)將 value attribute 用于不同的目的简珠。model 選項(xiàng)可以用來(lái)避免這樣的沖突:

 model: {
   prop: 'checked',
   event: 'change'
 },
 props: {
   checked: Boolean
 },
 template: `
   <input
     type="checkbox"
     v-bind:checked="checked"
     v-on:change="$emit('change', $event.target.checked)"
   >
 `
})

https://cn.vuejs.org/v2/guide/components-custom-events.html

我的理解就是提供了v-model;在自定義組件上model里的prop里的字段的值會(huì)直接賦給props里面對(duì)應(yīng)字段虹钮,像之前我們給checked傳值是在父組件上通過(guò):checked='false'這樣一種形式×郑現(xiàn)在我們可以使用v-model='false'。來(lái)看具體在select框里面的表現(xiàn)吧芙粱。

export default {
   name: 'fdSselect',
   model: {
   prop: 'selected',
   event: 'changeValue',
 },
 props: {
   list: {
     type: Array,
     required: true,
   },
   selected: Object,
 },
 data() {
   return {
     scoped: {
     // 是否展示下面的列表
     showFlag: false,
     // 當(dāng)前選中的
     selected: this.selected,
     },
     };
 },
 methods: {
   // 值改變后傳給父組件祭玉,因?yàn)榻M件定義了model,所以父組件相當(dāng)于執(zhí)行了綁定的model值=emit出去的值
   changeValue(item) {
     this.scoped.selected = item;
     this.scoped.showFlag = false;
     this.$emit('changeValue', this.scoped.selected);
     },
   },
};

父組件調(diào)用:

 <fd-select :list="selectList" v-model="selected"></fd-select>

上面的event是我們要emit出去的事件名春畔。這一步相當(dāng)于在父組件執(zhí)行了父組件的this.selected等于子組件的this.scoped.selected脱货;所以其實(shí)你用組件的時(shí)候v-model="value"其實(shí)就是:value="value" @change="(val) => {value = val}"

現(xiàn)在看看我們實(shí)現(xiàn)的效果:

02.gif

前兩個(gè)需求已經(jīng)實(shí)現(xiàn)了律姨,最后一個(gè)需求是在交互上的優(yōu)化振峻。

首先他要一開(kāi)始的時(shí)候不展示,我們給一個(gè)控制下拉框顯隱的變量择份。showFlag默認(rèn)值為false扣孟;點(diǎn)擊輸入框時(shí)展開(kāi)下拉列表。然后選中選項(xiàng)后隱藏下拉列表缓淹。

注意我們的頁(yè)面結(jié)構(gòu)哈打,下拉列表是輸入框的子元素塔逃,所以點(diǎn)擊下拉列表元素的時(shí)候會(huì)涉及到事件冒泡,這個(gè)時(shí)候我們使用.stop修飾符來(lái)組織時(shí)間冒泡導(dǎo)致下拉列表一直不能隱藏料仗。

vue:

 <div class="fd-select-box" @click="changeShow">
   <p v-text="scoped.selected&&scoped.selected.name?scoped.selected.name:'請(qǐng)選擇'"></p>
   <span :class="['fd-arrow icon iconfont',{'fd-down':scoped.showFlag}]">&#xe6a4;</span>
   <ul class="fd-select-list" v-show="scoped.showFlag">
     <li v-for="(item,index) in list"
         :key="index+'select'"
         @click.stop="changeValue(item)"
          :class="{'active':scoped.selected&&item.code===scoped.selected.code}">
           {{item.name}}</li>
   </ul>
</div>

JS:

 // 值改變后傳給父組件湾盗,因?yàn)榻M件定義了model,所以父組件相當(dāng)于執(zhí)行了綁定的model值=emit出去的值
 changeValue(item) {
   this.scoped.selected = item;
   this.scoped.showFlag = false;
   this.$emit('changeValue', this.scoped.selected);
 },
 // 改變下拉選項(xiàng)的顯隱
 changeShow() {
   this.scoped.showFlag = !this.scoped.showFlag;
 },

繼續(xù)優(yōu)化立轧,我們現(xiàn)在實(shí)現(xiàn)了組件列表的顯隱格粪,但是只有操作當(dāng)前組件時(shí)可以控制。那么我們點(diǎn)擊其他地方的時(shí)候氛改,其實(shí)也是希望組件列表可以隱藏起來(lái)的帐萎。

實(shí)現(xiàn)這個(gè)的思路:綁定一個(gè)點(diǎn)擊事件在頁(yè)面上,只要點(diǎn)擊的元素不是當(dāng)前組件胜卤,那么我們就可以隱藏當(dāng)前組件的列表疆导。這里我用到了自定義指令,具體實(shí)現(xiàn)如下:

clickOutside: {
   bind(el, binding) {
   function clickHandler(e) {
   // 這里判斷點(diǎn)擊的元素是否是本身葛躏,是本身澈段,則返回
   if (el.contains(e.target)) {
     return false;
   }
   // 判斷指令中是否綁定了函數(shù)
   if (binding.expression) {
   // 如果綁定了函數(shù) 則調(diào)用那個(gè)函數(shù),此處binding.value就是handleClose方法
     binding.value(e);
   }
   return true;
 }
 // 給當(dāng)前元素綁定個(gè)私有變量舰攒,方便在unbind中可以解除事件監(jiān)聽(tīng)
   el.vueClickOutside = clickHandler;
   document.addEventListener('click', clickHandler);
 },
 unbind(el) {
   // 解除事件監(jiān)聽(tīng)
   document.removeEventListener('click', el.vueClickOutside);
   delete el.vueClickOutside;
   },
 },

最后實(shí)現(xiàn)效果如圖:

03.gif

后期待優(yōu)化:實(shí)現(xiàn)可搜索的下拉框-->實(shí)現(xiàn)可以遠(yuǎn)程搜索的下拉框

以上為個(gè)人編寫败富,希望能對(duì)大家的項(xiàng)目有所幫助,如有不當(dāng)以及有更好的方法歡迎交流摩窃。

項(xiàng)目地址: https://github.com/jasminezx/select.git

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末兽叮,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子猾愿,更是在濱河造成了極大的恐慌鹦聪,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,366評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件匪蟀,死亡現(xiàn)場(chǎng)離奇詭異椎麦,居然都是意外死亡宰僧,警方通過(guò)查閱死者的電腦和手機(jī)材彪,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,521評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)琴儿,“玉大人段化,你說(shuō)我怎么就攤上這事≡斐桑” “怎么了显熏?”我有些...
    開(kāi)封第一講書人閱讀 165,689評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)晒屎。 經(jīng)常有香客問(wèn)我喘蟆,道長(zhǎng)缓升,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書人閱讀 58,925評(píng)論 1 295
  • 正文 為了忘掉前任蕴轨,我火速辦了婚禮港谊,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘橙弱。我一直安慰自己歧寺,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,942評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布棘脐。 她就那樣靜靜地躺著斜筐,像睡著了一般。 火紅的嫁衣襯著肌膚如雪蛀缝。 梳的紋絲不亂的頭發(fā)上顷链,一...
    開(kāi)封第一講書人閱讀 51,727評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音屈梁,去河邊找鬼蕴潦。 笑死,一個(gè)胖子當(dāng)著我的面吹牛俘闯,可吹牛的內(nèi)容都是我干的潭苞。 我是一名探鬼主播,決...
    沈念sama閱讀 40,447評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼真朗,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼此疹!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起遮婶,我...
    開(kāi)封第一講書人閱讀 39,349評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤蝗碎,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后旗扑,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體蹦骑,經(jīng)...
    沈念sama閱讀 45,820評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,990評(píng)論 3 337
  • 正文 我和宋清朗相戀三年臀防,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了眠菇。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,127評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡袱衷,死狀恐怖捎废,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情致燥,我是刑警寧澤登疗,帶...
    沈念sama閱讀 35,812評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響辐益,放射性物質(zhì)發(fā)生泄漏断傲。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,471評(píng)論 3 331
  • 文/蒙蒙 一智政、第九天 我趴在偏房一處隱蔽的房頂上張望艳悔。 院中可真熱鬧,春花似錦女仰、人聲如沸猜年。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 32,017評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)乔外。三九已至,卻和暖如春一罩,著一層夾襖步出監(jiān)牢的瞬間杨幼,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 33,142評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工聂渊, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留差购,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,388評(píng)論 3 373
  • 正文 我出身青樓汉嗽,卻偏偏與公主長(zhǎng)得像欲逃,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子饼暑,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,066評(píng)論 2 355