Vue管理系統(tǒng)前端之組件拆分封裝詳解
組件封裝
在上一篇記錄中,首頁(yè)中有太多的代碼,為了避免代碼的臃腫,需要對(duì)主要的功能模塊拆分,來(lái)讓代碼看起來(lái)更簡(jiǎn)潔,且能進(jìn)行復(fù)用。
拆分后還加了些小功能,加入了修改 title 的代碼,修改方式參考vue 動(dòng)態(tài)修改 title。
還增加了當(dāng)前請(qǐng)求的頁(yè)面緩存,使用狀態(tài)管理器處理。監(jiān)聽(tīng)路由,保存到 state 中,來(lái)處理的。 如何監(jiān)聽(tīng)可參考vue 計(jì)算屬性和監(jiān)聽(tīng)屬性。
完整效果圖如下:
首頁(yè)布局拆分后結(jié)構(gòu)
拆分后的,布局結(jié)構(gòu)圖:
拆分后代碼
布局最外層 index 代碼,使用頭部,側(cè)邊欄,主內(nèi)容欄組成,代碼如下:
<!-- 布局的首頁(yè) --> <template> <div> <l-header></l-header> <l-aside></l-aside> <l-main></l-main> </div> </template> <script> import LHeader from './components/header' import LAside from './components/aside' import LMain from './components/main' export default { data() { return {} }, //引入組件 components: { LHeader, LAside, LMain, }, } </script> <style lang="scss" scoped></style>
頭部 index.vue 代碼:
<!-- 頭部文件 --> <template> <div class="header"> <!-- logo --> <logo></logo> <!-- 折疊按鈕 --> <hamburger></hamburger> <!-- 頭部導(dǎo)航欄 --> <div class="heardNavBar"> <el-menu default-active="1" class="el-menu-demo" background-color="#4b5f6e" text-color="#fff" active-text-color="#ffd04b" mode="horizontal"> <el-menu-item index="1" @click="$router.push('/')">首頁(yè)</el-menu-item> <el-menu-item index="2" @click="openUrl('#')">使用文檔</el-menu-item> <el-menu-item index="3" @click="openUrl('https://github.com/levy-w-wang/lion-ui')">GitHub</el-menu-item> </el-menu> </div> <!-- 右側(cè)信息 --> <div style="float:right"> <!-- 全屏 --> <div style="float:left;line-height: 60px; padding: 0 10px;"> <i class="el-icon-full-screen" @click="toggleFull"></i> </div> <!-- 個(gè)人信息 --> <div class="userinfo"> <el-dropdown trigger="hover"> <span class="el-dropdown-link userinfo-inner"> <img src="@assets/img/user.jpg" /> {{ $store.getters.userInfo.username }}<i class="el-icon-caret-bottom"></i> </span> <el-dropdown-menu slot="dropdown"> <el-dropdown-item> <router-link to="/"><i class="el-icon-s-home"></i>首頁(yè)</router-link> </el-dropdown-item> <el-dropdown-item> <router-link to="/"><i class="el-icon-s-custom"></i>我的主頁(yè)</router-link> </el-dropdown-item> <el-dropdown-item divided> <a @click="loginOut()"><i class="el-icon-switch-button"></i>登出</a> </el-dropdown-item> </el-dropdown-menu> </el-dropdown> </div> </div> </div> </template> <script> import screenfull from 'screenfull' import hamburger from './hamburger' import logo from './logo' // import { mapState } from 'vuex' export default { data() { return {} }, computed: { // ...mapState({ // isCollapse: (state) => state.app.isCollapse, // }), }, //引入組件 components: { hamburger, logo, }, // 方法 methods: { openUrl(url) { window.open(url) }, loginOut() { this.$confirm('確認(rèn)退出嗎?', '提示', { type: 'warning', }) .then(() => { this.$store.commit('logout') }) .catch(() => {}) }, toggleFull() { if (!screenfull.isEnabled) { this.$message({ type: 'warning', message: 'you browser can not work', }) return false } screenfull.toggle() }, }, //未掛載DOM,不能訪問(wèn)ref為空數(shù)組 //可在這結(jié)束loading,還做一些初始化,實(shí)現(xiàn)函數(shù)自執(zhí)行, //可以對(duì)data數(shù)據(jù)進(jìn)行操作,可進(jìn)行一些請(qǐng)求,請(qǐng)求不易過(guò)多,避免白屏?xí)r間太長(zhǎng)。 created() {}, //可在這發(fā)起后端請(qǐng)求,拿回?cái)?shù)據(jù),配合路由鉤子做一些事情;可對(duì)DOM 進(jìn)行操作 mounted() {}, } </script> <style lang="scss" scoped> .header { padding-left: 0px !important; height: 60px; line-height: 60px; width: 100%; background: #4b5f6e; color: #fff; .heardNavBar { float: left; background: #4b5f6e; padding: 0px 0px; height: 60px; line-height: 60px; font-size: 28px; cursor: pointer; } .userinfo { text-align: right; padding-right: 24px; float: right; padding: 0 10px; .userinfo-inner { font-size: 20px; cursor: pointer; color: #fff; img { width: 40px; height: 40px; border-radius: 10px; margin: 10px 0px 10px 10px; float: right; } } } } </style>
頭部中引用的相關(guān)組件代碼如下
折疊導(dǎo)航欄 hamburger 下的 index.vue 代碼:
<template> <div @click="toggleCollapse"> <svg :class="{ 'is-active': !isCollapse }" class="hamburger" viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg" width="64" height="64"> <path d="M408 442h480c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8H408c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8zm-8 204c0 4.4 3.6 8 8 8h480c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8H408c-4.4 0-8 3.6-8 8v56zm504-486H120c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8h784c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8zm0 632H120c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8h784c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8zM142.4 642.1L298.7 519a8.84 8.84 0 0 0 0-13.9L142.4 381.9c-5.8-4.6-14.4-.5-14.4 6.9v246.3a8.9 8.9 0 0 0 14.4 7z" /> </svg> </div> </template> <script> import { mapState } from 'vuex' export default { name: 'Hamburger', computed: { ...mapState({ isCollapse: (state) => state.app.isCollapse, }), }, methods: { //折疊導(dǎo)航欄 toggleCollapse: function () { this.$store.commit('toggleCollapse') }, }, } </script> <style scoped> .hamburger { padding-left: 13px; padding-right: 13px; text-align: center; width: 34px; height: 60px; line-height: 60px; float: left; cursor: pointer; } .is-active { transform: rotate(180deg); } </style>
折疊導(dǎo)航欄 logo 下的 index.vue 代碼:
<!-- --> <template> <div class="logo" :class="isCollapse ? 'logo-collapse-width' : 'logo-width'"> <img v-if="isCollapse" src="@assets/logo6065.png" @click="$router.push('/')" /> <img v-else src="@assets/logo.png" @click="$router.push('/')" /> </div> </template> <script> import { mapState } from 'vuex' export default { data() { return {} }, computed: { ...mapState({ isCollapse: (state) => state.app.isCollapse, }), }, } </script> <style lang="scss" scoped> .logo { float: left; height: 60px; padding: 0; margin: 0; } .logo-width { width: 230px; } .logo-collapse-width { width: 65px; } </style>
側(cè)邊欄下的 index.vue代碼:
<!-- aside --> <template> <div class="aside-container" :class="isCollapse ? 'aside-collapse-width' : 'aside-width'"> <!--導(dǎo)航菜單 default-active="1-1"--> <el-menu class="el-menu-vertical-demo" :class="isCollapse ? 'aside-collapse-width' : 'aside-width'" :collapse-transition="false" :unique-opened="true" :collapse="isCollapse"> <el-submenu index="1"> <template slot="title"> <i class="el-icon-setting"></i> <span slot="title">系統(tǒng)管理</span> </template> <el-menu-item index="1-1" @click="$router.push('usermanage')">用戶管理</el-menu-item> <el-menu-item index="1-2" @click="$router.push('menumanage')">菜單管理</el-menu-item> </el-submenu> <el-menu-item index="2" disabled> <i class="el-icon-magic-stick"></i> <span slot="title">導(dǎo)航一</span> </el-menu-item> <el-menu-item index="3" disabled> <i class="el-icon-reading"></i> <span slot="title">導(dǎo)航二</span> </el-menu-item> </el-menu> </div> </template> <script> import { mapState } from 'vuex' export default { data() { return {} }, //$store.getters.isCollapse computed: { ...mapState({ isCollapse: (state) => state.app.isCollapse, }), mainTabs: { get() { return this.$store.state.app.mainTabs }, set(val) { this.$store.commit('updateMainTabs', val) }, }, mainTabsActiveName: { get() { return this.$store.state.app.mainTabsActiveName }, set(val) { this.$store.commit('updateMainTabsActiveName', val) }, }, }, watch: { $route: 'handleRoute', }, created() { console.log(this.$route) this.handleRoute(this.$route) }, methods: { // 路由操作處理 handleRoute(route) { // tab標(biāo)簽頁(yè)選中, 如果不存在則先添加 var tab = this.mainTabs.filter((item) => item.name === route.name)[0] if (!tab) { tab = { name: route.name, title: route.meta.title, icon: route.meta.icon, } this.mainTabs = this.mainTabs.concat(tab) } this.mainTabsActiveName = tab.name }, }, } </script> <style lang="scss" scoped> .aside-container { position: fixed; top: 0px; left: 0; bottom: 0; z-index: 1020; .el-menu { position: absolute; top: 60px; bottom: 0px; text-align: left; } } .aside-width { width: 230px; } .aside-collapse-width { width: 65px; } </style>
內(nèi)容模塊下的 index.vue代碼:
<!-- --> <template> <div class="main-container clear" :class="isCollapse ? 'position-collapse-left' : 'position-left'"> <!-- 標(biāo)簽頁(yè) --> <el-tabs class="tabs" :class="isCollapse ? 'position-collapse-left' : 'position-left'" v-model="mainTabsActiveName" :closable="true" type="card" @tab-click="selectedTabHandle" @tab-remove="removeTabHandle"> <el-dropdown class="tabs-tools" :show-timeout="0" trigger="hover"> <div style="font-size:20px;width:50px;"> <i class="el-icon-arrow-down"></i> </div> <el-dropdown-menu slot="dropdown"> <el-dropdown-item @click.native="tabsCloseCurrentHandle">關(guān)閉當(dāng)前標(biāo)簽</el-dropdown-item> <el-dropdown-item @click.native="tabsCloseOtherHandle">關(guān)閉其它標(biāo)簽</el-dropdown-item> <el-dropdown-item @click.native="tabsCloseAllHandle">關(guān)閉全部標(biāo)簽</el-dropdown-item> <el-dropdown-item @click.native="tabsRefreshCurrentHandle">刷新當(dāng)前標(biāo)簽</el-dropdown-item> </el-dropdown-menu> </el-dropdown> <el-tab-pane v-for="item in mainTabs" :key="item.name" :label="item.title" :name="item.name"> <span slot="label"> <i :class="item.icon"></i> {{ item.title }} </span> </el-tab-pane> </el-tabs> <!-- 主內(nèi)容區(qū)域 --> <div class="main-content"> <keep-alive> <transition name="fade" mode="out-in"> <router-view></router-view> </transition> </keep-alive> </div> </div> </template> <script> import { mapState } from 'vuex' export default { data() { return {} }, computed: { ...mapState({ isCollapse: (state) => state.app.isCollapse, }), mainTabs: { get() { return this.$store.state.app.mainTabs }, set(val) { this.$store.commit('updateMainTabs', val) }, }, mainTabsActiveName: { get() { return this.$store.state.app.mainTabsActiveName }, set(val) { this.$store.commit('updateMainTabsActiveName', val) }, }, }, methods: { // tabs, 選中tab selectedTabHandle(tab) { tab = this.mainTabs.filter((item) => item.name === tab.name) if (tab.length >= 1) { this.$router.push({ name: tab[0].name }) } }, // tabs, 刪除tab removeTabHandle(tabName) { // 當(dāng)只有首頁(yè)時(shí),不允許關(guān)掉。 若是其它頁(yè)面可關(guān)掉后,push 首頁(yè)進(jìn)去 if (this.mainTabs.length == 1 && this.mainTabs[0].name == 'index') { return } this.mainTabs = this.mainTabs.filter((item) => item.name !== tabName) if (this.mainTabs.length >= 1) { // 當(dāng)前選中tab被刪除 if (tabName === this.mainTabsActiveName) { this.$router.push({ name: this.mainTabs[this.mainTabs.length - 1].name }, () => { this.mainTabsActiveName = this.$route.name }) } } else { this.$router.push('/') } }, // tabs, 關(guān)閉當(dāng)前 tabsCloseCurrentHandle() { this.removeTabHandle(this.mainTabsActiveName) }, // tabs, 關(guān)閉其它 tabsCloseOtherHandle() { this.mainTabs = this.mainTabs.filter((item) => item.name === this.mainTabsActiveName) }, // tabs, 關(guān)閉全部 tabsCloseAllHandle() { this.mainTabs = [] this.$router.push('/') }, // tabs, 刷新當(dāng)前 tabsRefreshCurrentHandle() { var tempTabName = this.mainTabsActiveName this.removeTabHandle(tempTabName) this.$nextTick(() => { this.$router.push({ name: tempTabName }) }) }, }, } </script> <style lang="scss" scoped> .main-container { padding: 0 5px 5px; position: absolute; top: 60px; left: 1px; right: 1px; bottom: 0px; .tabs { position: fixed; top: 60px; right: 50px; padding-left: 0px; padding-right: 2px; z-index: 1020; height: 40px; line-height: 40px; font-size: 14px; background: rgb(255, 253, 255); border-color: rgba(200, 206, 206, 0.5); // border-left-width: 1px; // border-left-style: solid; border-bottom-width: 1px; border-bottom-style: solid; } .tabs-tools { position: fixed; top: 60px; right: 0; z-index: 1020; height: 40px; // padding: 0 10px; font-size: 14px; line-height: 40px; cursor: pointer; border-color: rgba(200, 206, 206, 0.5); border-left-width: 1px; border-left-style: solid; border-bottom-width: 1px; border-bottom-style: solid; background: rgba(255, 255, 255, 1); } .tabs-tools:hover { background: rgba(200, 206, 206, 1); } .main-content { position: absolute; top: 45px; left: 5px; right: 5px; bottom: 5px; padding: 5px; // background: rgba(209, 212, 212, 0.5); } } .position-left { left: 230px; } .position-collapse-left { left: 65px; } </style>
狀態(tài)管理中添加 app 模塊
代碼如下:
export default { state: { // 是否折疊導(dǎo)航欄 isCollapse: false, // 訪問(wèn)頁(yè)集合 mainTabs: [], // 當(dāng)前訪問(wèn)頁(yè)名 mainTabsActiveName: '', }, getters: { isCollapse: (state) => { return state.isCollapse }, }, mutations: { toggleCollapse(state) { state.isCollapse = !state.isCollapse }, updateMainTabs(state, tabs) { state.mainTabs = tabs }, updateMainTabsActiveName(state, name) { state.mainTabsActiveName = name }, }, actions: {}, }
當(dāng)然還有一些小的調(diào)整點(diǎn),可參考 git 上的提交版本 首頁(yè)組件拆分
總結(jié)
到此這篇關(guān)于Vue管理系統(tǒng)前端之組件拆分封裝的文章就介紹到這了,更多相關(guān)Vue組件拆分封裝內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
在nuxt使用vueX代替storage的實(shí)現(xiàn)方案
這篇文章主要介紹了在nuxt使用vueX代替storage的實(shí)現(xiàn)方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-10-10vue-cil之a(chǎn)xios的二次封裝與proxy反向代理使用說(shuō)明
這篇文章主要介紹了vue-cil之a(chǎn)xios的二次封裝與proxy反向代理使用說(shuō)明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-04-04基于Vue3和Element Plus實(shí)現(xiàn)可擴(kuò)展的表格組件
在開(kāi)發(fā)過(guò)程中,我們經(jīng)常需要?jiǎng)?chuàng)建具有復(fù)雜功能的表格組件,本文將介紹如何使用 Vue 3 和 Element Plus 庫(kù)來(lái)構(gòu)建一個(gè)可擴(kuò)展的表格組件,文中有詳細(xì)的代碼示例供大家參考,需要的朋友可以參考下2024-07-07vue前端性能優(yōu)化之預(yù)加載和懶加載示例詳解
這篇文章主要為大家介紹了vue前端性能優(yōu)化之預(yù)加載和懶加載示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-02-02VUEX 數(shù)據(jù)持久化,刷新后重新獲取的例子
今天小編就為大家分享一篇VUEX 數(shù)據(jù)持久化,刷新后重新獲取的例子,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2019-11-11elementUI Tree 樹(shù)形控件的官方使用文檔
這篇文章主要介紹了elementUI Tree 樹(shù)形控件的官方使用文檔,用清晰的層級(jí)結(jié)構(gòu)展示信息,可展開(kāi)或折疊。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2019-04-04Vue封裝一個(gè)Tabbar組件?帶組件路由跳轉(zhuǎn)方式
這篇文章主要介紹了Vue封裝一個(gè)Tabbar組件?帶組件路由跳轉(zhuǎn)方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-04-04利用Vue.js+Node.js+MongoDB實(shí)現(xiàn)一個(gè)博客系統(tǒng)(附源碼)
本文主要介紹了利用Vue.js+Node.js+MongoDB實(shí)現(xiàn)一個(gè)博客系統(tǒng),這個(gè)博客使用Vue做前端框架,Node+express做后端,數(shù)據(jù)庫(kù)使用的是MongoDB。實(shí)現(xiàn)了用戶注冊(cè)、用戶登錄、博客管理、文章編輯、標(biāo)簽分類等功能,需要的朋友可以參考學(xué)習(xí)。2017-04-04