Vue彈出菜單功能的實(shí)現(xiàn)代碼
言歸正傳
我們老樣子直接先上效果圖再開(kāi)始今天的分享 這個(gè)項(xiàng)目的github可以看一看
組件分析
- 界面組成
- 邏輯分析
- 最終實(shí)現(xiàn)
界面組成
從上圖中,我們可以看出界面主要分為menu和item2塊,其中menu的動(dòng)畫(huà)是自傳,item的動(dòng)畫(huà)是位移,然后這里我們通過(guò)絕對(duì)布局的方式將整個(gè)控件定位在四個(gè)角落
.menu_container { position: absolute; z-index: 100; border-radius: 50%; transition-duration: 400ms; text-align: center; border: #efefef 3px solid; box-shadow: aliceblue 1px 1px 1px; } .menu_item { position: absolute; border-radius: 50%; z-index: 99; border: #efefef 3px solid; text-align: center; box-shadow: aliceblue 1px 1px 1px; }
邏輯分析
這里我將這個(gè)控件幾個(gè)屬性獨(dú)立出來(lái),方便下次開(kāi)發(fā),其中包含,menu的背景,整個(gè)控件在屏幕的哪個(gè)角落,menu的寬高,item距離menu位移的距離,menu的背景色,及item的背景色,item的相關(guān)內(nèi)容則由數(shù)據(jù)來(lái)控制,具體的我們直接在下方的實(shí)現(xiàn)里來(lái)講解。
最終實(shí)現(xiàn)
這里我用代碼加注釋的方式,幫助大家理解,template我簡(jiǎn)單的帶過(guò)一下
<div> <div class="menu_container" ref="menuHome" @click="toggleMenu"> <img :src="menuSrc"><!--menu圖--> </div> <div class="menu_item" v-for="(item,index) in menuItems" :id="item.name" @click="clickMenu(item,index)"> <img :src="item.src"><!--item圖--> </div> </div>
核心實(shí)現(xiàn) 通過(guò)分析可以得出,每個(gè)item的偏移量應(yīng)該為 橫向x:基礎(chǔ)值 * sin(角度值) 縱向y:基礎(chǔ)值 * cos(角度值) 角度值:(數(shù)組的長(zhǎng)度-1-當(dāng)前的下標(biāo))* 每一塊所占的角度 * 弧度表示 弧度表示:2 * Math.PI / 360
export default { ... props: {//開(kāi)放的屬性,方便自定義 menuSrc: { default: require('../assets/menu.png') }, position: { default: 'LT'//可選擇LT、LB、RT、RB4個(gè)角落 }, width: { default: 50, }, baseDistance: { default: 150, }, menuBg: { default: 'white' }, itemBg: { default: 'white' }, menuItems: { type: Array, } }, data() { return { openFlag: false,//展開(kāi)合并標(biāo)志 operators: ['+', '+'],//用于記錄展開(kāi)時(shí)動(dòng)畫(huà)XY方向 } }, mounted() { //根據(jù)props初始化各內(nèi)容的各種style this.$refs.menuHome.style.width = this.width + 'px'; this.$refs.menuHome.style.height = this.width + 'px'; this.$refs.menuHome.style.lineHeight = this.width + 'px'; this.$refs.menuHome.style.background = this.menuBg; this.menuItems.forEach((item) => { let el = document.getElementById(item.name); el.style.width = `${this.width * 0.8}px`; el.style.height = `${this.width * 0.8}px`; el.style.lineHeight = `${this.width * 0.8}px`; el.style.background = this.itemBg; }); //根據(jù)position,選擇不同的定位 switch (this.position) { case 'LT': this.$refs.menuHome.style.left = '20px'; this.$refs.menuHome.style.top = '20px'; this.menuItems.forEach((item) => { let el = document.getElementById(item.name); el.style.left = '26px'; el.style.top = '26px'; }); this.operators = ['+', '+']; break; ... } }, methods: { toggleMenu() { if (!this.openFlag) {//合并時(shí),點(diǎn)擊展開(kāi)操作 this.menuItems.forEach((item, index) => { this.toggleMenuTransition(item.name, index, false) }); //menu本身轉(zhuǎn)一周 this.$refs.menuHome.style.transform = 'rotate(360deg)'; } else { this.menuItems.forEach((item, index) => { this.toggleMenuTransition(item.name, index, true) }); //menu恢復(fù) this.$refs.menuHome.style.transform = 'rotate(0)'; } this.openFlag = !this.openFlag; }, toggleMenuTransition(name, index, revert) { let oneArea = 90 / (this.menuItems.length - 1);//每一塊所占的角度 let axisX = Math.sin((this.menuItems.length - 1 - index) * oneArea * 2 * Math.PI / 360);//橫坐標(biāo)所偏移的比例 let axisY = Math.cos((this.menuItems.length - 1 - index) * oneArea * 2 * Math.PI / 360);//縱坐標(biāo)所便宜的比例 let el = document.getElementById(name);//若所傳的name一直,會(huì)報(bào)錯(cuò)。 let that = this; if (!revert) { setTimeout(function () { el.style.transitionDuration = '200ms'; el.style.transform = `translate(${that.operators[0]}${that.baseDistance * axisX}px,${that.operators[1]}${that.baseDistance * axisY }px)`;//進(jìn)行動(dòng)畫(huà) }, index * 100)//通過(guò)定時(shí)器的方式,達(dá)到一個(gè)一個(gè)彈出來(lái)的效果 } else { //item恢復(fù) el.style.transitionDuration = '200ms'; el.style.transform = `translate(0,0)`; } }, clickMenu(item, index) { //暴露方法給父組件,進(jìn)行點(diǎn)擊事件的操作 this.$emit('clickMenu', item, index) } } }
再父組件中引入就可以大功告成啦,先跳一會(huì)兒吧,燃燒你的卡路里
父組件調(diào)用
引入組件
import toggleMenu from './toggleMenu'
在 components聲明
components: { toggleMenu },
template中使用
menuItems: [//name和src必填,且name唯一否則會(huì)報(bào)錯(cuò) {name: 'menu1', src: require('../assets/emoji.png')}, {name: 'menu2', src: require('../assets/cart.png')}, {name: 'menu3', src: require('../assets/folder.png')}, {name: 'menu4', src: require('../assets/home.png')}, {name: 'menu5', src: require('../assets/my.png')}, ] <toggle-menu :menuItems="menuItems" @clickMenu="clickMenu" ></toggle-menu>
屬性及方法一欄
屬性名 | 用處 | 默認(rèn)值 | 是否必須 |
---|---|---|---|
position | 四個(gè)方位(LT、LB、RT、RB) | LT | 否 |
menuBg | 菜單背景 | white | 否 |
menuSrc | 菜單圖片 | 一個(gè)菜單圖片 | 否 |
itemBg | 按鈕背景 | white | 否 |
width | 按鈕寬度 | 50px | 否 |
baseDistance | 位移距離,若item很多,可適當(dāng)提高 | 150px | 否 |
menuItems | 菜單數(shù)組 | 無(wú) | 是 |
方法名 | 用處 | 參數(shù) |
---|---|---|
clickMenu | 點(diǎn)擊item觸發(fā)事件 | item,index |
總結(jié)
以上所述是小編給大家介紹的Vue左側(cè)底部彈出菜單功能的實(shí)現(xiàn)代碼,希望對(duì)大家有所幫助,如果大家有任何疑問(wèn)請(qǐng)給我留言,小編會(huì)及時(shí)回復(fù)大家的。在此也非常感謝大家對(duì)腳本之家網(wǎng)站的支持!
- vue2.0的contextmenu右鍵彈出菜單的實(shí)例代碼
- vue.js與element-ui實(shí)現(xiàn)菜單樹(shù)形結(jié)構(gòu)的解決方法
- vue+swiper實(shí)現(xiàn)側(cè)滑菜單效果
- 用 Vue.js 遞歸組件實(shí)現(xiàn)可折疊的樹(shù)形菜單(demo)
- vue.js 左側(cè)二級(jí)菜單顯示與隱藏切換的實(shí)例代碼
- Vue.js手風(fēng)琴菜單組件開(kāi)發(fā)實(shí)例
- vue2.0實(shí)現(xiàn)導(dǎo)航菜單切換效果
- Vue組件tree實(shí)現(xiàn)樹(shù)形菜單
相關(guān)文章
解決vite項(xiàng)目Uncaught Syntaxerror:Unexpected token>vue項(xiàng)
這篇文章主要介紹了解決vite項(xiàng)目Uncaught Syntaxerror:Unexpected token>vue項(xiàng)目上線(xiàn)白屏問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-03-03element-resize-detector監(jiān)聽(tīng)普通元素的實(shí)現(xiàn)示例
當(dāng)涉及到網(wǎng)頁(yè)元素的實(shí)時(shí)尺寸變化監(jiān)測(cè)時(shí),element-resize-detector?是一個(gè)值得推薦的開(kāi)源庫(kù),本文主要介紹了element-resize-detector監(jiān)聽(tīng)普通元素的實(shí)現(xiàn)示例,感興趣的可以了解一下2024-07-07vue?如何刪除數(shù)組中的某一條數(shù)據(jù)
這篇文章主要介紹了vue?如何刪除數(shù)組中的某一條數(shù)據(jù),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-08-08詳解vue渲染從后臺(tái)獲取的json數(shù)據(jù)
這篇文章主要介紹了詳解vue渲染從后臺(tái)獲取的json數(shù)據(jù),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-07-07vue后臺(tái)管理添加多語(yǔ)言功能的實(shí)現(xiàn)示例
這篇文章主要介紹了vue后臺(tái)管理添加多語(yǔ)言功能的實(shí)現(xiàn)示例,幫助大家更好的理解和學(xué)習(xí)使用vue框架,感興趣的朋友可以了解下2021-04-04vue使用el-upload實(shí)現(xiàn)文件上傳功能
這篇文章主要為大家詳細(xì)介紹了vue使用el-upload實(shí)現(xiàn)文件上傳功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-04-04vue.js添加一些觸摸事件以及安裝fastclick的實(shí)例
今天小編就為大家分享一篇vue.js添加一些觸摸事件以及安裝fastclick的實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2018-08-08