vue: 從一個下拉框元件理解vue中的父子通訊

深谷逸風發表於2019-03-04

如果說vue元件化開發中第一步應該瞭解的是什麼的話,那無疑是父子元件之間是如何實現通訊的(說白了就是父子元件中資料是如何傳遞的),只有理解了這一步,才能更好的開發元件

這裡先提出兩個關鍵詞: propsemit

寫這個元件之前,先看看效果圖:

下拉框元件圖

元件開發分析:

既然是元件:

  • 首先元件內部資料內容肯定是可變的(如上圖中的"按時間排序"之類的),這必須由父元件傳入(即父元件如何將資料傳個父元件);
  • 在選擇了內容之後,如何將資料傳出來(即子元件如何將資料傳給父元件)

先寫結構:

父元件

<!--下拉框父元件-->
<template>
    <div id="app">
        <oSelect @changeOption="onChangeOption" :selectData="selectData"></oSelect>
        <!--
        selectData: 傳入父元件需要傳入的資料;格式:childDataName="parentDataName";
        onChangeOption: 子元件觸發的事件名,通過觸發一個事件從而來接收子元件的傳過來的資料
        格式:@childEventName="parentEventName"
        注:可寫多個
        -->
    </div>
</template>
<script>
import oSelect from "@/components/select.vue"; //引入元件
export default{
    name: 'App',
    data(){
        return {
            selectData: {
                defaultIndex: 0, //預設選中的是第幾個
                selectStatus: false, // 通過selectStatus來控制下拉框的顯示/隱藏
                selectOptions: [ // 下拉框中的資料 name這樣的引數,看專案是否有需求,可自行修改
                    {
                        name: 'time',
                        context: '按時間排序'
                    },
                    {
                        name: 'view',
                        context: '按瀏覽量排序'
                    },
                    {
                        name: 'like',
                        context: '按點贊數排序'
                    },
                    {
                        name: 'reply',
                        context: '按回複數排序'
                    },
                    {
                        name: 'reward',
                        context: '按打賞數排序'
                    }
                ]
            }
        }
    },
    methods:{
        onChangeOption(index){
        //子元件通過一個事件來觸發onChangeOption方法,從而傳遞一系列引數,這裡的index就是傳過來的
            this.selectData.defaultIndex = index;
        //觸發過後,動態改變了需要值    
        }
    },
    components: {
        oSelect,
        //註冊元件
    }
}
</script>

複製程式碼

子元件

<template>
<!-- 下拉框元件html結構(子元件) -->
<div class="select-box" @click="changeStatus">
<!-- changeStatus事件: 點選實現下拉框的顯示和隱藏  -->
<h3 class="select-title"
	:name="selectData.selectOptions[selectData.defaultIndex].name"
	:class="{'select-title-active': selectData.selectStatus}"> 
	<!--屬性name class的動態繫結-->
	{{ selectData.selectOptions[selectData.defaultIndex].context }} 
	<!--這裡主要繫結選擇的資料-->
</h3>
<transition name="slide-down">
<!--transition 實現下拉選單顯示隱藏時的動畫-->
<ul class="select-options" v-show="selectData.selectStatus">
    <li class="select-option-item" 
    	v-for="(item,index) in selectData.selectOptions"
    	@click="EmitchangeOption(index)"
    	:class="{'select-option-active':selectData.defaultIndex===index}">
    	<!--
    	    v-for:迴圈資料渲染下拉選單
    	    EmitchangeOption:點選下拉選單事件
    	    class:動態繫結被選中的資料
    	-->
    	{{ selectData.selectOptions[index].context }}
    	
    </li>
    <div class="arrow-top"></div>
</ul>	
</transition>	
</div>    
</template>
<script>
export default{
    name: 'oSelect', //建議大家都寫上這個,有利於我們知道這個元件叫什麼名字
    //通過props來接收父元件傳過來的資料
    props:{
    	selectData: {
    		type: Object //規定傳過來的資料為物件,否則就會報錯(其實這樣寫就是規避錯誤和良好的習慣)
    	}
    },
    methods:{
    	EmitchangeOption(index){
    		this.$emit('changeOption',index);
    	    // 通過點選事件觸發EmitchangeOption函式,傳入當前點選下拉選單中的索引值index
    	    // 下拉框通過emit方法觸發父元件中changeOption函式,動態傳給父元件需要的資料,這裡為索引值
    	},
    	changeStatus(){
    	    // 通過changeStatus事件動態改變selectStatus的值,從而控制下拉框的顯示隱藏
    		this.selectData.selectStatus = !this.selectData.selectStatus
    	}
    }
}
</script>
複製程式碼

總結

  • 從以上的示例可以看出來,父元件傳入資料,需要在父元件中線繫結一個屬性,掛載需要傳入的資料;
  • 子元件接收父元件的資料通過 props 方法來接收;
  • 子元件傳遞資料需要使用 emit 方法來繫結父元件中事先設定好的方法,從而動態傳遞操作後需要的資料

最終效果如下:

動態效果圖

附上元件中的css,僅供參考:

.select-box{
	position: relative;
	max-width: 250px;
	line-height: 35px;
	margin: 50px auto;
}
.select-title{
	position: relative;
	padding: 0 30px 0 10px;
	border: 1px solid #d8dce5;
	border-radius: 5px;
	transition-duration: 300ms;
	cursor: pointer;
}
.select-title:after{
	content: '';
	position: absolute;
	height: 0;
	width: 0;
	border-top: 6px solid #d8dce5;
	border-left: 6px solid transparent;
	border-right: 6px solid transparent;
	right: 9px;
	top: 0;
	bottom: 0;
	margin: auto;
	transition-duration: 300ms;
	transition-timing-function: ease-in-out;
}
.select-title-active{
	border-color: #409eff;
}
.select-title-active:after{
	transform: rotate(-180deg);
	border-top-color: #409eff;
}
.select-options{
	position: absolute;
	padding:10px 0;
	top: 45px;
	border:1px solid #d8dce5;
	width: 100%;
	border-radius: 5px;
}
.select-option-item{
	padding:0 10px;
	cursor: pointer;
	transition-duration: 300ms;
}
.select-option-item:hover,.select-option-active{
	background: #f1f1f1;
	color: #409eff;
}

<!--箭頭css-->
.arrow-top{
	position: absolute;
	height: 0;
	width: 0;
	top: -7px;
	border-bottom: 7px solid #d8dce5;
	border-left: 7px solid transparent;
	border-right: 7px solid transparent;
	left: 0;
	right: 0;
	margin: auto;
	z-index: 99;
}
.arrow-top:after{
	content: '';
	position: absolute;
	display: block;
	height: 0;
	width: 0;
	border-bottom: 6px solid #fff;
	border-left: 6px solid transparent;
	border-right: 6px solid transparent;
	left: -6px;
	top: 1px;
	z-index: 99;
}

<!--下拉框顯示隱藏動畫-->
.slide-down-enter-active,.slide-down-leave{
	transition: all .3s ease-in-out;
	transform-origin:0 top;
	transform: scaleY(1);
}
.slide-down-enter{
	transform: scaleY(0);
}
.slide-down-leave-active{
	transition: all .3s ease-in-out;
	transform-origin:0 top;
	transform: scaleY(0);
}
複製程式碼

好了,關於本文就結束了,感謝大家的閱讀,如有不正之處,還望指正,非常感謝,想要了解更多的前端方面相關的知識, 請搜尋關注微信公眾號【大前端js,瞭解更多前端的硬技術

原創不易,轉載請註明出處,銘感五內

相關文章