意思是:避免修改prop值,因?yàn)楦附M件一旦re-render,這個(gè)值就會(huì)被覆蓋;
另外,盡管在這個(gè)按鈕上實(shí)現(xiàn)了顯示狀態(tài)的切換,但是點(diǎn)擊其他區(qū)域的時(shí)候,并不會(huì)隱藏它,原因是:子組件prop值的變化并沒有影響到父組件,因此showCancel的值一直保持初始值沒有變化,而只有在這個(gè)值被更新時(shí)才會(huì)觸發(fā)子組件中相關(guān)值的更新。
——好吧,那么老老實(shí)實(shí)的用一個(gè)計(jì)算屬性接收showCancel值,這樣實(shí)現(xiàn)點(diǎn)擊子組件控制系統(tǒng)菜單的狀態(tài)切換;
獲得了計(jì)算屬性ifShowCancel,組件相應(yīng)的變成了v-show="ifShowCancel",我試圖在綁定事件里通過this.ifShowCancel=!this.ifShowCancel切換菜單狀態(tài),報(bào)錯(cuò),得到報(bào)錯(cuò)信息:Computed property "ifShowCancel" was assigned to but it has no setter;
明白了,要以直接賦值的形式改變計(jì)算屬性ifShowCancel的值,需要一個(gè)setter函數(shù),但是setter函數(shù)中無(wú)法修改prop值,因此在getter中也就無(wú)法通過return this.showCancel來(lái)更新這個(gè)計(jì)算屬性,所以這個(gè)方法貌似也行不通;
到此為止,好像路都成了堵死狀態(tài):prop值不能改->要用計(jì)算屬性;計(jì)算屬性不能改->需要setter;而寫入了getter、setter,計(jì)算屬性的值依賴于prop值->prop值不能改。——一個(gè)堪稱完美的閉環(huán)誕生了!
走投無(wú)路之際我想起了$emit和$on這一對(duì)。
3. 父子互相通信
前邊的prop實(shí)現(xiàn)了從父到子的單向通信,而通過$emit和$on,就可以實(shí)現(xiàn)從子組件到父組件的通信:這不能直接修改父組件的屬性,但卻可以觸發(fā)父組件的指定綁定事件,并將一個(gè)值傳入父組件。
在這一步我摒棄了點(diǎn)擊按鈕時(shí)的去操作子組件內(nèi)屬性的想法,既然計(jì)算屬性ifShowCancel依賴于prop值,那么就在點(diǎn)擊按鈕時(shí),通過$emit觸發(fā)父組件的事件,并將需要修改的屬性值傳入父組件,于是:
/*父組件自定義元素綁定switch-show事件*/ <t-header :showCancel=showCancel @switch-show="switchShow"></t-header> // 父組件js methods: { //會(huì)被子組件$emit觸發(fā)的方法 switchShow(val) { this.showCancel = val; } } // 子組件js methods: { //按鈕上的綁定click事件 switchCancelBoard() { this.$emit("switch-show", this.ifShowCancel); } }
這樣處理流程就變成了:點(diǎn)擊按鈕->作為計(jì)算屬性的ifShowCancel值傳入父組件并觸發(fā)父組件事件,對(duì)showCancel賦值->父組件屬性更新->觸發(fā)子組件prop更新->觸發(fā)重新compute,更新ifShowCancel值->v-show起作用。
另外在點(diǎn)擊其他區(qū)域時(shí),通過父組件綁定的click事件,就可以重置showCancel值,進(jìn)而隱藏掉出現(xiàn)的系統(tǒng)菜單。
下邊放出這個(gè)功能的完整代碼。
4. 完整代碼
/*父組件*/ <template> <p id="app" @click="hideCancel"> <t-header :showCancel=showCancel @switch-show="switchShow"></t-header> <!-- <router-view/> --> </p> </template> <script> import THeader from "./components/t-header/t-header"; export default { name: "app", components: { THeader }, data() { return { showCancel: false }; }, methods: { hideCancel() { this.showCancel = false; }, switchShow(val) { this.showCancel = val; } } }; </script> <style scope lang="stylus"> </style> /*子組件*/ <template> <p class="header-wrapper"> <p class="title-wrapper"> <p class="logo"></p> <h2 class="title">Title</h2> </p> <p class="info-wrapper"> <span class="username">你好,管理員!</span> <span class="cancel" @click.stop="switchCancelBoard"> <p class="cancel-p" v-show="ifShowCancel"> <ul> <li @click.stop="doSomething" title="用戶設(shè)置">設(shè)置 </li> <li @click.stop="doSomething" title="退出登錄">退出 </li> </ul> </p> </span> </p> </p> </template> <script> export default { props: { showCancel: { type: Boolean } }, methods: { doSomething() {}, switchCancelBoard() { // this.ifShowCancel = !this.showCancel; this.$emit("switch-show", !this.ifShowCancel); } }, computed: { ifShowCancel() { return this.showCancel; } } }; </script> <style lang="stylus" rel="stylesheet/stylus" scoped> .header-wrapper background: #1C60D1 color: #fff width: 100% height: 50px line-height: 50px position: fixed top: 0px left: 0px font-size: 0 .title-wrapper display: block position: relative float: left height: 50px .logo display: inline-block background-image: url('./logo.png') background-size: 30px 30px background-repeat: no-repeat width: 30px height: 30px margin-top: 10px .title display: inline-block font-size: 16px height: 50px line-height: 50px margin: 0px auto 0px 16px font-weight: normal vertical-align: top .info-wrapper display: block position: relative float: right height: 50px width: 160px font-size: 0 .username display: inline-block height: 50px line-height: 50px font-size: 14px vertical-align: top .cancel display: inline-block vertical-align: middle background-image: url('./cancel.png') background-size: 32px 32px cursor: pointer background-repeat: no-repeat width: 32px height: 32px .cancel-p position: absolute display: block width: 60px height: 80px background: #fff z-index: 50 top: 40px right: 16px font-size: 14px color: #646464 box-shadow: 1px 1px 8px rgba(0, 0, 0, 0.4) ul padding-left: 0px margin: 0px li width: 100% height: 40px line-height: 40px text-align: center list-style-type: none &:hover background-color: #eaeaea </style>
相信看了本文案例你已經(jīng)掌握了方法,更多精彩請(qǐng)關(guān)注Gxl網(wǎng)其它相關(guān)文章!
推薦閱讀:
JS做出哈希表功能
vue地區(qū)選擇組件使用步驟詳解
聲明:本網(wǎng)頁(yè)內(nèi)容旨在傳播知識(shí),若有侵權(quán)等問題請(qǐng)及時(shí)與本網(wǎng)聯(lián)系,我們將在第一時(shí)間刪除處理。TEL:177 7030 7066 E-MAIL:11247931@qq.com