国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 編程 > JavaScript > 正文

Vue在頁面右上角實現可懸浮/隱藏的系統菜單

2019-11-19 13:55:24
字體:
來源:轉載
供稿:網友

這是個大多數網站很常見的功能,點擊頁面右上角頭像顯示一個懸浮菜單,點擊頁面其他位置或再次點擊頭像則菜單隱藏。

作為一個jQuery前端攻城獅實現這個功能可以說是很easy了,但是對只剛粗看了一遍vue文檔的菜鳥來說,坑還是要親自踩過才算圓滿。

知識點

  • 組件及組件間通信
  • 計算屬性

正文

1. 父組件

這里暫時只涉及系統菜單這一個功能,因此路由暫未涉及。

基本思路是:通過props將showCancel這個Boolean值傳遞到子組件,對父子組件分別綁定事件,來控制這個系統菜單的顯示狀態。其中在父組件的綁定click事件中,將傳入子組件的showCancel值重置。

這里就涉及第一個小知識點――子組件調用:

首先寫好等待被子組件渲染的自定義元素:

<t-header :showCancel=showCancel></t-header>

接著import寫好的子組件:

import THeader from "./components/t-header/t-header";

然后在組件中注冊子組件:

components: { THeader}

到這里,新入坑的同學可能會比較疑惑這幾行代碼是怎樣把子組件對應到<t-header>標簽的,官方文檔是這樣說的:

當注冊組件 (或者 prop) 時,可以使用 kebab-case (短橫線分隔命名)、camelCase (駝峰式命名) 或 PascalCase (單詞首字母大寫命名);

在 HTML 模板中,請使用 kebab-case;

我的理解是(舉例),當自定義元素為<t-header>時,注冊組件名可以有三種寫法:t-header、tHeader和THeader,在這種情況下注冊的組件會自動識別并渲染到<t-header>。

需要注意的是,以上使用的是HTML 模板,是在單文件組件里用<template><template/>指定的模板;另外存在一種字符串模板,是用在組件選項里用template: "" 指定的模板。當使用字符串模板時,自定義標簽可以用三種寫法,具體情況請移步官方文檔 組件命名約定。

這樣父組件的雛形就誕生了:

<template> <div id="app" @click="hideCancel"> <t-header :showCancel=showCancel></t-header> <!-- <router-view/> --> </div></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;  } } };</script>

2. 子組件

子組件中.cancel為打開系統菜單的按鈕,.cancel-div為系統菜單,最開始是這個樣子:

<template> <div class="header-wrapper"> /*這里是logo和title*/ ... /*這里是用戶名和按鈕*/ <div class="info-wrapper">  <span class="username">你好,管理員!</span>  <span class="cancel" @click.stop="switchCancelBoard">  <div class="cancel-div" v-show="showCancel">   <ul>   <li @click.stop="doSomething" title="用戶設置">設置 </li>   <li @click.stop="doSomething" title="退出登錄">退出 </li>   </ul>  </div>  </span> </div> </div></template>

按照踩坑之前的思路,在子組件接到showCancel值后用v-show控制顯示隱藏,那么在父子組件的綁定click事件中只需要根據情況更改showCancel值就可以了,只要注意對系統菜單內幾個選項的綁定事件不要觸發父子組件上的綁定事件――總不能一點菜單它就沒了,所以在綁定事件中用到了.stop,即
@click.stop="doSomething"

于是萬事大吉,也就是像這樣:

<script> export default { props: {  showCancel: {  type: Boolean  } }, methods: {  doSomething() {},  switchCancelBoard() {  this.showCancel = !this.showCancel;  } }, computed: {  ifShowCancel() {  return this.showCancel;  } } };</script>

然而第一波踩坑之后一起表明顯然我還是太年輕。下面是一些不好的示范:

prop來的showCancel值的確可以用,點擊子組件按鈕的時候,

this.showCancel=!this.showCancel

實現了菜單的顯示/隱藏,但是一打開控制臺,每次點擊貢獻了一條報錯:

vue.esm.js?efeb:578 [Vue warn]: Avoid mutating a prop directly since the value will be overwritten whenever the parent component re-renders. Instead, use a data or computed property based on the prop's value.

意思是:避免修改prop值,因為父組件一旦re-render,這個值就會被覆蓋;

另外,盡管在這個按鈕上實現了顯示狀態的切換,但是點擊其他區域的時候,并不會隱藏它,原因是:子組件prop值的變化并沒有影響到父組件,因此showCancel的值一直保持初始值沒有變化,而只有在這個值被更新時才會觸發子組件中相關值的更新。

――好吧,那么老老實實的用一個計算屬性接收showCancel值,這樣實現點擊子組件控制系統菜單的狀態切換;

獲得了計算屬性ifShowCancel,組件相應的變成了v-show="ifShowCancel",我試圖在綁定事件里通過this.ifShowCancel=!this.ifShowCancel切換菜單狀態,報錯,得到報錯信息:Computed property "ifShowCancel" was assigned to but it has no setter;

明白了,要以直接賦值的形式改變計算屬性ifShowCancel的值,需要一個setter函數,但是setter函數中無法修改prop值,因此在getter中也就無法通過return this.showCancel來更新這個計算屬性,所以這個方法貌似也行不通;

到此為止,好像路都成了堵死狀態:prop值不能改->要用計算屬性;計算屬性不能改->需要setter;而寫入了getter、setter,計算屬性的值依賴于prop值->prop值不能改。――一個堪稱完美的閉環誕生了!

走投無路之際我想起了$emit和$on這一對。

3. 父子互相通信

前邊的prop實現了從父到子的單向通信,而通過$emit和$on,就可以實現從子組件到父組件的通信:這不能直接修改父組件的屬性,但卻可以觸發父組件的指定綁定事件,并將一個值傳入父組件。

在這一步我摒棄了點擊按鈕時的去操作子組件內屬性的想法,既然計算屬性ifShowCancel依賴于prop值,那么就在點擊按鈕時,通過$emit觸發父組件的事件,并將需要修改的屬性值傳入父組件,于是:

/*父組件自定義元素綁定switch-show事件*/<t-header :showCancel=showCancel @switch-show="switchShow"></t-header>// 父組件jsmethods: { //會被子組件$emit觸發的方法 switchShow(val) { this.showCancel = val; }}// 子組件jsmethods: { //按鈕上的綁定click事件 switchCancelBoard() { this.$emit("switch-show", this.ifShowCancel); }}

這樣處理流程就變成了:點擊按鈕->作為計算屬性的ifShowCancel值傳入父組件并觸發父組件事件,對showCancel賦值->父組件屬性更新->觸發子組件prop更新->觸發重新compute,更新ifShowCancel值->v-show起作用。
另外在點擊其他區域時,通過父組件綁定的click事件,就可以重置showCancel值,進而隱藏掉出現的系統菜單。

下邊放出這個功能的完整代碼。

4. 完整代碼

/*父組件*/<template> <div id="app" @click="hideCancel"> <t-header :showCancel=showCancel @switch-show="switchShow"></t-header> <!-- <router-view/> --> </div></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> <div class="header-wrapper"> <div class="title-wrapper">  <div class="logo"></div>  <h2 class="title">Title</h2> </div> <div class="info-wrapper">  <span class="username">你好,管理員!</span>  <span class="cancel" @click.stop="switchCancelBoard">  <div class="cancel-div" v-show="ifShowCancel">   <ul>   <li @click.stop="doSomething" title="用戶設置">設置 </li>   <li @click.stop="doSomething" title="退出登錄">退出 </li>   </ul>  </div>  </span> </div> </div></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-div   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>

總結

以上所述是小編給大家介紹的Vue在頁面右上角實現可懸浮/隱藏的系統菜單,希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會及時回復大家的。在此也非常感謝大家對武林網網站的支持!

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 嘉定区| 许昌市| 承德县| 集安市| 石楼县| 平乡县| 来安县| 错那县| 汨罗市| 定陶县| 江山市| 枝江市| 中超| 淳安县| 那坡县| 京山县| 海阳市| 涟水县| 巴中市| 上杭县| 丽江市| 澄迈县| 小金县| 双辽市| 闵行区| 广州市| 湘潭县| 揭阳市| 郎溪县| 铜鼓县| 宁蒗| 朝阳县| 新津县| 泾阳县| 广安市| 镇原县| 久治县| 邛崃市| 志丹县| 松桃| 徐汇区|