Vue组件拆分封装 Vue管理系统前端之组件拆分封装详解
Levy-伟 人气:0想了解Vue管理系统前端之组件拆分封装详解的相关内容吗,Levy-伟在本文为您仔细讲解Vue组件拆分封装的相关知识和一些Code实例,欢迎阅读和指正,我们先划重点:vue组件封装并复用,vue封装组件的过程,vue组件拆分封装,下面大家一起来学习吧。
组件封装
在上一篇记录中,首页中有太多的代码,为了避免代码的臃肿,需要对主要的功能模块拆分,来让代码看起来更简洁,且能进行复用。
拆分后还加了些小功能,加入了修改 title 的代码,修改方式参考vue 动态修改 title。
还增加了当前请求的页面缓存,使用状态管理器处理。监听路由,保存到 state 中,来处理的。 如何监听可参考vue 计算属性和监听属性。
完整效果图如下:
首页布局拆分后结构
拆分后的,布局结构图:
拆分后代码
布局最外层 index 代码,使用头部,侧边栏,主内容栏组成,代码如下:
<!-- 布局的首页 --> <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> <!-- 头部导航栏 --> <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> <!-- 右侧信息 --> <div style="float:right"> <!-- 全屏 --> <div style="float:left;line-height: 60px; padding: 0 10px;"> <i class="el-icon-full-screen" @click="toggleFull"></i> </div> <!-- 个人信息 --> <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('确认退出吗?', '提示', { 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为空数组 //可在这结束loading,还做一些初始化,实现函数自执行, //可以对data数据进行操作,可进行一些请求,请求不易过多,避免白屏时间太长。 created() {}, //可在这发起后端请求,拿回数据,配合路由钩子做一些事情;可对DOM 进行操作 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>
头部中引用的相关组件代码如下
折叠导航栏 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: { //折叠导航栏 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>
折叠导航栏 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>
侧边栏下的 index.vue代码:
<!-- aside --> <template> <div class="aside-container" :class="isCollapse ? 'aside-collapse-width' : 'aside-width'"> <!--导航菜单 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">系统管理</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">导航一</span> </el-menu-item> <el-menu-item index="3" disabled> <i class="el-icon-reading"></i> <span slot="title">导航二</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标签页选中, 如果不存在则先添加 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>
内容模块下的 index.vue代码:
<!-- --> <template> <div class="main-container clear" :class="isCollapse ? 'position-collapse-left' : 'position-left'"> <!-- 标签页 --> <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">关闭当前标签</el-dropdown-item> <el-dropdown-item @click.native="tabsCloseOtherHandle">关闭其它标签</el-dropdown-item> <el-dropdown-item @click.native="tabsCloseAllHandle">关闭全部标签</el-dropdown-item> <el-dropdown-item @click.native="tabsRefreshCurrentHandle">刷新当前标签</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> <!-- 主内容区域 --> <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) { // 当只有首页时,不允许关掉。 若是其它页面可关掉后,push 首页进去 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) { // 当前选中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, 关闭当前 tabsCloseCurrentHandle() { this.removeTabHandle(this.mainTabsActiveName) }, // tabs, 关闭其它 tabsCloseOtherHandle() { this.mainTabs = this.mainTabs.filter((item) => item.name === this.mainTabsActiveName) }, // tabs, 关闭全部 tabsCloseAllHandle() { this.mainTabs = [] this.$router.push('/') }, // tabs, 刷新当前 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>
状态管理中添加 app 模块
代码如下:
export default { state: { // 是否折叠导航栏 isCollapse: false, // 访问页集合 mainTabs: [], // 当前访问页名 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: {}, }
当然还有一些小的调整点,可参考 git 上的提交版本 首页组件拆分
总结
加载全部内容