Vue管理系統(tǒng)前端之組件拆分封裝詳解
組件封裝
在上一篇記錄中,首頁中有太多的代碼,為了避免代碼的臃腫,需要對(duì)主要的功能模塊拆分,來讓代碼看起來更簡(jiǎn)潔,且能進(jìn)行復(fù)用。
拆分后還加了些小功能,加入了修改 title 的代碼,修改方式參考vue 動(dòng)態(tài)修改 title。
還增加了當(dāng)前請(qǐng)求的頁面緩存,使用狀態(tài)管理器處理。監(jiān)聽路由,保存到 state 中,來處理的。 如何監(jiān)聽可參考vue 計(jì)算屬性和監(jiān)聽屬性。
完整效果圖如下:

首頁布局拆分后結(jié)構(gòu)
拆分后的,布局結(jié)構(gòu)圖:

拆分后代碼
布局最外層 index 代碼,使用頭部,側(cè)邊欄,主內(nèi)容欄組成,代碼如下:
<!-- 布局的首頁 -->
<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('/')">首頁</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>首頁</router-link>
</el-dropdown-item>
<el-dropdown-item>
<router-link to="/"><i class="el-icon-s-custom"></i>我的主頁</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,不能訪問ref為空數(shù)組
//可在這結(jié)束loading,還做一些初始化,實(shí)現(xiàn)函數(shù)自執(zhí)行,
//可以對(duì)data數(shù)據(jù)進(jìn)行操作,可進(jìn)行一些請(qǐng)求,請(qǐng)求不易過多,避免白屏?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)簽頁選中, 如果不存在則先添加
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)簽頁 -->
<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)只有首頁時(shí),不允許關(guān)掉。 若是其它頁面可關(guān)掉后,push 首頁進(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,
// 訪問頁集合
mainTabs: [],
// 當(dāng)前訪問頁名
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 上的提交版本 首頁組件拆分
總結(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-10
vue-cil之a(chǎn)xios的二次封裝與proxy反向代理使用說明
這篇文章主要介紹了vue-cil之a(chǎn)xios的二次封裝與proxy反向代理使用說明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-04-04
基于Vue3和Element Plus實(shí)現(xiàn)可擴(kuò)展的表格組件
在開發(fā)過程中,我們經(jīng)常需要?jiǎng)?chuàng)建具有復(fù)雜功能的表格組件,本文將介紹如何使用 Vue 3 和 Element Plus 庫來構(gòu)建一個(gè)可擴(kuò)展的表格組件,文中有詳細(xì)的代碼示例供大家參考,需要的朋友可以參考下2024-07-07
vue前端性能優(yōu)化之預(yù)加載和懶加載示例詳解
這篇文章主要為大家介紹了vue前端性能優(yōu)化之預(yù)加載和懶加載示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-02-02
VUEX 數(shù)據(jù)持久化,刷新后重新獲取的例子
今天小編就為大家分享一篇VUEX 數(shù)據(jù)持久化,刷新后重新獲取的例子,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2019-11-11
Vue封裝一個(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ù)庫使用的是MongoDB。實(shí)現(xiàn)了用戶注冊(cè)、用戶登錄、博客管理、文章編輯、標(biāo)簽分類等功能,需要的朋友可以參考學(xué)習(xí)。2017-04-04

